diff options
author | Starla Insigna <starla4444@gmail.com> | 2011-07-30 11:19:14 -0400 |
---|---|---|
committer | Starla Insigna <starla4444@gmail.com> | 2011-07-30 11:19:14 -0400 |
commit | 9cd57b731ab1c666d4a1cb725538fdc137763d12 (patch) | |
tree | 5bac45ae5157a1cb10c6e45500cbf72789917980 /libs | |
download | cartcollect-9cd57b731ab1c666d4a1cb725538fdc137763d12.tar.gz cartcollect-9cd57b731ab1c666d4a1cb725538fdc137763d12.tar.bz2 cartcollect-9cd57b731ab1c666d4a1cb725538fdc137763d12.zip |
Initial commit (version 0.2.1)
Diffstat (limited to 'libs')
204 files changed, 51028 insertions, 0 deletions
diff --git a/libs/CocosDenshion/CDAudioManager.h b/libs/CocosDenshion/CDAudioManager.h new file mode 100755 index 0000000..2475929 --- /dev/null +++ b/libs/CocosDenshion/CDAudioManager.h | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | Copyright (c) 2010 Steve Oldmeadow | ||
3 | |||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | of this software and associated documentation files (the "Software"), to deal | ||
6 | in the Software without restriction, including without limitation the rights | ||
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
8 | copies of the Software, and to permit persons to whom the Software is | ||
9 | furnished to do so, subject to the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be included in | ||
12 | all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
20 | THE SOFTWARE. | ||
21 | |||
22 | $Id$ | ||
23 | */ | ||
24 | |||
25 | #import "CocosDenshion.h" | ||
26 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 30000 | ||
27 | #import <AVFoundation/AVFoundation.h> | ||
28 | #else | ||
29 | #import "CDXMacOSXSupport.h" | ||
30 | #endif | ||
31 | |||
32 | /** Different modes of the engine */ | ||
33 | typedef enum { | ||
34 | kAMM_FxOnly, //!Other apps will be able to play audio | ||
35 | kAMM_FxPlusMusic, //!Only this app will play audio | ||
36 | kAMM_FxPlusMusicIfNoOtherAudio, //!If another app is playing audio at start up then allow it to continue and don't play music | ||
37 | kAMM_MediaPlayback, //!This app takes over audio e.g music player app | ||
38 | kAMM_PlayAndRecord //!App takes over audio and has input and output | ||
39 | } tAudioManagerMode; | ||
40 | |||
41 | /** Possible states of the engine */ | ||
42 | typedef enum { | ||
43 | kAMStateUninitialised, //!Audio manager has not been initialised - do not use | ||
44 | kAMStateInitialising, //!Audio manager is in the process of initialising - do not use | ||
45 | kAMStateInitialised //!Audio manager is initialised - safe to use | ||
46 | } tAudioManagerState; | ||
47 | |||
48 | typedef enum { | ||
49 | kAMRBDoNothing, //Audio manager will not do anything on resign or becoming active | ||
50 | kAMRBStopPlay, //Background music is stopped on resign and resumed on become active | ||
51 | kAMRBStop //Background music is stopped on resign but not resumed - maybe because you want to do this from within your game | ||
52 | } tAudioManagerResignBehavior; | ||
53 | |||
54 | /** Notifications */ | ||
55 | extern NSString * const kCDN_AudioManagerInitialised; | ||
56 | |||
57 | @interface CDAsynchInitialiser : NSOperation {} | ||
58 | @end | ||
59 | |||
60 | /** CDAudioManager supports two long audio source channels called left and right*/ | ||
61 | typedef enum { | ||
62 | kASC_Left = 0, | ||
63 | kASC_Right = 1 | ||
64 | } tAudioSourceChannel; | ||
65 | |||
66 | typedef enum { | ||
67 | kLAS_Init, | ||
68 | kLAS_Loaded, | ||
69 | kLAS_Playing, | ||
70 | kLAS_Paused, | ||
71 | kLAS_Stopped, | ||
72 | } tLongAudioSourceState; | ||
73 | |||
74 | @class CDLongAudioSource; | ||
75 | @protocol CDLongAudioSourceDelegate <NSObject> | ||
76 | @optional | ||
77 | /** The audio source completed playing */ | ||
78 | - (void) cdAudioSourceDidFinishPlaying:(CDLongAudioSource *) audioSource; | ||
79 | /** The file used to load the audio source has changed */ | ||
80 | - (void) cdAudioSourceFileDidChange:(CDLongAudioSource *) audioSource; | ||
81 | @end | ||
82 | |||
83 | /** | ||
84 | CDLongAudioSource represents an audio source that has a long duration which makes | ||
85 | it costly to load into memory for playback as an effect using CDSoundEngine. Examples | ||
86 | include background music and narration tracks. The audio file may or may not be compressed. | ||
87 | Bear in mind that current iDevices can only use hardware to decode a single compressed | ||
88 | audio file at a time and playing multiple compressed files will result in a performance drop | ||
89 | as software decompression will take place. | ||
90 | @since v0.99 | ||
91 | */ | ||
92 | @interface CDLongAudioSource : NSObject <AVAudioPlayerDelegate, CDAudioInterruptProtocol>{ | ||
93 | AVAudioPlayer *audioSourcePlayer; | ||
94 | NSString *audioSourceFilePath; | ||
95 | NSInteger numberOfLoops; | ||
96 | float volume; | ||
97 | id<CDLongAudioSourceDelegate> delegate; | ||
98 | BOOL mute; | ||
99 | BOOL enabled_; | ||
100 | BOOL backgroundMusic; | ||
101 | @public | ||
102 | BOOL systemPaused;//Used for auto resign handling | ||
103 | NSTimeInterval systemPauseLocation;//Used for auto resign handling | ||
104 | @protected | ||
105 | tLongAudioSourceState state; | ||
106 | } | ||
107 | @property (readonly) AVAudioPlayer *audioSourcePlayer; | ||
108 | @property (readonly) NSString *audioSourceFilePath; | ||
109 | @property (readwrite, nonatomic) NSInteger numberOfLoops; | ||
110 | @property (readwrite, nonatomic) float volume; | ||
111 | @property (assign) id<CDLongAudioSourceDelegate> delegate; | ||
112 | /* This long audio source functions as background music */ | ||
113 | @property (readwrite, nonatomic) BOOL backgroundMusic; | ||
114 | |||
115 | /** Loads the file into the audio source */ | ||
116 | -(void) load:(NSString*) filePath; | ||
117 | /** Plays the audio source */ | ||
118 | -(void) play; | ||
119 | /** Stops playing the audio soruce */ | ||
120 | -(void) stop; | ||
121 | /** Pauses the audio source */ | ||
122 | -(void) pause; | ||
123 | /** Rewinds the audio source */ | ||
124 | -(void) rewind; | ||
125 | /** Resumes playing the audio source if it was paused */ | ||
126 | -(void) resume; | ||
127 | /** Returns whether or not the audio source is playing */ | ||
128 | -(BOOL) isPlaying; | ||
129 | |||
130 | @end | ||
131 | |||
132 | /** | ||
133 | CDAudioManager manages audio requirements for a game. It provides access to a CDSoundEngine object | ||
134 | for playing sound effects. It provides access to two CDLongAudioSource object (left and right channel) | ||
135 | for playing long duration audio such as background music and narration tracks. Additionally it manages | ||
136 | the audio session to take care of things like audio session interruption and interacting with the audio | ||
137 | of other apps that are running on the device. | ||
138 | |||
139 | Requirements: | ||
140 | - Firmware: OS 2.2 or greater | ||
141 | - Files: CDAudioManager.*, CocosDenshion.* | ||
142 | - Frameworks: OpenAL, AudioToolbox, AVFoundation | ||
143 | @since v0.8 | ||
144 | */ | ||
145 | @interface CDAudioManager : NSObject <CDLongAudioSourceDelegate, CDAudioInterruptProtocol, AVAudioSessionDelegate> { | ||
146 | CDSoundEngine *soundEngine; | ||
147 | CDLongAudioSource *backgroundMusic; | ||
148 | NSMutableArray *audioSourceChannels; | ||
149 | NSString* _audioSessionCategory; | ||
150 | BOOL _audioWasPlayingAtStartup; | ||
151 | tAudioManagerMode _mode; | ||
152 | SEL backgroundMusicCompletionSelector; | ||
153 | id backgroundMusicCompletionListener; | ||
154 | BOOL willPlayBackgroundMusic; | ||
155 | BOOL _mute; | ||
156 | BOOL _resigned; | ||
157 | BOOL _interrupted; | ||
158 | BOOL _audioSessionActive; | ||
159 | BOOL enabled_; | ||
160 | |||
161 | //For handling resign/become active | ||
162 | BOOL _isObservingAppEvents; | ||
163 | tAudioManagerResignBehavior _resignBehavior; | ||
164 | } | ||
165 | |||
166 | @property (readonly) CDSoundEngine *soundEngine; | ||
167 | @property (readonly) CDLongAudioSource *backgroundMusic; | ||
168 | @property (readonly) BOOL willPlayBackgroundMusic; | ||
169 | |||
170 | /** Returns the shared singleton */ | ||
171 | + (CDAudioManager *) sharedManager; | ||
172 | + (tAudioManagerState) sharedManagerState; | ||
173 | /** Configures the shared singleton with a mode*/ | ||
174 | + (void) configure: (tAudioManagerMode) mode; | ||
175 | /** Initializes the engine asynchronously with a mode */ | ||
176 | + (void) initAsynchronously: (tAudioManagerMode) mode; | ||
177 | /** Initializes the engine synchronously with a mode, channel definition and a total number of channels */ | ||
178 | - (id) init: (tAudioManagerMode) mode; | ||
179 | -(void) audioSessionInterrupted; | ||
180 | -(void) audioSessionResumed; | ||
181 | -(void) setResignBehavior:(tAudioManagerResignBehavior) resignBehavior autoHandle:(BOOL) autoHandle; | ||
182 | /** Returns true is audio is muted at a hardware level e.g user has ringer switch set to off */ | ||
183 | -(BOOL) isDeviceMuted; | ||
184 | /** Returns true if another app is playing audio such as the iPod music player */ | ||
185 | -(BOOL) isOtherAudioPlaying; | ||
186 | /** Sets the way the audio manager interacts with the operating system such as whether it shares output with other apps or obeys the mute switch */ | ||
187 | -(void) setMode:(tAudioManagerMode) mode; | ||
188 | /** Shuts down the shared audio manager instance so that it can be reinitialised */ | ||
189 | +(void) end; | ||
190 | |||
191 | /** Call if you want to use built in resign behavior but need to do some additional audio processing on resign active. */ | ||
192 | - (void) applicationWillResignActive; | ||
193 | /** Call if you want to use built in resign behavior but need to do some additional audio processing on become active. */ | ||
194 | - (void) applicationDidBecomeActive; | ||
195 | |||
196 | //New AVAudioPlayer API | ||
197 | /** Loads the data from the specified file path to the channel's audio source */ | ||
198 | -(CDLongAudioSource*) audioSourceLoad:(NSString*) filePath channel:(tAudioSourceChannel) channel; | ||
199 | /** Retrieves the audio source for the specified channel */ | ||
200 | -(CDLongAudioSource*) audioSourceForChannel:(tAudioSourceChannel) channel; | ||
201 | |||
202 | //Legacy AVAudioPlayer API | ||
203 | /** Plays music in background. The music can be looped or not | ||
204 | It is recommended to use .aac files as background music since they are decoded by the device (hardware). | ||
205 | */ | ||
206 | -(void) playBackgroundMusic:(NSString*) filePath loop:(BOOL) loop; | ||
207 | /** Preloads a background music */ | ||
208 | -(void) preloadBackgroundMusic:(NSString*) filePath; | ||
209 | /** Stops playing the background music */ | ||
210 | -(void) stopBackgroundMusic; | ||
211 | /** Pauses the background music */ | ||
212 | -(void) pauseBackgroundMusic; | ||
213 | /** Rewinds the background music */ | ||
214 | -(void) rewindBackgroundMusic; | ||
215 | /** Resumes playing the background music */ | ||
216 | -(void) resumeBackgroundMusic; | ||
217 | /** Returns whether or not the background music is playing */ | ||
218 | -(BOOL) isBackgroundMusicPlaying; | ||
219 | |||
220 | -(void) setBackgroundMusicCompletionListener:(id) listener selector:(SEL) selector; | ||
221 | |||
222 | @end | ||
223 | |||
224 | /** Fader for long audio source objects */ | ||
225 | @interface CDLongAudioSourceFader : CDPropertyModifier{} | ||
226 | @end | ||
227 | |||
228 | static const int kCDNoBuffer = -1; | ||
229 | |||
230 | /** Allows buffers to be associated with file names */ | ||
231 | @interface CDBufferManager:NSObject{ | ||
232 | NSMutableDictionary* loadedBuffers; | ||
233 | NSMutableArray *freedBuffers; | ||
234 | CDSoundEngine *soundEngine; | ||
235 | int nextBufferId; | ||
236 | } | ||
237 | |||
238 | -(id) initWithEngine:(CDSoundEngine *) theSoundEngine; | ||
239 | -(int) bufferForFile:(NSString*) filePath create:(BOOL) create; | ||
240 | -(void) releaseBufferForFile:(NSString *) filePath; | ||
241 | |||
242 | @end | ||
243 | |||
diff --git a/libs/CocosDenshion/CDAudioManager.m b/libs/CocosDenshion/CDAudioManager.m new file mode 100755 index 0000000..0929f3c --- /dev/null +++ b/libs/CocosDenshion/CDAudioManager.m | |||
@@ -0,0 +1,887 @@ | |||
1 | /* | ||
2 | Copyright (c) 2010 Steve Oldmeadow | ||
3 | |||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | of this software and associated documentation files (the "Software"), to deal | ||
6 | in the Software without restriction, including without limitation the rights | ||
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
8 | copies of the Software, and to permit persons to whom the Software is | ||
9 | furnished to do so, subject to the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be included in | ||
12 | all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
20 | THE SOFTWARE. | ||
21 | |||
22 | $Id$ | ||
23 | */ | ||
24 | |||
25 | |||
26 | #import "CDAudioManager.h" | ||
27 | |||
28 | NSString * const kCDN_AudioManagerInitialised = @"kCDN_AudioManagerInitialised"; | ||
29 | |||
30 | //NSOperation object used to asynchronously initialise | ||
31 | @implementation CDAsynchInitialiser | ||
32 | |||
33 | -(void) main { | ||
34 | [super main]; | ||
35 | [CDAudioManager sharedManager]; | ||
36 | } | ||
37 | |||
38 | @end | ||
39 | |||
40 | @implementation CDLongAudioSource | ||
41 | |||
42 | @synthesize audioSourcePlayer, audioSourceFilePath, delegate, backgroundMusic; | ||
43 | |||
44 | -(id) init { | ||
45 | if ((self = [super init])) { | ||
46 | state = kLAS_Init; | ||
47 | volume = 1.0f; | ||
48 | mute = NO; | ||
49 | enabled_ = YES; | ||
50 | } | ||
51 | return self; | ||
52 | } | ||
53 | |||
54 | -(void) dealloc { | ||
55 | CDLOGINFO(@"Denshion::CDLongAudioSource - deallocating %@", self); | ||
56 | [audioSourcePlayer release]; | ||
57 | [audioSourceFilePath release]; | ||
58 | [super dealloc]; | ||
59 | } | ||
60 | |||
61 | -(void) load:(NSString*) filePath { | ||
62 | //We have alread loaded a file previously, check if we are being asked to load the same file | ||
63 | if (state == kLAS_Init || ![filePath isEqualToString:audioSourceFilePath]) { | ||
64 | CDLOGINFO(@"Denshion::CDLongAudioSource - Loading new audio source %@",filePath); | ||
65 | //New file | ||
66 | if (state != kLAS_Init) { | ||
67 | [audioSourceFilePath release];//Release old file path | ||
68 | [audioSourcePlayer release];//Release old AVAudioPlayer, they can't be reused | ||
69 | } | ||
70 | audioSourceFilePath = [filePath copy]; | ||
71 | NSError *error = nil; | ||
72 | NSString *path = [CDUtilities fullPathFromRelativePath:audioSourceFilePath]; | ||
73 | audioSourcePlayer = [(AVAudioPlayer*)[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error]; | ||
74 | if (error == nil) { | ||
75 | [audioSourcePlayer prepareToPlay]; | ||
76 | audioSourcePlayer.delegate = self; | ||
77 | if (delegate && [delegate respondsToSelector:@selector(cdAudioSourceFileDidChange:)]) { | ||
78 | //Tell our delegate the file has changed | ||
79 | [delegate cdAudioSourceFileDidChange:self]; | ||
80 | } | ||
81 | } else { | ||
82 | CDLOG(@"Denshion::CDLongAudioSource - Error initialising audio player: %@",error); | ||
83 | } | ||
84 | } else { | ||
85 | //Same file - just return it to a consistent state | ||
86 | [self pause]; | ||
87 | [self rewind]; | ||
88 | } | ||
89 | audioSourcePlayer.volume = volume; | ||
90 | audioSourcePlayer.numberOfLoops = numberOfLoops; | ||
91 | state = kLAS_Loaded; | ||
92 | } | ||
93 | |||
94 | -(void) play { | ||
95 | if (enabled_) { | ||
96 | self->systemPaused = NO; | ||
97 | [audioSourcePlayer play]; | ||
98 | } else { | ||
99 | CDLOGINFO(@"Denshion::CDLongAudioSource long audio source didn't play because it is disabled"); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | -(void) stop { | ||
104 | [audioSourcePlayer stop]; | ||
105 | } | ||
106 | |||
107 | -(void) pause { | ||
108 | [audioSourcePlayer pause]; | ||
109 | } | ||
110 | |||
111 | -(void) rewind { | ||
112 | [audioSourcePlayer setCurrentTime:0]; | ||
113 | } | ||
114 | |||
115 | -(void) resume { | ||
116 | [audioSourcePlayer play]; | ||
117 | } | ||
118 | |||
119 | -(BOOL) isPlaying { | ||
120 | if (state != kLAS_Init) { | ||
121 | return [audioSourcePlayer isPlaying]; | ||
122 | } else { | ||
123 | return NO; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | -(void) setVolume:(float) newVolume | ||
128 | { | ||
129 | volume = newVolume; | ||
130 | if (state != kLAS_Init && !mute) { | ||
131 | audioSourcePlayer.volume = newVolume; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | -(float) volume | ||
136 | { | ||
137 | return volume; | ||
138 | } | ||
139 | |||
140 | #pragma mark Audio Interrupt Protocol | ||
141 | -(BOOL) mute | ||
142 | { | ||
143 | return mute; | ||
144 | } | ||
145 | |||
146 | -(void) setMute:(BOOL) muteValue | ||
147 | { | ||
148 | if (mute != muteValue) { | ||
149 | if (mute) { | ||
150 | //Turn sound back on | ||
151 | audioSourcePlayer.volume = volume; | ||
152 | } else { | ||
153 | audioSourcePlayer.volume = 0.0f; | ||
154 | } | ||
155 | mute = muteValue; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | -(BOOL) enabled | ||
160 | { | ||
161 | return enabled_; | ||
162 | } | ||
163 | |||
164 | -(void) setEnabled:(BOOL)enabledValue | ||
165 | { | ||
166 | if (enabledValue != enabled_) { | ||
167 | enabled_ = enabledValue; | ||
168 | if (!enabled_) { | ||
169 | //"Stop" the sounds | ||
170 | [self pause]; | ||
171 | [self rewind]; | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | -(NSInteger) numberOfLoops { | ||
177 | return numberOfLoops; | ||
178 | } | ||
179 | |||
180 | -(void) setNumberOfLoops:(NSInteger) loopCount | ||
181 | { | ||
182 | audioSourcePlayer.numberOfLoops = loopCount; | ||
183 | numberOfLoops = loopCount; | ||
184 | } | ||
185 | |||
186 | - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { | ||
187 | CDLOGINFO(@"Denshion::CDLongAudioSource - audio player finished"); | ||
188 | #if TARGET_IPHONE_SIMULATOR | ||
189 | CDLOGINFO(@"Denshion::CDLongAudioSource - workaround for OpenAL clobbered audio issue"); | ||
190 | //This is a workaround for an issue in all simulators (tested to 3.1.2). Problem is | ||
191 | //that OpenAL audio playback is clobbered when an AVAudioPlayer stops. Workaround | ||
192 | //is to keep the player playing on an endless loop with 0 volume and then when | ||
193 | //it is played again reset the volume and set loop count appropriately. | ||
194 | //NB: this workaround is not foolproof but it is good enough for most situations. | ||
195 | player.numberOfLoops = -1; | ||
196 | player.volume = 0; | ||
197 | [player play]; | ||
198 | #endif | ||
199 | if (delegate && [delegate respondsToSelector:@selector(cdAudioSourceDidFinishPlaying:)]) { | ||
200 | [delegate cdAudioSourceDidFinishPlaying:self]; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | -(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player { | ||
205 | CDLOGINFO(@"Denshion::CDLongAudioSource - audio player interrupted"); | ||
206 | } | ||
207 | |||
208 | -(void)audioPlayerEndInterruption:(AVAudioPlayer *)player { | ||
209 | CDLOGINFO(@"Denshion::CDLongAudioSource - audio player resumed"); | ||
210 | if (self.backgroundMusic) { | ||
211 | //Check if background music can play as rules may have changed during | ||
212 | //the interruption. This is to address a specific issue in 4.x when | ||
213 | //fast task switching | ||
214 | if([CDAudioManager sharedManager].willPlayBackgroundMusic) { | ||
215 | [player play]; | ||
216 | } | ||
217 | } else { | ||
218 | [player play]; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | @end | ||
223 | |||
224 | |||
225 | @interface CDAudioManager (PrivateMethods) | ||
226 | -(BOOL) audioSessionSetActive:(BOOL) active; | ||
227 | -(BOOL) audioSessionSetCategory:(NSString*) category; | ||
228 | -(void) badAlContextHandler; | ||
229 | @end | ||
230 | |||
231 | |||
232 | @implementation CDAudioManager | ||
233 | #define BACKGROUND_MUSIC_CHANNEL kASC_Left | ||
234 | |||
235 | @synthesize soundEngine, willPlayBackgroundMusic; | ||
236 | static CDAudioManager *sharedManager; | ||
237 | static tAudioManagerState _sharedManagerState = kAMStateUninitialised; | ||
238 | static tAudioManagerMode configuredMode; | ||
239 | static BOOL configured = FALSE; | ||
240 | |||
241 | -(BOOL) audioSessionSetActive:(BOOL) active { | ||
242 | NSError *activationError = nil; | ||
243 | if ([[AVAudioSession sharedInstance] setActive:active error:&activationError]) { | ||
244 | _audioSessionActive = active; | ||
245 | CDLOGINFO(@"Denshion::CDAudioManager - Audio session set active %i succeeded", active); | ||
246 | return YES; | ||
247 | } else { | ||
248 | //Failed | ||
249 | CDLOG(@"Denshion::CDAudioManager - Audio session set active %i failed with error %@", active, activationError); | ||
250 | return NO; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | -(BOOL) audioSessionSetCategory:(NSString*) category { | ||
255 | NSError *categoryError = nil; | ||
256 | if ([[AVAudioSession sharedInstance] setCategory:category error:&categoryError]) { | ||
257 | CDLOGINFO(@"Denshion::CDAudioManager - Audio session set category %@ succeeded", category); | ||
258 | return YES; | ||
259 | } else { | ||
260 | //Failed | ||
261 | CDLOG(@"Denshion::CDAudioManager - Audio session set category %@ failed with error %@", category, categoryError); | ||
262 | return NO; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | // Init | ||
267 | + (CDAudioManager *) sharedManager | ||
268 | { | ||
269 | @synchronized(self) { | ||
270 | if (!sharedManager) { | ||
271 | if (!configured) { | ||
272 | //Set defaults here | ||
273 | configuredMode = kAMM_FxPlusMusicIfNoOtherAudio; | ||
274 | } | ||
275 | sharedManager = [[CDAudioManager alloc] init:configuredMode]; | ||
276 | _sharedManagerState = kAMStateInitialised;//This is only really relevant when using asynchronous initialisation | ||
277 | [[NSNotificationCenter defaultCenter] postNotificationName:kCDN_AudioManagerInitialised object:nil]; | ||
278 | } | ||
279 | } | ||
280 | return sharedManager; | ||
281 | } | ||
282 | |||
283 | + (tAudioManagerState) sharedManagerState { | ||
284 | return _sharedManagerState; | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * Call this to set up audio manager asynchronously. Initialisation is finished when sharedManagerState == kAMStateInitialised | ||
289 | */ | ||
290 | + (void) initAsynchronously: (tAudioManagerMode) mode { | ||
291 | @synchronized(self) { | ||
292 | if (_sharedManagerState == kAMStateUninitialised) { | ||
293 | _sharedManagerState = kAMStateInitialising; | ||
294 | [CDAudioManager configure:mode]; | ||
295 | CDAsynchInitialiser *initOp = [[[CDAsynchInitialiser alloc] init] autorelease]; | ||
296 | NSOperationQueue *opQ = [[[NSOperationQueue alloc] init] autorelease]; | ||
297 | [opQ addOperation:initOp]; | ||
298 | } | ||
299 | } | ||
300 | } | ||
301 | |||
302 | + (id) alloc | ||
303 | { | ||
304 | @synchronized(self) { | ||
305 | NSAssert(sharedManager == nil, @"Attempted to allocate a second instance of a singleton."); | ||
306 | return [super alloc]; | ||
307 | } | ||
308 | return nil; | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * Call this method before accessing the shared manager in order to configure the shared audio manager | ||
313 | */ | ||
314 | + (void) configure: (tAudioManagerMode) mode { | ||
315 | configuredMode = mode; | ||
316 | configured = TRUE; | ||
317 | } | ||
318 | |||
319 | -(BOOL) isOtherAudioPlaying { | ||
320 | UInt32 isPlaying = 0; | ||
321 | UInt32 varSize = sizeof(isPlaying); | ||
322 | AudioSessionGetProperty (kAudioSessionProperty_OtherAudioIsPlaying, &varSize, &isPlaying); | ||
323 | return (isPlaying != 0); | ||
324 | } | ||
325 | |||
326 | -(void) setMode:(tAudioManagerMode) mode { | ||
327 | |||
328 | _mode = mode; | ||
329 | switch (_mode) { | ||
330 | |||
331 | case kAMM_FxOnly: | ||
332 | //Share audio with other app | ||
333 | CDLOGINFO(@"Denshion::CDAudioManager - Audio will be shared"); | ||
334 | //_audioSessionCategory = kAudioSessionCategory_AmbientSound; | ||
335 | _audioSessionCategory = AVAudioSessionCategoryAmbient; | ||
336 | willPlayBackgroundMusic = NO; | ||
337 | break; | ||
338 | |||
339 | case kAMM_FxPlusMusic: | ||
340 | //Use audio exclusively - if other audio is playing it will be stopped | ||
341 | CDLOGINFO(@"Denshion::CDAudioManager - Audio will be exclusive"); | ||
342 | //_audioSessionCategory = kAudioSessionCategory_SoloAmbientSound; | ||
343 | _audioSessionCategory = AVAudioSessionCategorySoloAmbient; | ||
344 | willPlayBackgroundMusic = YES; | ||
345 | break; | ||
346 | |||
347 | case kAMM_MediaPlayback: | ||
348 | //Use audio exclusively, ignore mute switch and sleep | ||
349 | CDLOGINFO(@"Denshion::CDAudioManager - Media playback mode, audio will be exclusive"); | ||
350 | //_audioSessionCategory = kAudioSessionCategory_MediaPlayback; | ||
351 | _audioSessionCategory = AVAudioSessionCategoryPlayback; | ||
352 | willPlayBackgroundMusic = YES; | ||
353 | break; | ||
354 | |||
355 | case kAMM_PlayAndRecord: | ||
356 | //Use audio exclusively, ignore mute switch and sleep, has inputs and outputs | ||
357 | CDLOGINFO(@"Denshion::CDAudioManager - Play and record mode, audio will be exclusive"); | ||
358 | //_audioSessionCategory = kAudioSessionCategory_PlayAndRecord; | ||
359 | _audioSessionCategory = AVAudioSessionCategoryPlayAndRecord; | ||
360 | willPlayBackgroundMusic = YES; | ||
361 | break; | ||
362 | |||
363 | default: | ||
364 | //kAudioManagerFxPlusMusicIfNoOtherAudio | ||
365 | if ([self isOtherAudioPlaying]) { | ||
366 | CDLOGINFO(@"Denshion::CDAudioManager - Other audio is playing audio will be shared"); | ||
367 | //_audioSessionCategory = kAudioSessionCategory_AmbientSound; | ||
368 | _audioSessionCategory = AVAudioSessionCategoryAmbient; | ||
369 | willPlayBackgroundMusic = NO; | ||
370 | } else { | ||
371 | CDLOGINFO(@"Denshion::CDAudioManager - Other audio is not playing audio will be exclusive"); | ||
372 | //_audioSessionCategory = kAudioSessionCategory_SoloAmbientSound; | ||
373 | _audioSessionCategory = AVAudioSessionCategorySoloAmbient; | ||
374 | willPlayBackgroundMusic = YES; | ||
375 | } | ||
376 | |||
377 | break; | ||
378 | } | ||
379 | |||
380 | [self audioSessionSetCategory:_audioSessionCategory]; | ||
381 | |||
382 | } | ||
383 | |||
384 | /** | ||
385 | * This method is used to work around various bugs introduced in 4.x OS versions. In some circumstances the | ||
386 | * audio session is interrupted but never resumed, this results in the loss of OpenAL audio when following | ||
387 | * standard practices. If we detect this situation then we will attempt to resume the audio session ourselves. | ||
388 | * Known triggers: lock the device then unlock it (iOS 4.2 gm), playback a song using MPMediaPlayer (iOS 4.0) | ||
389 | */ | ||
390 | - (void) badAlContextHandler { | ||
391 | if (_interrupted && alcGetCurrentContext() == NULL) { | ||
392 | CDLOG(@"Denshion::CDAudioManager - bad OpenAL context detected, attempting to resume audio session"); | ||
393 | [self audioSessionResumed]; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | - (id) init: (tAudioManagerMode) mode { | ||
398 | if ((self = [super init])) { | ||
399 | |||
400 | //Initialise the audio session | ||
401 | AVAudioSession* session = [AVAudioSession sharedInstance]; | ||
402 | session.delegate = self; | ||
403 | |||
404 | _mode = mode; | ||
405 | backgroundMusicCompletionSelector = nil; | ||
406 | _isObservingAppEvents = FALSE; | ||
407 | _mute = NO; | ||
408 | _resigned = NO; | ||
409 | _interrupted = NO; | ||
410 | enabled_ = YES; | ||
411 | _audioSessionActive = NO; | ||
412 | [self setMode:mode]; | ||
413 | soundEngine = [[CDSoundEngine alloc] init]; | ||
414 | |||
415 | //Set up audioSource channels | ||
416 | audioSourceChannels = [[NSMutableArray alloc] init]; | ||
417 | CDLongAudioSource *leftChannel = [[CDLongAudioSource alloc] init]; | ||
418 | leftChannel.backgroundMusic = YES; | ||
419 | CDLongAudioSource *rightChannel = [[CDLongAudioSource alloc] init]; | ||
420 | rightChannel.backgroundMusic = NO; | ||
421 | [audioSourceChannels insertObject:leftChannel atIndex:kASC_Left]; | ||
422 | [audioSourceChannels insertObject:rightChannel atIndex:kASC_Right]; | ||
423 | [leftChannel release]; | ||
424 | [rightChannel release]; | ||
425 | //Used to support legacy APIs | ||
426 | backgroundMusic = [self audioSourceForChannel:BACKGROUND_MUSIC_CHANNEL]; | ||
427 | backgroundMusic.delegate = self; | ||
428 | |||
429 | //Add handler for bad al context messages, these are posted by the sound engine. | ||
430 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(badAlContextHandler) name:kCDN_BadAlContext object:nil]; | ||
431 | |||
432 | } | ||
433 | return self; | ||
434 | } | ||
435 | |||
436 | -(void) dealloc { | ||
437 | CDLOGINFO(@"Denshion::CDAudioManager - deallocating"); | ||
438 | [self stopBackgroundMusic]; | ||
439 | [soundEngine release]; | ||
440 | [[NSNotificationCenter defaultCenter] removeObserver:self]; | ||
441 | [self audioSessionSetActive:NO]; | ||
442 | [audioSourceChannels release]; | ||
443 | [super dealloc]; | ||
444 | } | ||
445 | |||
446 | /** Retrieves the audio source for the specified channel */ | ||
447 | -(CDLongAudioSource*) audioSourceForChannel:(tAudioSourceChannel) channel | ||
448 | { | ||
449 | return (CDLongAudioSource*)[audioSourceChannels objectAtIndex:channel]; | ||
450 | } | ||
451 | |||
452 | /** Loads the data from the specified file path to the channel's audio source */ | ||
453 | -(CDLongAudioSource*) audioSourceLoad:(NSString*) filePath channel:(tAudioSourceChannel) channel | ||
454 | { | ||
455 | CDLongAudioSource *audioSource = [self audioSourceForChannel:channel]; | ||
456 | if (audioSource) { | ||
457 | [audioSource load:filePath]; | ||
458 | } | ||
459 | return audioSource; | ||
460 | } | ||
461 | |||
462 | -(BOOL) isBackgroundMusicPlaying { | ||
463 | return [self.backgroundMusic isPlaying]; | ||
464 | } | ||
465 | |||
466 | //NB: originally I tried using a route change listener and intended to store the current route, | ||
467 | //however, on a 3gs running 3.1.2 no route change is generated when the user switches the | ||
468 | //ringer mute switch to off (i.e. enables sound) therefore polling is the only reliable way to | ||
469 | //determine ringer switch state | ||
470 | -(BOOL) isDeviceMuted { | ||
471 | |||
472 | #if TARGET_IPHONE_SIMULATOR | ||
473 | //Calling audio route stuff on the simulator causes problems | ||
474 | return NO; | ||
475 | #else | ||
476 | CFStringRef newAudioRoute; | ||
477 | UInt32 propertySize = sizeof (CFStringRef); | ||
478 | |||
479 | AudioSessionGetProperty ( | ||
480 | kAudioSessionProperty_AudioRoute, | ||
481 | &propertySize, | ||
482 | &newAudioRoute | ||
483 | ); | ||
484 | |||
485 | if (newAudioRoute == NULL) { | ||
486 | //Don't expect this to happen but playing safe otherwise a null in the CFStringCompare will cause a crash | ||
487 | return YES; | ||
488 | } else { | ||
489 | CFComparisonResult newDeviceIsMuted = CFStringCompare ( | ||
490 | newAudioRoute, | ||
491 | (CFStringRef) @"", | ||
492 | 0 | ||
493 | ); | ||
494 | |||
495 | return (newDeviceIsMuted == kCFCompareEqualTo); | ||
496 | } | ||
497 | #endif | ||
498 | } | ||
499 | |||
500 | #pragma mark Audio Interrupt Protocol | ||
501 | |||
502 | -(BOOL) mute { | ||
503 | return _mute; | ||
504 | } | ||
505 | |||
506 | -(void) setMute:(BOOL) muteValue { | ||
507 | if (muteValue != _mute) { | ||
508 | _mute = muteValue; | ||
509 | [soundEngine setMute:muteValue]; | ||
510 | for( CDLongAudioSource *audioSource in audioSourceChannels) { | ||
511 | audioSource.mute = muteValue; | ||
512 | } | ||
513 | } | ||
514 | } | ||
515 | |||
516 | -(BOOL) enabled { | ||
517 | return enabled_; | ||
518 | } | ||
519 | |||
520 | -(void) setEnabled:(BOOL) enabledValue { | ||
521 | if (enabledValue != enabled_) { | ||
522 | enabled_ = enabledValue; | ||
523 | [soundEngine setEnabled:enabled_]; | ||
524 | for( CDLongAudioSource *audioSource in audioSourceChannels) { | ||
525 | audioSource.enabled = enabled_; | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | |||
530 | -(CDLongAudioSource*) backgroundMusic | ||
531 | { | ||
532 | return backgroundMusic; | ||
533 | } | ||
534 | |||
535 | //Load background music ready for playing | ||
536 | -(void) preloadBackgroundMusic:(NSString*) filePath | ||
537 | { | ||
538 | [self.backgroundMusic load:filePath]; | ||
539 | } | ||
540 | |||
541 | -(void) playBackgroundMusic:(NSString*) filePath loop:(BOOL) loop | ||
542 | { | ||
543 | [self.backgroundMusic load:filePath]; | ||
544 | |||
545 | if (!willPlayBackgroundMusic || _mute) { | ||
546 | CDLOGINFO(@"Denshion::CDAudioManager - play bgm aborted because audio is not exclusive or sound is muted"); | ||
547 | return; | ||
548 | } | ||
549 | |||
550 | if (loop) { | ||
551 | [self.backgroundMusic setNumberOfLoops:-1]; | ||
552 | } else { | ||
553 | [self.backgroundMusic setNumberOfLoops:0]; | ||
554 | } | ||
555 | [self.backgroundMusic play]; | ||
556 | } | ||
557 | |||
558 | -(void) stopBackgroundMusic | ||
559 | { | ||
560 | [self.backgroundMusic stop]; | ||
561 | } | ||
562 | |||
563 | -(void) pauseBackgroundMusic | ||
564 | { | ||
565 | [self.backgroundMusic pause]; | ||
566 | } | ||
567 | |||
568 | -(void) resumeBackgroundMusic | ||
569 | { | ||
570 | if (!willPlayBackgroundMusic || _mute) { | ||
571 | CDLOGINFO(@"Denshion::CDAudioManager - resume bgm aborted because audio is not exclusive or sound is muted"); | ||
572 | return; | ||
573 | } | ||
574 | |||
575 | [self.backgroundMusic resume]; | ||
576 | } | ||
577 | |||
578 | -(void) rewindBackgroundMusic | ||
579 | { | ||
580 | [self.backgroundMusic rewind]; | ||
581 | } | ||
582 | |||
583 | -(void) setBackgroundMusicCompletionListener:(id) listener selector:(SEL) selector { | ||
584 | backgroundMusicCompletionListener = listener; | ||
585 | backgroundMusicCompletionSelector = selector; | ||
586 | } | ||
587 | |||
588 | /* | ||
589 | * Call this method to have the audio manager automatically handle application resign and | ||
590 | * become active. Pass a tAudioManagerResignBehavior to indicate the desired behavior | ||
591 | * for resigning and becoming active again. | ||
592 | * | ||
593 | * If autohandle is YES then the applicationWillResignActive and applicationDidBecomActive | ||
594 | * methods are automatically called, otherwise you must call them yourself at the appropriate time. | ||
595 | * | ||
596 | * Based on idea of Dominique Bongard | ||
597 | */ | ||
598 | -(void) setResignBehavior:(tAudioManagerResignBehavior) resignBehavior autoHandle:(BOOL) autoHandle { | ||
599 | |||
600 | if (!_isObservingAppEvents && autoHandle) { | ||
601 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:@"UIApplicationWillResignActiveNotification" object:nil]; | ||
602 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:@"UIApplicationDidBecomeActiveNotification" object:nil]; | ||
603 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:@"UIApplicationWillTerminateNotification" object:nil]; | ||
604 | _isObservingAppEvents = TRUE; | ||
605 | } | ||
606 | _resignBehavior = resignBehavior; | ||
607 | } | ||
608 | |||
609 | - (void) applicationWillResignActive { | ||
610 | self->_resigned = YES; | ||
611 | |||
612 | //Set the audio sesssion to one that allows sharing so that other audio won't be clobbered on resume | ||
613 | [self audioSessionSetCategory:AVAudioSessionCategoryAmbient]; | ||
614 | |||
615 | switch (_resignBehavior) { | ||
616 | |||
617 | case kAMRBStopPlay: | ||
618 | |||
619 | for( CDLongAudioSource *audioSource in audioSourceChannels) { | ||
620 | if (audioSource.isPlaying) { | ||
621 | audioSource->systemPaused = YES; | ||
622 | audioSource->systemPauseLocation = audioSource.audioSourcePlayer.currentTime; | ||
623 | [audioSource stop]; | ||
624 | } else { | ||
625 | //Music is either paused or stopped, if it is paused it will be restarted | ||
626 | //by OS so we will stop it. | ||
627 | audioSource->systemPaused = NO; | ||
628 | [audioSource stop]; | ||
629 | } | ||
630 | } | ||
631 | break; | ||
632 | |||
633 | case kAMRBStop: | ||
634 | //Stop music regardless of whether it is playing or not because if it was paused | ||
635 | //then the OS would resume it | ||
636 | for( CDLongAudioSource *audioSource in audioSourceChannels) { | ||
637 | [audioSource stop]; | ||
638 | } | ||
639 | |||
640 | default: | ||
641 | break; | ||
642 | |||
643 | } | ||
644 | CDLOGINFO(@"Denshion::CDAudioManager - handled resign active"); | ||
645 | } | ||
646 | |||
647 | //Called when application resigns active only if setResignBehavior has been called | ||
648 | - (void) applicationWillResignActive:(NSNotification *) notification | ||
649 | { | ||
650 | [self applicationWillResignActive]; | ||
651 | } | ||
652 | |||
653 | - (void) applicationDidBecomeActive { | ||
654 | |||
655 | if (self->_resigned) { | ||
656 | _resigned = NO; | ||
657 | //Reset the mode incase something changed with audio while we were inactive | ||
658 | [self setMode:_mode]; | ||
659 | switch (_resignBehavior) { | ||
660 | |||
661 | case kAMRBStopPlay: | ||
662 | |||
663 | //Music had been stopped but stop maintains current time | ||
664 | //so playing again will continue from where music was before resign active. | ||
665 | //We check if music can be played because while we were inactive the user might have | ||
666 | //done something that should force music to not play such as starting a track in the iPod | ||
667 | if (self.willPlayBackgroundMusic) { | ||
668 | for( CDLongAudioSource *audioSource in audioSourceChannels) { | ||
669 | if (audioSource->systemPaused) { | ||
670 | [audioSource resume]; | ||
671 | audioSource->systemPaused = NO; | ||
672 | } | ||
673 | } | ||
674 | } | ||
675 | break; | ||
676 | |||
677 | default: | ||
678 | break; | ||
679 | |||
680 | } | ||
681 | CDLOGINFO(@"Denshion::CDAudioManager - audio manager handled become active"); | ||
682 | } | ||
683 | } | ||
684 | |||
685 | //Called when application becomes active only if setResignBehavior has been called | ||
686 | - (void) applicationDidBecomeActive:(NSNotification *) notification | ||
687 | { | ||
688 | [self applicationDidBecomeActive]; | ||
689 | } | ||
690 | |||
691 | //Called when application terminates only if setResignBehavior has been called | ||
692 | - (void) applicationWillTerminate:(NSNotification *) notification | ||
693 | { | ||
694 | CDLOGINFO(@"Denshion::CDAudioManager - audio manager handling terminate"); | ||
695 | [self stopBackgroundMusic]; | ||
696 | } | ||
697 | |||
698 | /** The audio source completed playing */ | ||
699 | - (void) cdAudioSourceDidFinishPlaying:(CDLongAudioSource *) audioSource { | ||
700 | CDLOGINFO(@"Denshion::CDAudioManager - audio manager got told background music finished"); | ||
701 | if (backgroundMusicCompletionSelector != nil) { | ||
702 | [backgroundMusicCompletionListener performSelector:backgroundMusicCompletionSelector]; | ||
703 | } | ||
704 | } | ||
705 | |||
706 | -(void) beginInterruption { | ||
707 | CDLOGINFO(@"Denshion::CDAudioManager - begin interruption"); | ||
708 | [self audioSessionInterrupted]; | ||
709 | } | ||
710 | |||
711 | -(void) endInterruption { | ||
712 | CDLOGINFO(@"Denshion::CDAudioManager - end interruption"); | ||
713 | [self audioSessionResumed]; | ||
714 | } | ||
715 | |||
716 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000 | ||
717 | -(void) endInterruptionWithFlags:(NSUInteger)flags { | ||
718 | CDLOGINFO(@"Denshion::CDAudioManager - interruption ended with flags %i",flags); | ||
719 | if (flags == AVAudioSessionInterruptionFlags_ShouldResume) { | ||
720 | [self audioSessionResumed]; | ||
721 | } | ||
722 | } | ||
723 | #endif | ||
724 | |||
725 | -(void)audioSessionInterrupted | ||
726 | { | ||
727 | if (!_interrupted) { | ||
728 | CDLOGINFO(@"Denshion::CDAudioManager - Audio session interrupted"); | ||
729 | _interrupted = YES; | ||
730 | |||
731 | // Deactivate the current audio session | ||
732 | [self audioSessionSetActive:NO]; | ||
733 | |||
734 | if (alcGetCurrentContext() != NULL) { | ||
735 | CDLOGINFO(@"Denshion::CDAudioManager - Setting OpenAL context to NULL"); | ||
736 | |||
737 | ALenum error = AL_NO_ERROR; | ||
738 | |||
739 | // set the current context to NULL will 'shutdown' openAL | ||
740 | alcMakeContextCurrent(NULL); | ||
741 | |||
742 | if((error = alGetError()) != AL_NO_ERROR) { | ||
743 | CDLOG(@"Denshion::CDAudioManager - Error making context current %x\n", error); | ||
744 | } | ||
745 | #pragma unused(error) | ||
746 | } | ||
747 | } | ||
748 | } | ||
749 | |||
750 | -(void)audioSessionResumed | ||
751 | { | ||
752 | if (_interrupted) { | ||
753 | CDLOGINFO(@"Denshion::CDAudioManager - Audio session resumed"); | ||
754 | _interrupted = NO; | ||
755 | |||
756 | BOOL activationResult = NO; | ||
757 | // Reactivate the current audio session | ||
758 | activationResult = [self audioSessionSetActive:YES]; | ||
759 | |||
760 | //This code is to handle a problem with iOS 4.0 and 4.01 where reactivating the session can fail if | ||
761 | //task switching is performed too rapidly. A test case that reliably reproduces the issue is to call the | ||
762 | //iPhone and then hang up after two rings (timing may vary ;)) | ||
763 | //Basically we keep waiting and trying to let the OS catch up with itself but the number of tries is | ||
764 | //limited. | ||
765 | if (!activationResult) { | ||
766 | CDLOG(@"Denshion::CDAudioManager - Failure reactivating audio session, will try wait-try cycle"); | ||
767 | int activateCount = 0; | ||
768 | while (!activationResult && activateCount < 10) { | ||
769 | [NSThread sleepForTimeInterval:0.5]; | ||
770 | activationResult = [self audioSessionSetActive:YES]; | ||
771 | activateCount++; | ||
772 | CDLOGINFO(@"Denshion::CDAudioManager - Reactivation attempt %i status = %i",activateCount,activationResult); | ||
773 | } | ||
774 | } | ||
775 | |||
776 | if (alcGetCurrentContext() == NULL) { | ||
777 | CDLOGINFO(@"Denshion::CDAudioManager - Restoring OpenAL context"); | ||
778 | ALenum error = AL_NO_ERROR; | ||
779 | // Restore open al context | ||
780 | alcMakeContextCurrent([soundEngine openALContext]); | ||
781 | if((error = alGetError()) != AL_NO_ERROR) { | ||
782 | CDLOG(@"Denshion::CDAudioManager - Error making context current%x\n", error); | ||
783 | } | ||
784 | #pragma unused(error) | ||
785 | } | ||
786 | } | ||
787 | } | ||
788 | |||
789 | +(void) end { | ||
790 | [sharedManager release]; | ||
791 | sharedManager = nil; | ||
792 | } | ||
793 | |||
794 | @end | ||
795 | |||
796 | /////////////////////////////////////////////////////////////////////////////////////// | ||
797 | @implementation CDLongAudioSourceFader | ||
798 | |||
799 | -(void) _setTargetProperty:(float) newVal { | ||
800 | ((CDLongAudioSource*)target).volume = newVal; | ||
801 | } | ||
802 | |||
803 | -(float) _getTargetProperty { | ||
804 | return ((CDLongAudioSource*)target).volume; | ||
805 | } | ||
806 | |||
807 | -(void) _stopTarget { | ||
808 | //Pause instead of stop as stop releases resources and causes problems in the simulator | ||
809 | [((CDLongAudioSource*)target) pause]; | ||
810 | } | ||
811 | |||
812 | -(Class) _allowableType { | ||
813 | return [CDLongAudioSource class]; | ||
814 | } | ||
815 | |||
816 | @end | ||
817 | /////////////////////////////////////////////////////////////////////////////////////// | ||
818 | @implementation CDBufferManager | ||
819 | |||
820 | -(id) initWithEngine:(CDSoundEngine *) theSoundEngine { | ||
821 | if ((self = [super init])) { | ||
822 | soundEngine = theSoundEngine; | ||
823 | loadedBuffers = [[NSMutableDictionary alloc] initWithCapacity:CD_BUFFERS_START]; | ||
824 | freedBuffers = [[NSMutableArray alloc] init]; | ||
825 | nextBufferId = 0; | ||
826 | } | ||
827 | return self; | ||
828 | } | ||
829 | |||
830 | -(void) dealloc { | ||
831 | [loadedBuffers release]; | ||
832 | [freedBuffers release]; | ||
833 | [super dealloc]; | ||
834 | } | ||
835 | |||
836 | -(int) bufferForFile:(NSString*) filePath create:(BOOL) create { | ||
837 | |||
838 | NSNumber* soundId = (NSNumber*)[loadedBuffers objectForKey:filePath]; | ||
839 | if(soundId == nil) | ||
840 | { | ||
841 | if (create) { | ||
842 | NSNumber* bufferId = nil; | ||
843 | //First try to get a buffer from the free buffers | ||
844 | if ([freedBuffers count] > 0) { | ||
845 | bufferId = [[[freedBuffers lastObject] retain] autorelease]; | ||
846 | [freedBuffers removeLastObject]; | ||
847 | CDLOGINFO(@"Denshion::CDBufferManager reusing buffer id %i",[bufferId intValue]); | ||
848 | } else { | ||
849 | bufferId = [[NSNumber alloc] initWithInt:nextBufferId]; | ||
850 | [bufferId autorelease]; | ||
851 | CDLOGINFO(@"Denshion::CDBufferManager generating new buffer id %i",[bufferId intValue]); | ||
852 | nextBufferId++; | ||
853 | } | ||
854 | |||
855 | if ([soundEngine loadBuffer:[bufferId intValue] filePath:filePath]) { | ||
856 | //File successfully loaded | ||
857 | CDLOGINFO(@"Denshion::CDBufferManager buffer loaded %@ %@",bufferId,filePath); | ||
858 | [loadedBuffers setObject:bufferId forKey:filePath]; | ||
859 | return [bufferId intValue]; | ||
860 | } else { | ||
861 | //File didn't load, put buffer id on free list | ||
862 | [freedBuffers addObject:bufferId]; | ||
863 | return kCDNoBuffer; | ||
864 | } | ||
865 | } else { | ||
866 | //No matching buffer was found | ||
867 | return kCDNoBuffer; | ||
868 | } | ||
869 | } else { | ||
870 | return [soundId intValue]; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | -(void) releaseBufferForFile:(NSString *) filePath { | ||
875 | int bufferId = [self bufferForFile:filePath create:NO]; | ||
876 | if (bufferId != kCDNoBuffer) { | ||
877 | [soundEngine unloadBuffer:bufferId]; | ||
878 | [loadedBuffers removeObjectForKey:filePath]; | ||
879 | NSNumber *freedBufferId = [[NSNumber alloc] initWithInt:bufferId]; | ||
880 | [freedBufferId autorelease]; | ||
881 | [freedBuffers addObject:freedBufferId]; | ||
882 | } | ||
883 | } | ||
884 | @end | ||
885 | |||
886 | |||
887 | |||
diff --git a/libs/CocosDenshion/CDConfig.h b/libs/CocosDenshion/CDConfig.h new file mode 100755 index 0000000..2bd8f76 --- /dev/null +++ b/libs/CocosDenshion/CDConfig.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | Copyright (c) 2010 Steve Oldmeadow | ||
3 | |||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | of this software and associated documentation files (the "Software"), to deal | ||
6 | in the Software without restriction, including without limitation the rights | ||
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
8 | copies of the Software, and to permit persons to whom the Software is | ||
9 | furnished to do so, subject to the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be included in | ||
12 | all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
20 | THE SOFTWARE. | ||
21 | |||
22 | $Id$ | ||
23 | */ | ||
24 | #define COCOSDENSHION_VERSION "Aphex.rc" | ||
25 | |||
26 | |||
27 | /** | ||
28 | If enabled code useful for debugging such as parameter check assertions will be performed. | ||
29 | If you experience any problems you should enable this and test your code with a debug build. | ||
30 | */ | ||
31 | //#define CD_DEBUG 1 | ||
32 | |||
33 | /** | ||
34 | The total number of sounds/buffers that can be loaded assuming memory is sufficient | ||
35 | */ | ||
36 | //Number of buffers slots that will be initially created | ||
37 | #define CD_BUFFERS_START 64 | ||
38 | //Number of buffers that will be added | ||
39 | #define CD_BUFFERS_INCREMENT 16 | ||
40 | |||
41 | /** | ||
42 | If enabled, OpenAL code will use static buffers. When static buffers are used the audio | ||
43 | data is managed outside of OpenAL, this eliminates a memcpy operation which leads to | ||
44 | higher performance when loading sounds. | ||
45 | |||
46 | However, the downside is that when the audio data is freed you must | ||
47 | be certain that it is no longer being accessed otherwise your app will crash. Testing on OS 2.2.1 | ||
48 | and 3.1.2 has shown that this may occur if a buffer is being used by a source with state = AL_PLAYING | ||
49 | when the buffer is deleted. If the data is freed too quickly after the source is stopped then | ||
50 | a crash will occur. The implemented workaround is that when static buffers are used the unloadBuffer code will wait for | ||
51 | any playing sources to finish playing before the associated buffer and data are deleted, however, this delay may negate any | ||
52 | performance gains that are achieved during loading. | ||
53 | |||
54 | Performance tests on a 1st gen iPod running OS 2.2.1 loading the CocosDenshionDemo sounds were ~0.14 seconds without | ||
55 | static buffers and ~0.12 seconds when using static buffers. | ||
56 | |||
57 | */ | ||
58 | //#define CD_USE_STATIC_BUFFERS 1 | ||
59 | |||
60 | |||
diff --git a/libs/CocosDenshion/CDOpenALSupport.h b/libs/CocosDenshion/CDOpenALSupport.h new file mode 100755 index 0000000..661c69e --- /dev/null +++ b/libs/CocosDenshion/CDOpenALSupport.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | |||
3 | Disclaimer: IMPORTANT: This Apple software is supplied to you by | ||
4 | Apple Inc. ("Apple") in consideration of your agreement to the | ||
5 | following terms, and your use, installation, modification or | ||
6 | redistribution of this Apple software constitutes acceptance of these | ||
7 | terms. If you do not agree with these terms, please do not use, | ||
8 | install, modify or redistribute this Apple software. | ||
9 | |||
10 | In consideration of your agreement to abide by the following terms, and | ||
11 | subject to these terms, Apple grants you a personal, non-exclusive | ||
12 | license, under Apple's copyrights in this original Apple software (the | ||
13 | "Apple Software"), to use, reproduce, modify and redistribute the Apple | ||
14 | Software, with or without modifications, in source and/or binary forms; | ||
15 | provided that if you redistribute the Apple Software in its entirety and | ||
16 | without modifications, you must retain this notice and the following | ||
17 | text and disclaimers in all such redistributions of the Apple Software. | ||
18 | Neither the name, trademarks, service marks or logos of Apple Inc. | ||
19 | may be used to endorse or promote products derived from the Apple | ||
20 | Software without specific prior written permission from Apple. Except | ||
21 | as expressly stated in this notice, no other rights or licenses, express | ||
22 | or implied, are granted by Apple herein, including but not limited to | ||
23 | any patent rights that may be infringed by your derivative works or by | ||
24 | other works in which the Apple Software may be incorporated. | ||
25 | |||
26 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE | ||
27 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION | ||
28 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS | ||
29 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND | ||
30 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. | ||
31 | |||
32 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL | ||
33 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
34 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
35 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, | ||
36 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED | ||
37 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), | ||
38 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE | ||
39 | POSSIBILITY OF SUCH DAMAGE. | ||
40 | |||
41 | Copyright (C) 2009 Apple Inc. All Rights Reserved. | ||
42 | |||
43 | $Id$ | ||
44 | */ | ||
45 | |||
46 | /* | ||
47 | This file contains code from version 1.1 and 1.4 of MyOpenALSupport.h taken from Apple's oalTouch version. | ||
48 | The 1.4 version code is used for loading IMA4 files, however, this code causes very noticeable clicking | ||
49 | when used to load wave files that are looped so the 1.1 version code is used specifically for loading | ||
50 | wav files. | ||
51 | */ | ||
52 | |||
53 | #ifndef __CD_OPENAL_H | ||
54 | #define __CD_OPENAL_H | ||
55 | |||
56 | #ifdef __cplusplus | ||
57 | extern "C" { | ||
58 | #endif | ||
59 | |||
60 | |||
61 | #import <OpenAL/al.h> | ||
62 | #import <OpenAL/alc.h> | ||
63 | #import <CoreFoundation/CFURL.h> | ||
64 | |||
65 | |||
66 | //Taken from oalTouch MyOpenALSupport 1.1 | ||
67 | void* CDloadWaveAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate); | ||
68 | void* CDloadCafAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate); | ||
69 | void* CDGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate); | ||
70 | |||
71 | #ifdef __cplusplus | ||
72 | } | ||
73 | #endif | ||
74 | |||
75 | #endif | ||
76 | |||
77 | |||
diff --git a/libs/CocosDenshion/CDOpenALSupport.m b/libs/CocosDenshion/CDOpenALSupport.m new file mode 100755 index 0000000..ab0df8e --- /dev/null +++ b/libs/CocosDenshion/CDOpenALSupport.m | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | |||
3 | Disclaimer: IMPORTANT: This Apple software is supplied to you by | ||
4 | Apple Inc. ("Apple") in consideration of your agreement to the | ||
5 | following terms, and your use, installation, modification or | ||
6 | redistribution of this Apple software constitutes acceptance of these | ||
7 | terms. If you do not agree with these terms, please do not use, | ||
8 | install, modify or redistribute this Apple software. | ||
9 | |||
10 | In consideration of your agreement to abide by the following terms, and | ||
11 | subject to these terms, Apple grants you a personal, non-exclusive | ||
12 | license, under Apple's copyrights in this original Apple software (the | ||
13 | "Apple Software"), to use, reproduce, modify and redistribute the Apple | ||
14 | Software, with or without modifications, in source and/or binary forms; | ||
15 | provided that if you redistribute the Apple Software in its entirety and | ||
16 | without modifications, you must retain this notice and the following | ||
17 | text and disclaimers in all such redistributions of the Apple Software. | ||
18 | Neither the name, trademarks, service marks or logos of Apple Inc. | ||
19 | may be used to endorse or promote products derived from the Apple | ||
20 | Software without specific prior written permission from Apple. Except | ||
21 | as expressly stated in this notice, no other rights or licenses, express | ||
22 | or implied, are granted by Apple herein, including but not limited to | ||
23 | any patent rights that may be infringed by your derivative works or by | ||
24 | other works in which the Apple Software may be incorporated. | ||
25 | |||
26 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE | ||
27 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION | ||
28 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS | ||
29 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND | ||
30 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. | ||
31 | |||
32 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL | ||
33 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
34 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
35 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, | ||
36 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED | ||
37 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), | ||
38 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE | ||
39 | POSSIBILITY OF SUCH DAMAGE. | ||
40 | |||
41 | Copyright (C) 2009 Apple Inc. All Rights Reserved. | ||
42 | |||
43 | $Id: CDOpenALSupport.h 16 2010-03-11 06:22:10Z steveoldmeadow $ | ||
44 | */ | ||
45 | |||
46 | #import "CDOpenALSupport.h" | ||
47 | #import "CocosDenshion.h" | ||
48 | #import <AudioToolbox/AudioToolbox.h> | ||
49 | #import <AudioToolbox/ExtendedAudioFile.h> | ||
50 | |||
51 | //Taken from oalTouch MyOpenALSupport 1.1 | ||
52 | void* CDloadWaveAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate) | ||
53 | { | ||
54 | OSStatus err = noErr; | ||
55 | UInt64 fileDataSize = 0; | ||
56 | AudioStreamBasicDescription theFileFormat; | ||
57 | UInt32 thePropertySize = sizeof(theFileFormat); | ||
58 | AudioFileID afid = 0; | ||
59 | void* theData = NULL; | ||
60 | |||
61 | // Open a file with ExtAudioFileOpen() | ||
62 | err = AudioFileOpenURL(inFileURL, kAudioFileReadPermission, 0, &afid); | ||
63 | if(err) { CDLOG(@"MyGetOpenALAudioData: AudioFileOpenURL FAILED, Error = %ld\n", err); goto Exit; } | ||
64 | |||
65 | // Get the audio data format | ||
66 | err = AudioFileGetProperty(afid, kAudioFilePropertyDataFormat, &thePropertySize, &theFileFormat); | ||
67 | if(err) { CDLOG(@"MyGetOpenALAudioData: AudioFileGetProperty(kAudioFileProperty_DataFormat) FAILED, Error = %ld\n", err); goto Exit; } | ||
68 | |||
69 | if (theFileFormat.mChannelsPerFrame > 2) { | ||
70 | CDLOG(@"MyGetOpenALAudioData - Unsupported Format, channel count is greater than stereo\n"); goto Exit; | ||
71 | } | ||
72 | |||
73 | if ((theFileFormat.mFormatID != kAudioFormatLinearPCM) || (!TestAudioFormatNativeEndian(theFileFormat))) { | ||
74 | CDLOG(@"MyGetOpenALAudioData - Unsupported Format, must be little-endian PCM\n"); goto Exit; | ||
75 | } | ||
76 | |||
77 | if ((theFileFormat.mBitsPerChannel != 8) && (theFileFormat.mBitsPerChannel != 16)) { | ||
78 | CDLOG(@"MyGetOpenALAudioData - Unsupported Format, must be 8 or 16 bit PCM\n"); goto Exit; | ||
79 | } | ||
80 | |||
81 | |||
82 | thePropertySize = sizeof(fileDataSize); | ||
83 | err = AudioFileGetProperty(afid, kAudioFilePropertyAudioDataByteCount, &thePropertySize, &fileDataSize); | ||
84 | if(err) { CDLOG(@"MyGetOpenALAudioData: AudioFileGetProperty(kAudioFilePropertyAudioDataByteCount) FAILED, Error = %ld\n", err); goto Exit; } | ||
85 | |||
86 | // Read all the data into memory | ||
87 | UInt32 dataSize = (UInt32)fileDataSize; | ||
88 | theData = malloc(dataSize); | ||
89 | if (theData) | ||
90 | { | ||
91 | AudioFileReadBytes(afid, false, 0, &dataSize, theData); | ||
92 | if(err == noErr) | ||
93 | { | ||
94 | // success | ||
95 | *outDataSize = (ALsizei)dataSize; | ||
96 | //This fix was added by me, however, 8 bit sounds have a clipping sound at the end so aren't really usable (SO) | ||
97 | if (theFileFormat.mBitsPerChannel == 16) { | ||
98 | *outDataFormat = (theFileFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; | ||
99 | } else { | ||
100 | *outDataFormat = (theFileFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8; | ||
101 | } | ||
102 | *outSampleRate = (ALsizei)theFileFormat.mSampleRate; | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | // failure | ||
107 | free (theData); | ||
108 | theData = NULL; // make sure to return NULL | ||
109 | CDLOG(@"MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %ld\n", err); goto Exit; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | Exit: | ||
114 | // Dispose the ExtAudioFileRef, it is no longer needed | ||
115 | if (afid) AudioFileClose(afid); | ||
116 | return theData; | ||
117 | } | ||
118 | |||
119 | //Taken from oalTouch MyOpenALSupport 1.4 | ||
120 | void* CDloadCafAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate) | ||
121 | { | ||
122 | OSStatus status = noErr; | ||
123 | BOOL abort = NO; | ||
124 | SInt64 theFileLengthInFrames = 0; | ||
125 | AudioStreamBasicDescription theFileFormat; | ||
126 | UInt32 thePropertySize = sizeof(theFileFormat); | ||
127 | ExtAudioFileRef extRef = NULL; | ||
128 | void* theData = NULL; | ||
129 | AudioStreamBasicDescription theOutputFormat; | ||
130 | UInt32 dataSize = 0; | ||
131 | |||
132 | // Open a file with ExtAudioFileOpen() | ||
133 | status = ExtAudioFileOpenURL(inFileURL, &extRef); | ||
134 | if (status != noErr) | ||
135 | { | ||
136 | CDLOG(@"MyGetOpenALAudioData: ExtAudioFileOpenURL FAILED, Error = %ld\n", status); | ||
137 | abort = YES; | ||
138 | } | ||
139 | if (abort) | ||
140 | goto Exit; | ||
141 | |||
142 | // Get the audio data format | ||
143 | status = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &theFileFormat); | ||
144 | if (status != noErr) | ||
145 | { | ||
146 | CDLOG(@"MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %ld\n", status); | ||
147 | abort = YES; | ||
148 | } | ||
149 | if (abort) | ||
150 | goto Exit; | ||
151 | |||
152 | if (theFileFormat.mChannelsPerFrame > 2) | ||
153 | { | ||
154 | CDLOG(@"MyGetOpenALAudioData - Unsupported Format, channel count is greater than stereo\n"); | ||
155 | abort = YES; | ||
156 | } | ||
157 | if (abort) | ||
158 | goto Exit; | ||
159 | |||
160 | // Set the client format to 16 bit signed integer (native-endian) data | ||
161 | // Maintain the channel count and sample rate of the original source format | ||
162 | theOutputFormat.mSampleRate = theFileFormat.mSampleRate; | ||
163 | theOutputFormat.mChannelsPerFrame = theFileFormat.mChannelsPerFrame; | ||
164 | |||
165 | theOutputFormat.mFormatID = kAudioFormatLinearPCM; | ||
166 | theOutputFormat.mBytesPerPacket = 2 * theOutputFormat.mChannelsPerFrame; | ||
167 | theOutputFormat.mFramesPerPacket = 1; | ||
168 | theOutputFormat.mBytesPerFrame = 2 * theOutputFormat.mChannelsPerFrame; | ||
169 | theOutputFormat.mBitsPerChannel = 16; | ||
170 | theOutputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; | ||
171 | |||
172 | // Set the desired client (output) data format | ||
173 | status = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(theOutputFormat), &theOutputFormat); | ||
174 | if (status != noErr) | ||
175 | { | ||
176 | CDLOG(@"MyGetOpenALAudioData: ExtAudioFileSetProperty(kExtAudioFileProperty_ClientDataFormat) FAILED, Error = %ld\n", status); | ||
177 | abort = YES; | ||
178 | } | ||
179 | if (abort) | ||
180 | goto Exit; | ||
181 | |||
182 | // Get the total frame count | ||
183 | thePropertySize = sizeof(theFileLengthInFrames); | ||
184 | status = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames); | ||
185 | if (status != noErr) | ||
186 | { | ||
187 | CDLOG(@"MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileLengthFrames) FAILED, Error = %ld\n", status); | ||
188 | abort = YES; | ||
189 | } | ||
190 | if (abort) | ||
191 | goto Exit; | ||
192 | |||
193 | // Read all the data into memory | ||
194 | dataSize = (UInt32) theFileLengthInFrames * theOutputFormat.mBytesPerFrame; | ||
195 | theData = malloc(dataSize); | ||
196 | if (theData) | ||
197 | { | ||
198 | AudioBufferList theDataBuffer; | ||
199 | theDataBuffer.mNumberBuffers = 1; | ||
200 | theDataBuffer.mBuffers[0].mDataByteSize = dataSize; | ||
201 | theDataBuffer.mBuffers[0].mNumberChannels = theOutputFormat.mChannelsPerFrame; | ||
202 | theDataBuffer.mBuffers[0].mData = theData; | ||
203 | |||
204 | // Read the data into an AudioBufferList | ||
205 | status = ExtAudioFileRead(extRef, (UInt32*)&theFileLengthInFrames, &theDataBuffer); | ||
206 | if(status == noErr) | ||
207 | { | ||
208 | // success | ||
209 | *outDataSize = (ALsizei)dataSize; | ||
210 | *outDataFormat = (theOutputFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; | ||
211 | *outSampleRate = (ALsizei)theOutputFormat.mSampleRate; | ||
212 | } | ||
213 | else | ||
214 | { | ||
215 | // failure | ||
216 | free (theData); | ||
217 | theData = NULL; // make sure to return NULL | ||
218 | CDLOG(@"MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %ld\n", status); | ||
219 | abort = YES; | ||
220 | } | ||
221 | } | ||
222 | if (abort) | ||
223 | goto Exit; | ||
224 | |||
225 | Exit: | ||
226 | // Dispose the ExtAudioFileRef, it is no longer needed | ||
227 | if (extRef) ExtAudioFileDispose(extRef); | ||
228 | return theData; | ||
229 | } | ||
230 | |||
231 | void* CDGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate) { | ||
232 | |||
233 | CFStringRef extension = CFURLCopyPathExtension(inFileURL); | ||
234 | CFComparisonResult isWavFile = 0; | ||
235 | if (extension != NULL) { | ||
236 | isWavFile = CFStringCompare (extension,(CFStringRef)@"wav", kCFCompareCaseInsensitive); | ||
237 | CFRelease(extension); | ||
238 | } | ||
239 | |||
240 | if (isWavFile == kCFCompareEqualTo) { | ||
241 | return CDloadWaveAudioData(inFileURL, outDataSize, outDataFormat, outSampleRate); | ||
242 | } else { | ||
243 | return CDloadCafAudioData(inFileURL, outDataSize, outDataFormat, outSampleRate); | ||
244 | } | ||
245 | } | ||
246 | |||
diff --git a/libs/CocosDenshion/CocosDenshion.h b/libs/CocosDenshion/CocosDenshion.h new file mode 100755 index 0000000..638d852 --- /dev/null +++ b/libs/CocosDenshion/CocosDenshion.h | |||
@@ -0,0 +1,440 @@ | |||
1 | /* | ||
2 | Copyright (c) 2010 Steve Oldmeadow | ||
3 | |||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | of this software and associated documentation files (the "Software"), to deal | ||
6 | in the Software without restriction, including without limitation the rights | ||
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
8 | copies of the Software, and to permit persons to whom the Software is | ||
9 | furnished to do so, subject to the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be included in | ||
12 | all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
20 | THE SOFTWARE. | ||
21 | |||
22 | $Id$ | ||
23 | */ | ||
24 | |||
25 | |||
26 | |||
27 | /** | ||
28 | @file | ||
29 | @b IMPORTANT | ||
30 | There are 3 different ways of using CocosDenshion. Depending on which you choose you | ||
31 | will need to include different files and frameworks. | ||
32 | |||
33 | @par SimpleAudioEngine | ||
34 | This is recommended for basic audio requirements. If you just want to play some sound fx | ||
35 | and some background music and have no interest in learning the lower level workings then | ||
36 | this is the interface to use. | ||
37 | |||
38 | Requirements: | ||
39 | - Firmware: OS 2.2 or greater | ||
40 | - Files: SimpleAudioEngine.*, CocosDenshion.* | ||
41 | - Frameworks: OpenAL, AudioToolbox, AVFoundation | ||
42 | |||
43 | @par CDAudioManager | ||
44 | CDAudioManager is basically a thin wrapper around an AVAudioPlayer object used for playing | ||
45 | background music and a CDSoundEngine object used for playing sound effects. It manages the | ||
46 | audio session for you deals with audio session interruption. It is fairly low level and it | ||
47 | is expected you have some understanding of the underlying technologies. For example, for | ||
48 | many use cases regarding background music it is expected you will work directly with the | ||
49 | backgroundMusic AVAudioPlayer which is exposed as a property. | ||
50 | |||
51 | Requirements: | ||
52 | - Firmware: OS 2.2 or greater | ||
53 | - Files: CDAudioManager.*, CocosDenshion.* | ||
54 | - Frameworks: OpenAL, AudioToolbox, AVFoundation | ||
55 | |||
56 | @par CDSoundEngine | ||
57 | CDSoundEngine is a sound engine built upon OpenAL and derived from Apple's oalTouch | ||
58 | example. It can playback up to 32 sounds simultaneously with control over pitch, pan | ||
59 | and gain. It can be set up to handle audio session interruption automatically. You | ||
60 | may decide to use CDSoundEngine directly instead of CDAudioManager or SimpleAudioEngine | ||
61 | because you require OS 2.0 compatibility. | ||
62 | |||
63 | Requirements: | ||
64 | - Firmware: OS 2.0 or greater | ||
65 | - Files: CocosDenshion.* | ||
66 | - Frameworks: OpenAL, AudioToolbox | ||
67 | |||
68 | */ | ||
69 | |||
70 | #import <OpenAL/al.h> | ||
71 | #import <OpenAL/alc.h> | ||
72 | #import <AudioToolbox/AudioToolbox.h> | ||
73 | #import <Foundation/Foundation.h> | ||
74 | #import "CDConfig.h" | ||
75 | |||
76 | |||
77 | #if !defined(CD_DEBUG) || CD_DEBUG == 0 | ||
78 | #define CDLOG(...) do {} while (0) | ||
79 | #define CDLOGINFO(...) do {} while (0) | ||
80 | |||
81 | #elif CD_DEBUG == 1 | ||
82 | #define CDLOG(...) NSLog(__VA_ARGS__) | ||
83 | #define CDLOGINFO(...) do {} while (0) | ||
84 | |||
85 | #elif CD_DEBUG > 1 | ||
86 | #define CDLOG(...) NSLog(__VA_ARGS__) | ||
87 | #define CDLOGINFO(...) NSLog(__VA_ARGS__) | ||
88 | #endif // CD_DEBUG | ||
89 | |||
90 | |||
91 | #import "CDOpenALSupport.h" | ||
92 | |||
93 | //Tested source limit on 2.2.1 and 3.1.2 with up to 128 sources and appears to work. Older OS versions e.g 2.2 may support only 32 | ||
94 | #define CD_SOURCE_LIMIT 32 //Total number of sources we will ever want, may actually get less | ||
95 | #define CD_NO_SOURCE 0xFEEDFAC //Return value indicating playback failed i.e. no source | ||
96 | #define CD_IGNORE_AUDIO_SESSION 0xBEEFBEE //Used internally to indicate audio session will not be handled | ||
97 | #define CD_MUTE 0xFEEDBAB //Return value indicating sound engine is muted or non functioning | ||
98 | #define CD_NO_SOUND = -1; | ||
99 | |||
100 | #define CD_SAMPLE_RATE_HIGH 44100 | ||
101 | #define CD_SAMPLE_RATE_MID 22050 | ||
102 | #define CD_SAMPLE_RATE_LOW 16000 | ||
103 | #define CD_SAMPLE_RATE_BASIC 8000 | ||
104 | #define CD_SAMPLE_RATE_DEFAULT 44100 | ||
105 | |||
106 | extern NSString * const kCDN_BadAlContext; | ||
107 | extern NSString * const kCDN_AsynchLoadComplete; | ||
108 | |||
109 | extern float const kCD_PitchDefault; | ||
110 | extern float const kCD_PitchLowerOneOctave; | ||
111 | extern float const kCD_PitchHigherOneOctave; | ||
112 | extern float const kCD_PanDefault; | ||
113 | extern float const kCD_PanFullLeft; | ||
114 | extern float const kCD_PanFullRight; | ||
115 | extern float const kCD_GainDefault; | ||
116 | |||
117 | enum bufferState { | ||
118 | CD_BS_EMPTY = 0, | ||
119 | CD_BS_LOADED = 1, | ||
120 | CD_BS_FAILED = 2 | ||
121 | }; | ||
122 | |||
123 | typedef struct _sourceGroup { | ||
124 | int startIndex; | ||
125 | int currentIndex; | ||
126 | int totalSources; | ||
127 | bool enabled; | ||
128 | bool nonInterruptible; | ||
129 | int *sourceStatuses;//pointer into array of source status information | ||
130 | } sourceGroup; | ||
131 | |||
132 | typedef struct _bufferInfo { | ||
133 | ALuint bufferId; | ||
134 | int bufferState; | ||
135 | void* bufferData; | ||
136 | ALenum format; | ||
137 | ALsizei sizeInBytes; | ||
138 | ALsizei frequencyInHertz; | ||
139 | } bufferInfo; | ||
140 | |||
141 | typedef struct _sourceInfo { | ||
142 | bool usable; | ||
143 | ALuint sourceId; | ||
144 | ALuint attachedBufferId; | ||
145 | } sourceInfo; | ||
146 | |||
147 | #pragma mark CDAudioTransportProtocol | ||
148 | |||
149 | @protocol CDAudioTransportProtocol <NSObject> | ||
150 | /** Play the audio */ | ||
151 | -(BOOL) play; | ||
152 | /** Pause the audio, retain resources */ | ||
153 | -(BOOL) pause; | ||
154 | /** Stop the audio, release resources */ | ||
155 | -(BOOL) stop; | ||
156 | /** Return playback to beginning */ | ||
157 | -(BOOL) rewind; | ||
158 | @end | ||
159 | |||
160 | #pragma mark CDAudioInterruptProtocol | ||
161 | |||
162 | @protocol CDAudioInterruptProtocol <NSObject> | ||
163 | /** Is audio mute */ | ||
164 | -(BOOL) mute; | ||
165 | /** If YES then audio is silenced but not stopped, calls to start new audio will proceed but silently */ | ||
166 | -(void) setMute:(BOOL) muteValue; | ||
167 | /** Is audio enabled */ | ||
168 | -(BOOL) enabled; | ||
169 | /** If NO then all audio is stopped and any calls to start new audio will be ignored */ | ||
170 | -(void) setEnabled:(BOOL) enabledValue; | ||
171 | @end | ||
172 | |||
173 | #pragma mark CDUtilities | ||
174 | /** | ||
175 | Collection of utilities required by CocosDenshion | ||
176 | */ | ||
177 | @interface CDUtilities : NSObject | ||
178 | { | ||
179 | } | ||
180 | |||
181 | /** Fundamentally the same as the corresponding method is CCFileUtils but added to break binding to cocos2d */ | ||
182 | +(NSString*) fullPathFromRelativePath:(NSString*) relPath; | ||
183 | |||
184 | @end | ||
185 | |||
186 | |||
187 | #pragma mark CDSoundEngine | ||
188 | |||
189 | /** CDSoundEngine is built upon OpenAL and works with SDK 2.0. | ||
190 | CDSoundEngine is a sound engine built upon OpenAL and derived from Apple's oalTouch | ||
191 | example. It can playback up to 32 sounds simultaneously with control over pitch, pan | ||
192 | and gain. It can be set up to handle audio session interruption automatically. You | ||
193 | may decide to use CDSoundEngine directly instead of CDAudioManager or SimpleAudioEngine | ||
194 | because you require OS 2.0 compatibility. | ||
195 | |||
196 | Requirements: | ||
197 | - Firmware: OS 2.0 or greater | ||
198 | - Files: CocosDenshion.* | ||
199 | - Frameworks: OpenAL, AudioToolbox | ||
200 | |||
201 | @since v0.8 | ||
202 | */ | ||
203 | @class CDSoundSource; | ||
204 | @interface CDSoundEngine : NSObject <CDAudioInterruptProtocol> { | ||
205 | |||
206 | bufferInfo *_buffers; | ||
207 | sourceInfo *_sources; | ||
208 | sourceGroup *_sourceGroups; | ||
209 | ALCcontext *context; | ||
210 | NSUInteger _sourceGroupTotal; | ||
211 | UInt32 _audioSessionCategory; | ||
212 | BOOL _handleAudioSession; | ||
213 | ALfloat _preMuteGain; | ||
214 | NSObject *_mutexBufferLoad; | ||
215 | BOOL mute_; | ||
216 | BOOL enabled_; | ||
217 | |||
218 | ALenum lastErrorCode_; | ||
219 | BOOL functioning_; | ||
220 | float asynchLoadProgress_; | ||
221 | BOOL getGainWorks_; | ||
222 | |||
223 | //For managing dynamic allocation of sources and buffers | ||
224 | int sourceTotal_; | ||
225 | int bufferTotal; | ||
226 | |||
227 | } | ||
228 | |||
229 | @property (readwrite, nonatomic) ALfloat masterGain; | ||
230 | @property (readonly) ALenum lastErrorCode;//Last OpenAL error code that was generated | ||
231 | @property (readonly) BOOL functioning;//Is the sound engine functioning | ||
232 | @property (readwrite) float asynchLoadProgress; | ||
233 | @property (readonly) BOOL getGainWorks;//Does getting the gain for a source work | ||
234 | /** Total number of sources available */ | ||
235 | @property (readonly) int sourceTotal; | ||
236 | /** Total number of source groups that have been defined */ | ||
237 | @property (readonly) NSUInteger sourceGroupTotal; | ||
238 | |||
239 | /** Sets the sample rate for the audio mixer. For best performance this should match the sample rate of your audio content */ | ||
240 | +(void) setMixerSampleRate:(Float32) sampleRate; | ||
241 | |||
242 | /** Initializes the engine with a group definition and a total number of groups */ | ||
243 | -(id)init; | ||
244 | |||
245 | /** Plays a sound in a channel group with a pitch, pan and gain. The sound could played looped or not */ | ||
246 | -(ALuint) playSound:(int) soundId sourceGroupId:(int)sourceGroupId pitch:(float) pitch pan:(float) pan gain:(float) gain loop:(BOOL) loop; | ||
247 | |||
248 | /** Creates and returns a sound source object for the specified sound within the specified source group. | ||
249 | */ | ||
250 | -(CDSoundSource *) soundSourceForSound:(int) soundId sourceGroupId:(int) sourceGroupId; | ||
251 | |||
252 | /** Stops playing a sound */ | ||
253 | - (void) stopSound:(ALuint) sourceId; | ||
254 | /** Stops playing a source group */ | ||
255 | - (void) stopSourceGroup:(int) sourceGroupId; | ||
256 | /** Stops all playing sounds */ | ||
257 | -(void) stopAllSounds; | ||
258 | -(void) defineSourceGroups:(NSArray*) sourceGroupDefinitions; | ||
259 | -(void) defineSourceGroups:(int[]) sourceGroupDefinitions total:(NSUInteger) total; | ||
260 | -(void) setSourceGroupNonInterruptible:(int) sourceGroupId isNonInterruptible:(BOOL) isNonInterruptible; | ||
261 | -(void) setSourceGroupEnabled:(int) sourceGroupId enabled:(BOOL) enabled; | ||
262 | -(BOOL) sourceGroupEnabled:(int) sourceGroupId; | ||
263 | -(BOOL) loadBufferFromData:(int) soundId soundData:(ALvoid*) soundData format:(ALenum) format size:(ALsizei) size freq:(ALsizei) freq; | ||
264 | -(BOOL) loadBuffer:(int) soundId filePath:(NSString*) filePath; | ||
265 | -(void) loadBuffersAsynchronously:(NSArray *) loadRequests; | ||
266 | -(BOOL) unloadBuffer:(int) soundId; | ||
267 | -(ALCcontext *) openALContext; | ||
268 | |||
269 | /** Returns the duration of the buffer in seconds or a negative value if the buffer id is invalid */ | ||
270 | -(float) bufferDurationInSeconds:(int) soundId; | ||
271 | /** Returns the size of the buffer in bytes or a negative value if the buffer id is invalid */ | ||
272 | -(ALsizei) bufferSizeInBytes:(int) soundId; | ||
273 | /** Returns the sampling frequency of the buffer in hertz or a negative value if the buffer id is invalid */ | ||
274 | -(ALsizei) bufferFrequencyInHertz:(int) soundId; | ||
275 | |||
276 | /** Used internally, never call unless you know what you are doing */ | ||
277 | -(void) _soundSourcePreRelease:(CDSoundSource *) soundSource; | ||
278 | |||
279 | @end | ||
280 | |||
281 | #pragma mark CDSoundSource | ||
282 | /** CDSoundSource is a wrapper around an OpenAL sound source. | ||
283 | It allows you to manipulate properties such as pitch, gain, pan and looping while the | ||
284 | sound is playing. CDSoundSource is based on the old CDSourceWrapper class but with much | ||
285 | added functionality. | ||
286 | |||
287 | @since v1.0 | ||
288 | */ | ||
289 | @interface CDSoundSource : NSObject <CDAudioTransportProtocol, CDAudioInterruptProtocol> { | ||
290 | ALenum lastError; | ||
291 | @public | ||
292 | ALuint _sourceId; | ||
293 | ALuint _sourceIndex; | ||
294 | CDSoundEngine* _engine; | ||
295 | int _soundId; | ||
296 | float _preMuteGain; | ||
297 | BOOL enabled_; | ||
298 | BOOL mute_; | ||
299 | } | ||
300 | @property (readwrite, nonatomic) float pitch; | ||
301 | @property (readwrite, nonatomic) float gain; | ||
302 | @property (readwrite, nonatomic) float pan; | ||
303 | @property (readwrite, nonatomic) BOOL looping; | ||
304 | @property (readonly) BOOL isPlaying; | ||
305 | @property (readwrite, nonatomic) int soundId; | ||
306 | /** Returns the duration of the attached buffer in seconds or a negative value if the buffer is invalid */ | ||
307 | @property (readonly) float durationInSeconds; | ||
308 | |||
309 | /** Stores the last error code that occurred. Check against AL_NO_ERROR */ | ||
310 | @property (readonly) ALenum lastError; | ||
311 | /** Do not init yourself, get an instance from the sourceForSound factory method on CDSoundEngine */ | ||
312 | -(id)init:(ALuint) theSourceId sourceIndex:(int) index soundEngine:(CDSoundEngine*) engine; | ||
313 | |||
314 | @end | ||
315 | |||
316 | #pragma mark CDAudioInterruptTargetGroup | ||
317 | |||
318 | /** Container for objects that implement audio interrupt protocol i.e. they can be muted and enabled. | ||
319 | Setting mute and enabled for the group propagates to all children. | ||
320 | Designed to be used with your CDSoundSource objects to get them to comply with global enabled and mute settings | ||
321 | if that is what you want to do.*/ | ||
322 | @interface CDAudioInterruptTargetGroup : NSObject <CDAudioInterruptProtocol> { | ||
323 | BOOL mute_; | ||
324 | BOOL enabled_; | ||
325 | NSMutableArray *children_; | ||
326 | } | ||
327 | -(void) addAudioInterruptTarget:(NSObject<CDAudioInterruptProtocol>*) interruptibleTarget; | ||
328 | @end | ||
329 | |||
330 | #pragma mark CDAsynchBufferLoader | ||
331 | |||
332 | /** CDAsynchBufferLoader | ||
333 | TODO | ||
334 | */ | ||
335 | @interface CDAsynchBufferLoader : NSOperation { | ||
336 | NSArray *_loadRequests; | ||
337 | CDSoundEngine *_soundEngine; | ||
338 | } | ||
339 | |||
340 | -(id) init:(NSArray *)loadRequests soundEngine:(CDSoundEngine *) theSoundEngine; | ||
341 | |||
342 | @end | ||
343 | |||
344 | #pragma mark CDBufferLoadRequest | ||
345 | |||
346 | /** CDBufferLoadRequest */ | ||
347 | @interface CDBufferLoadRequest: NSObject | ||
348 | { | ||
349 | NSString *filePath; | ||
350 | int soundId; | ||
351 | //id loader; | ||
352 | } | ||
353 | |||
354 | @property (readonly) NSString *filePath; | ||
355 | @property (readonly) int soundId; | ||
356 | |||
357 | - (id)init:(int) theSoundId filePath:(const NSString *) theFilePath; | ||
358 | @end | ||
359 | |||
360 | /** Interpolation type */ | ||
361 | typedef enum { | ||
362 | kIT_Linear, //!Straight linear interpolation fade | ||
363 | kIT_SCurve, //!S curved interpolation | ||
364 | kIT_Exponential //!Exponential interpolation | ||
365 | } tCDInterpolationType; | ||
366 | |||
367 | #pragma mark CDFloatInterpolator | ||
368 | @interface CDFloatInterpolator: NSObject | ||
369 | { | ||
370 | float start; | ||
371 | float end; | ||
372 | float lastValue; | ||
373 | tCDInterpolationType interpolationType; | ||
374 | } | ||
375 | @property (readwrite, nonatomic) float start; | ||
376 | @property (readwrite, nonatomic) float end; | ||
377 | @property (readwrite, nonatomic) tCDInterpolationType interpolationType; | ||
378 | |||
379 | /** Return a value between min and max based on t which represents fractional progress where 0 is the start | ||
380 | and 1 is the end */ | ||
381 | -(float) interpolate:(float) t; | ||
382 | -(id) init:(tCDInterpolationType) type startVal:(float) startVal endVal:(float) endVal; | ||
383 | |||
384 | @end | ||
385 | |||
386 | #pragma mark CDPropertyModifier | ||
387 | |||
388 | /** Base class for classes that modify properties such as pitch, pan and gain */ | ||
389 | @interface CDPropertyModifier: NSObject | ||
390 | { | ||
391 | CDFloatInterpolator *interpolator; | ||
392 | float startValue; | ||
393 | float endValue; | ||
394 | id target; | ||
395 | BOOL stopTargetWhenComplete; | ||
396 | |||
397 | } | ||
398 | @property (readwrite, nonatomic) BOOL stopTargetWhenComplete; | ||
399 | @property (readwrite, nonatomic) float startValue; | ||
400 | @property (readwrite, nonatomic) float endValue; | ||
401 | @property (readwrite, nonatomic) tCDInterpolationType interpolationType; | ||
402 | |||
403 | -(id) init:(id) theTarget interpolationType:(tCDInterpolationType) type startVal:(float) startVal endVal:(float) endVal; | ||
404 | /** Set to a fractional value between 0 and 1 where 0 equals the start and 1 equals the end*/ | ||
405 | -(void) modify:(float) t; | ||
406 | |||
407 | -(void) _setTargetProperty:(float) newVal; | ||
408 | -(float) _getTargetProperty; | ||
409 | -(void) _stopTarget; | ||
410 | -(Class) _allowableType; | ||
411 | |||
412 | @end | ||
413 | |||
414 | #pragma mark CDSoundSourceFader | ||
415 | |||
416 | /** Fader for CDSoundSource objects */ | ||
417 | @interface CDSoundSourceFader : CDPropertyModifier{} | ||
418 | @end | ||
419 | |||
420 | #pragma mark CDSoundSourcePanner | ||
421 | |||
422 | /** Panner for CDSoundSource objects */ | ||
423 | @interface CDSoundSourcePanner : CDPropertyModifier{} | ||
424 | @end | ||
425 | |||
426 | #pragma mark CDSoundSourcePitchBender | ||
427 | |||
428 | /** Pitch bender for CDSoundSource objects */ | ||
429 | @interface CDSoundSourcePitchBender : CDPropertyModifier{} | ||
430 | @end | ||
431 | |||
432 | #pragma mark CDSoundEngineFader | ||
433 | |||
434 | /** Fader for CDSoundEngine objects */ | ||
435 | @interface CDSoundEngineFader : CDPropertyModifier{} | ||
436 | @end | ||
437 | |||
438 | |||
439 | |||
440 | |||
diff --git a/libs/CocosDenshion/CocosDenshion.m b/libs/CocosDenshion/CocosDenshion.m new file mode 100755 index 0000000..6956c3a --- /dev/null +++ b/libs/CocosDenshion/CocosDenshion.m | |||
@@ -0,0 +1,1602 @@ | |||
1 | /* | ||
2 | Copyright (c) 2010 Steve Oldmeadow | ||
3 | |||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | of this software and associated documentation files (the "Software"), to deal | ||
6 | in the Software without restriction, including without limitation the rights | ||
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
8 | copies of the Software, and to permit persons to whom the Software is | ||
9 | furnished to do so, subject to the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be included in | ||
12 | all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
20 | THE SOFTWARE. | ||
21 | |||
22 | $Id$ | ||
23 | */ | ||
24 | |||
25 | #import "CocosDenshion.h" | ||
26 | |||
27 | ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq); | ||
28 | ALvoid alcMacOSXMixerOutputRateProc(const ALdouble value); | ||
29 | |||
30 | |||
31 | typedef ALvoid AL_APIENTRY (*alBufferDataStaticProcPtr) (const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq); | ||
32 | ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq) | ||
33 | { | ||
34 | static alBufferDataStaticProcPtr proc = NULL; | ||
35 | |||
36 | if (proc == NULL) { | ||
37 | proc = (alBufferDataStaticProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alBufferDataStatic"); | ||
38 | } | ||
39 | |||
40 | if (proc) | ||
41 | proc(bid, format, data, size, freq); | ||
42 | |||
43 | return; | ||
44 | } | ||
45 | |||
46 | typedef ALvoid AL_APIENTRY (*alcMacOSXMixerOutputRateProcPtr) (const ALdouble value); | ||
47 | ALvoid alcMacOSXMixerOutputRateProc(const ALdouble value) | ||
48 | { | ||
49 | static alcMacOSXMixerOutputRateProcPtr proc = NULL; | ||
50 | |||
51 | if (proc == NULL) { | ||
52 | proc = (alcMacOSXMixerOutputRateProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcMacOSXMixerOutputRate"); | ||
53 | } | ||
54 | |||
55 | if (proc) | ||
56 | proc(value); | ||
57 | |||
58 | return; | ||
59 | } | ||
60 | |||
61 | NSString * const kCDN_BadAlContext = @"kCDN_BadAlContext"; | ||
62 | NSString * const kCDN_AsynchLoadComplete = @"kCDN_AsynchLoadComplete"; | ||
63 | float const kCD_PitchDefault = 1.0f; | ||
64 | float const kCD_PitchLowerOneOctave = 0.5f; | ||
65 | float const kCD_PitchHigherOneOctave = 2.0f; | ||
66 | float const kCD_PanDefault = 0.0f; | ||
67 | float const kCD_PanFullLeft = -1.0f; | ||
68 | float const kCD_PanFullRight = 1.0f; | ||
69 | float const kCD_GainDefault = 1.0f; | ||
70 | |||
71 | @interface CDSoundEngine (PrivateMethods) | ||
72 | -(BOOL) _initOpenAL; | ||
73 | -(void) _testGetGain; | ||
74 | -(void) _dumpSourceGroupsInfo; | ||
75 | -(void) _getSourceIndexForSourceGroup; | ||
76 | -(void) _freeSourceGroups; | ||
77 | -(BOOL) _setUpSourceGroups:(int[]) definitions total:(NSUInteger) total; | ||
78 | @end | ||
79 | |||
80 | #pragma mark - | ||
81 | #pragma mark CDUtilities | ||
82 | |||
83 | @implementation CDUtilities | ||
84 | |||
85 | +(NSString*) fullPathFromRelativePath:(NSString*) relPath | ||
86 | { | ||
87 | // do not convert an absolute path (starting with '/') | ||
88 | if(([relPath length] > 0) && ([relPath characterAtIndex:0] == '/')) | ||
89 | { | ||
90 | return relPath; | ||
91 | } | ||
92 | |||
93 | NSMutableArray *imagePathComponents = [NSMutableArray arrayWithArray:[relPath pathComponents]]; | ||
94 | NSString *file = [imagePathComponents lastObject]; | ||
95 | |||
96 | [imagePathComponents removeLastObject]; | ||
97 | NSString *imageDirectory = [NSString pathWithComponents:imagePathComponents]; | ||
98 | |||
99 | NSString *fullpath = [[NSBundle mainBundle] pathForResource:file ofType:nil inDirectory:imageDirectory]; | ||
100 | if (fullpath == nil) | ||
101 | fullpath = relPath; | ||
102 | |||
103 | return fullpath; | ||
104 | } | ||
105 | |||
106 | @end | ||
107 | |||
108 | #pragma mark - | ||
109 | #pragma mark CDSoundEngine | ||
110 | |||
111 | @implementation CDSoundEngine | ||
112 | |||
113 | static Float32 _mixerSampleRate; | ||
114 | static BOOL _mixerRateSet = NO; | ||
115 | |||
116 | @synthesize lastErrorCode = lastErrorCode_; | ||
117 | @synthesize functioning = functioning_; | ||
118 | @synthesize asynchLoadProgress = asynchLoadProgress_; | ||
119 | @synthesize getGainWorks = getGainWorks_; | ||
120 | @synthesize sourceTotal = sourceTotal_; | ||
121 | |||
122 | + (void) setMixerSampleRate:(Float32) sampleRate { | ||
123 | _mixerRateSet = YES; | ||
124 | _mixerSampleRate = sampleRate; | ||
125 | } | ||
126 | |||
127 | - (void) _testGetGain { | ||
128 | float testValue = 0.7f; | ||
129 | ALuint testSourceId = _sources[0].sourceId; | ||
130 | alSourcef(testSourceId, AL_GAIN, 0.0f);//Start from know value | ||
131 | alSourcef(testSourceId, AL_GAIN, testValue); | ||
132 | ALfloat gainVal; | ||
133 | alGetSourcef(testSourceId, AL_GAIN, &gainVal); | ||
134 | getGainWorks_ = (gainVal == testValue); | ||
135 | } | ||
136 | |||
137 | //Generate sources one at a time until we fail | ||
138 | -(void) _generateSources { | ||
139 | |||
140 | _sources = (sourceInfo*)malloc( sizeof(_sources[0]) * CD_SOURCE_LIMIT); | ||
141 | BOOL hasFailed = NO; | ||
142 | sourceTotal_ = 0; | ||
143 | alGetError();//Clear error | ||
144 | while (!hasFailed && sourceTotal_ < CD_SOURCE_LIMIT) { | ||
145 | alGenSources(1, &(_sources[sourceTotal_].sourceId)); | ||
146 | if (alGetError() == AL_NO_ERROR) { | ||
147 | //Now try attaching source to null buffer | ||
148 | alSourcei(_sources[sourceTotal_].sourceId, AL_BUFFER, 0); | ||
149 | if (alGetError() == AL_NO_ERROR) { | ||
150 | _sources[sourceTotal_].usable = true; | ||
151 | sourceTotal_++; | ||
152 | } else { | ||
153 | hasFailed = YES; | ||
154 | } | ||
155 | } else { | ||
156 | _sources[sourceTotal_].usable = false; | ||
157 | hasFailed = YES; | ||
158 | } | ||
159 | } | ||
160 | //Mark the rest of the sources as not usable | ||
161 | for (int i=sourceTotal_; i < CD_SOURCE_LIMIT; i++) { | ||
162 | _sources[i].usable = false; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | -(void) _generateBuffers:(int) startIndex endIndex:(int) endIndex { | ||
167 | if (_buffers) { | ||
168 | alGetError(); | ||
169 | for (int i=startIndex; i <= endIndex; i++) { | ||
170 | alGenBuffers(1, &_buffers[i].bufferId); | ||
171 | _buffers[i].bufferData = NULL; | ||
172 | if (alGetError() == AL_NO_ERROR) { | ||
173 | _buffers[i].bufferState = CD_BS_EMPTY; | ||
174 | } else { | ||
175 | _buffers[i].bufferState = CD_BS_FAILED; | ||
176 | CDLOG(@"Denshion::CDSoundEngine - buffer creation failed %i",i); | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * Internal method called during init | ||
184 | */ | ||
185 | - (BOOL) _initOpenAL | ||
186 | { | ||
187 | //ALenum error; | ||
188 | context = NULL; | ||
189 | ALCdevice *newDevice = NULL; | ||
190 | |||
191 | //Set the mixer rate for the audio mixer | ||
192 | if (!_mixerRateSet) { | ||
193 | _mixerSampleRate = CD_SAMPLE_RATE_DEFAULT; | ||
194 | } | ||
195 | alcMacOSXMixerOutputRateProc(_mixerSampleRate); | ||
196 | CDLOGINFO(@"Denshion::CDSoundEngine - mixer output rate set to %0.2f",_mixerSampleRate); | ||
197 | |||
198 | // Create a new OpenAL Device | ||
199 | // Pass NULL to specify the system's default output device | ||
200 | newDevice = alcOpenDevice(NULL); | ||
201 | if (newDevice != NULL) | ||
202 | { | ||
203 | // Create a new OpenAL Context | ||
204 | // The new context will render to the OpenAL Device just created | ||
205 | context = alcCreateContext(newDevice, 0); | ||
206 | if (context != NULL) | ||
207 | { | ||
208 | // Make the new context the Current OpenAL Context | ||
209 | alcMakeContextCurrent(context); | ||
210 | |||
211 | // Create some OpenAL Buffer Objects | ||
212 | [self _generateBuffers:0 endIndex:bufferTotal-1]; | ||
213 | |||
214 | // Create some OpenAL Source Objects | ||
215 | [self _generateSources]; | ||
216 | |||
217 | } | ||
218 | } else { | ||
219 | return FALSE;//No device | ||
220 | } | ||
221 | alGetError();//Clear error | ||
222 | return TRUE; | ||
223 | } | ||
224 | |||
225 | - (void) dealloc { | ||
226 | |||
227 | ALCcontext *currentContext = NULL; | ||
228 | ALCdevice *device = NULL; | ||
229 | |||
230 | [self stopAllSounds]; | ||
231 | |||
232 | CDLOGINFO(@"Denshion::CDSoundEngine - Deallocing sound engine."); | ||
233 | [self _freeSourceGroups]; | ||
234 | |||
235 | // Delete the Sources | ||
236 | CDLOGINFO(@"Denshion::CDSoundEngine - deleting sources."); | ||
237 | for (int i=0; i < sourceTotal_; i++) { | ||
238 | alSourcei(_sources[i].sourceId, AL_BUFFER, 0);//Detach from current buffer | ||
239 | alDeleteSources(1, &(_sources[i].sourceId)); | ||
240 | if((lastErrorCode_ = alGetError()) != AL_NO_ERROR) { | ||
241 | CDLOG(@"Denshion::CDSoundEngine - Error deleting source! %x\n", lastErrorCode_); | ||
242 | } | ||
243 | } | ||
244 | |||
245 | // Delete the Buffers | ||
246 | CDLOGINFO(@"Denshion::CDSoundEngine - deleting buffers."); | ||
247 | for (int i=0; i < bufferTotal; i++) { | ||
248 | alDeleteBuffers(1, &_buffers[i].bufferId); | ||
249 | #ifdef CD_USE_STATIC_BUFFERS | ||
250 | if (_buffers[i].bufferData) { | ||
251 | free(_buffers[i].bufferData); | ||
252 | } | ||
253 | #endif | ||
254 | } | ||
255 | CDLOGINFO(@"Denshion::CDSoundEngine - free buffers."); | ||
256 | free(_buffers); | ||
257 | currentContext = alcGetCurrentContext(); | ||
258 | //Get device for active context | ||
259 | device = alcGetContextsDevice(currentContext); | ||
260 | //Release context | ||
261 | CDLOGINFO(@"Denshion::CDSoundEngine - destroy context."); | ||
262 | alcDestroyContext(currentContext); | ||
263 | //Close device | ||
264 | CDLOGINFO(@"Denshion::CDSoundEngine - close device."); | ||
265 | alcCloseDevice(device); | ||
266 | CDLOGINFO(@"Denshion::CDSoundEngine - free sources."); | ||
267 | free(_sources); | ||
268 | |||
269 | //Release mutexes | ||
270 | [_mutexBufferLoad release]; | ||
271 | |||
272 | [super dealloc]; | ||
273 | } | ||
274 | |||
275 | -(NSUInteger) sourceGroupTotal { | ||
276 | return _sourceGroupTotal; | ||
277 | } | ||
278 | |||
279 | -(void) _freeSourceGroups | ||
280 | { | ||
281 | CDLOGINFO(@"Denshion::CDSoundEngine freeing source groups"); | ||
282 | if(_sourceGroups) { | ||
283 | for (int i=0; i < _sourceGroupTotal; i++) { | ||
284 | if (_sourceGroups[i].sourceStatuses) { | ||
285 | free(_sourceGroups[i].sourceStatuses); | ||
286 | CDLOGINFO(@"Denshion::CDSoundEngine freed source statuses %i",i); | ||
287 | } | ||
288 | } | ||
289 | free(_sourceGroups); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | -(BOOL) _redefineSourceGroups:(int[]) definitions total:(NSUInteger) total | ||
294 | { | ||
295 | if (_sourceGroups) { | ||
296 | //Stop all sounds | ||
297 | [self stopAllSounds]; | ||
298 | //Need to free source groups | ||
299 | [self _freeSourceGroups]; | ||
300 | } | ||
301 | return [self _setUpSourceGroups:definitions total:total]; | ||
302 | } | ||
303 | |||
304 | -(BOOL) _setUpSourceGroups:(int[]) definitions total:(NSUInteger) total | ||
305 | { | ||
306 | _sourceGroups = (sourceGroup *)malloc( sizeof(_sourceGroups[0]) * total); | ||
307 | if(!_sourceGroups) { | ||
308 | CDLOG(@"Denshion::CDSoundEngine - source groups memory allocation failed"); | ||
309 | return NO; | ||
310 | } | ||
311 | |||
312 | _sourceGroupTotal = total; | ||
313 | int sourceCount = 0; | ||
314 | for (int i=0; i < _sourceGroupTotal; i++) { | ||
315 | |||
316 | _sourceGroups[i].startIndex = 0; | ||
317 | _sourceGroups[i].currentIndex = _sourceGroups[i].startIndex; | ||
318 | _sourceGroups[i].enabled = false; | ||
319 | _sourceGroups[i].nonInterruptible = false; | ||
320 | _sourceGroups[i].totalSources = definitions[i]; | ||
321 | _sourceGroups[i].sourceStatuses = malloc(sizeof(_sourceGroups[i].sourceStatuses[0]) * _sourceGroups[i].totalSources); | ||
322 | if (_sourceGroups[i].sourceStatuses) { | ||
323 | for (int j=0; j < _sourceGroups[i].totalSources; j++) { | ||
324 | //First bit is used to indicate whether source is locked, index is shifted back 1 bit | ||
325 | _sourceGroups[i].sourceStatuses[j] = (sourceCount + j) << 1; | ||
326 | } | ||
327 | } | ||
328 | sourceCount += definitions[i]; | ||
329 | } | ||
330 | return YES; | ||
331 | } | ||
332 | |||
333 | -(void) defineSourceGroups:(int[]) sourceGroupDefinitions total:(NSUInteger) total { | ||
334 | [self _redefineSourceGroups:sourceGroupDefinitions total:total]; | ||
335 | } | ||
336 | |||
337 | -(void) defineSourceGroups:(NSArray*) sourceGroupDefinitions { | ||
338 | CDLOGINFO(@"Denshion::CDSoundEngine - source groups defined by NSArray."); | ||
339 | NSUInteger totalDefs = [sourceGroupDefinitions count]; | ||
340 | int* defs = (int *)malloc( sizeof(int) * totalDefs); | ||
341 | int currentIndex = 0; | ||
342 | for (id currentDef in sourceGroupDefinitions) { | ||
343 | if ([currentDef isKindOfClass:[NSNumber class]]) { | ||
344 | defs[currentIndex] = (int)[(NSNumber*)currentDef integerValue]; | ||
345 | CDLOGINFO(@"Denshion::CDSoundEngine - found definition %i.",defs[currentIndex]); | ||
346 | } else { | ||
347 | CDLOG(@"Denshion::CDSoundEngine - warning, did not understand source definition."); | ||
348 | defs[currentIndex] = 0; | ||
349 | } | ||
350 | currentIndex++; | ||
351 | } | ||
352 | [self _redefineSourceGroups:defs total:totalDefs]; | ||
353 | free(defs); | ||
354 | } | ||
355 | |||
356 | - (id)init | ||
357 | { | ||
358 | if ((self = [super init])) { | ||
359 | |||
360 | //Create mutexes | ||
361 | _mutexBufferLoad = [[NSObject alloc] init]; | ||
362 | |||
363 | asynchLoadProgress_ = 0.0f; | ||
364 | |||
365 | bufferTotal = CD_BUFFERS_START; | ||
366 | _buffers = (bufferInfo *)malloc( sizeof(_buffers[0]) * bufferTotal); | ||
367 | |||
368 | // Initialize our OpenAL environment | ||
369 | if ([self _initOpenAL]) { | ||
370 | //Set up the default source group - a single group that contains all the sources | ||
371 | int sourceDefs[1]; | ||
372 | sourceDefs[0] = self.sourceTotal; | ||
373 | [self _setUpSourceGroups:sourceDefs total:1]; | ||
374 | |||
375 | functioning_ = YES; | ||
376 | //Synchronize premute gain | ||
377 | _preMuteGain = self.masterGain; | ||
378 | mute_ = NO; | ||
379 | enabled_ = YES; | ||
380 | //Test whether get gain works for sources | ||
381 | [self _testGetGain]; | ||
382 | } else { | ||
383 | //Something went wrong with OpenAL | ||
384 | functioning_ = NO; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | return self; | ||
389 | } | ||
390 | |||
391 | /** | ||
392 | * Delete the buffer identified by soundId | ||
393 | * @return true if buffer deleted successfully, otherwise false | ||
394 | */ | ||
395 | - (BOOL) unloadBuffer:(int) soundId | ||
396 | { | ||
397 | //Ensure soundId is within array bounds otherwise memory corruption will occur | ||
398 | if (soundId < 0 || soundId >= bufferTotal) { | ||
399 | CDLOG(@"Denshion::CDSoundEngine - soundId is outside array bounds, maybe you need to increase CD_MAX_BUFFERS"); | ||
400 | return FALSE; | ||
401 | } | ||
402 | |||
403 | //Before a buffer can be deleted any sources that are attached to it must be stopped | ||
404 | for (int i=0; i < sourceTotal_; i++) { | ||
405 | //Note: tried getting the AL_BUFFER attribute of the source instead but doesn't | ||
406 | //appear to work on a device - just returned zero. | ||
407 | if (_buffers[soundId].bufferId == _sources[i].attachedBufferId) { | ||
408 | |||
409 | CDLOG(@"Denshion::CDSoundEngine - Found attached source %i %i %i",i,_buffers[soundId].bufferId,_sources[i].sourceId); | ||
410 | #ifdef CD_USE_STATIC_BUFFERS | ||
411 | //When using static buffers a crash may occur if a source is playing with a buffer that is about | ||
412 | //to be deleted even though we stop the source and successfully delete the buffer. Crash is confirmed | ||
413 | //on 2.2.1 and 3.1.2, however, it will only occur if a source is used rapidly after having its prior | ||
414 | //data deleted. To avoid any possibility of the crash we wait for the source to finish playing. | ||
415 | ALint state; | ||
416 | |||
417 | alGetSourcei(_sources[i].sourceId, AL_SOURCE_STATE, &state); | ||
418 | |||
419 | if (state == AL_PLAYING) { | ||
420 | CDLOG(@"Denshion::CDSoundEngine - waiting for source to complete playing before removing buffer data"); | ||
421 | alSourcei(_sources[i].sourceId, AL_LOOPING, FALSE);//Turn off looping otherwise loops will never end | ||
422 | while (state == AL_PLAYING) { | ||
423 | alGetSourcei(_sources[i].sourceId, AL_SOURCE_STATE, &state); | ||
424 | usleep(10000); | ||
425 | } | ||
426 | } | ||
427 | #endif | ||
428 | //Stop source and detach | ||
429 | alSourceStop(_sources[i].sourceId); | ||
430 | if((lastErrorCode_ = alGetError()) != AL_NO_ERROR) { | ||
431 | CDLOG(@"Denshion::CDSoundEngine - error stopping source: %x\n", lastErrorCode_); | ||
432 | } | ||
433 | |||
434 | alSourcei(_sources[i].sourceId, AL_BUFFER, 0);//Attach to "NULL" buffer to detach | ||
435 | if((lastErrorCode_ = alGetError()) != AL_NO_ERROR) { | ||
436 | CDLOG(@"Denshion::CDSoundEngine - error detaching buffer: %x\n", lastErrorCode_); | ||
437 | } else { | ||
438 | //Record that source is now attached to nothing | ||
439 | _sources[i].attachedBufferId = 0; | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | |||
444 | alDeleteBuffers(1, &_buffers[soundId].bufferId); | ||
445 | if((lastErrorCode_ = alGetError()) != AL_NO_ERROR) { | ||
446 | CDLOG(@"Denshion::CDSoundEngine - error deleting buffer: %x\n", lastErrorCode_); | ||
447 | _buffers[soundId].bufferState = CD_BS_FAILED; | ||
448 | return FALSE; | ||
449 | } else { | ||
450 | #ifdef CD_USE_STATIC_BUFFERS | ||
451 | //Free previous data, if alDeleteBuffer has returned without error then no | ||
452 | if (_buffers[soundId].bufferData) { | ||
453 | CDLOGINFO(@"Denshion::CDSoundEngine - freeing static data for soundId %i @ %i",soundId,_buffers[soundId].bufferData); | ||
454 | free(_buffers[soundId].bufferData);//Free the old data | ||
455 | _buffers[soundId].bufferData = NULL; | ||
456 | } | ||
457 | #endif | ||
458 | } | ||
459 | |||
460 | alGenBuffers(1, &_buffers[soundId].bufferId); | ||
461 | if((lastErrorCode_ = alGetError()) != AL_NO_ERROR) { | ||
462 | CDLOG(@"Denshion::CDSoundEngine - error regenerating buffer: %x\n", lastErrorCode_); | ||
463 | _buffers[soundId].bufferState = CD_BS_FAILED; | ||
464 | return FALSE; | ||
465 | } else { | ||
466 | //We now have an empty buffer | ||
467 | _buffers[soundId].bufferState = CD_BS_EMPTY; | ||
468 | CDLOGINFO(@"Denshion::CDSoundEngine - buffer %i successfully unloaded\n",soundId); | ||
469 | return TRUE; | ||
470 | } | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * Load buffers asynchronously | ||
475 | * Check asynchLoadProgress for progress. asynchLoadProgress represents fraction of completion. When it equals 1.0 loading | ||
476 | * is complete. NB: asynchLoadProgress is simply based on the number of load requests, it does not take into account | ||
477 | * file sizes. | ||
478 | * @param An array of CDBufferLoadRequest objects | ||
479 | */ | ||
480 | - (void) loadBuffersAsynchronously:(NSArray *) loadRequests { | ||
481 | @synchronized(self) { | ||
482 | asynchLoadProgress_ = 0.0f; | ||
483 | CDAsynchBufferLoader *loaderOp = [[[CDAsynchBufferLoader alloc] init:loadRequests soundEngine:self] autorelease]; | ||
484 | NSOperationQueue *opQ = [[[NSOperationQueue alloc] init] autorelease]; | ||
485 | [opQ addOperation:loaderOp]; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | -(BOOL) _resizeBuffers:(int) increment { | ||
490 | |||
491 | void * tmpBufferInfos = realloc( _buffers, sizeof(_buffers[0]) * (bufferTotal + increment) ); | ||
492 | |||
493 | if(!tmpBufferInfos) { | ||
494 | free(tmpBufferInfos); | ||
495 | return NO; | ||
496 | } else { | ||
497 | _buffers = tmpBufferInfos; | ||
498 | int oldBufferTotal = bufferTotal; | ||
499 | bufferTotal = bufferTotal + increment; | ||
500 | [self _generateBuffers:oldBufferTotal endIndex:bufferTotal-1]; | ||
501 | return YES; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | -(BOOL) loadBufferFromData:(int) soundId soundData:(ALvoid*) soundData format:(ALenum) format size:(ALsizei) size freq:(ALsizei) freq { | ||
506 | |||
507 | @synchronized(_mutexBufferLoad) { | ||
508 | |||
509 | if (!functioning_) { | ||
510 | //OpenAL initialisation has previously failed | ||
511 | CDLOG(@"Denshion::CDSoundEngine - Loading buffer failed because sound engine state != functioning"); | ||
512 | return FALSE; | ||
513 | } | ||
514 | |||
515 | //Ensure soundId is within array bounds otherwise memory corruption will occur | ||
516 | if (soundId < 0) { | ||
517 | CDLOG(@"Denshion::CDSoundEngine - soundId is negative"); | ||
518 | return FALSE; | ||
519 | } | ||
520 | |||
521 | if (soundId >= bufferTotal) { | ||
522 | //Need to resize the buffers | ||
523 | int requiredIncrement = CD_BUFFERS_INCREMENT; | ||
524 | while (bufferTotal + requiredIncrement < soundId) { | ||
525 | requiredIncrement += CD_BUFFERS_INCREMENT; | ||
526 | } | ||
527 | CDLOGINFO(@"Denshion::CDSoundEngine - attempting to resize buffers by %i for sound %i",requiredIncrement,soundId); | ||
528 | if (![self _resizeBuffers:requiredIncrement]) { | ||
529 | CDLOG(@"Denshion::CDSoundEngine - buffer resize failed"); | ||
530 | return FALSE; | ||
531 | } | ||
532 | } | ||
533 | |||
534 | if (soundData) | ||
535 | { | ||
536 | if (_buffers[soundId].bufferState != CD_BS_EMPTY) { | ||
537 | CDLOGINFO(@"Denshion::CDSoundEngine - non empty buffer, regenerating"); | ||
538 | if (![self unloadBuffer:soundId]) { | ||
539 | //Deletion of buffer failed, delete buffer routine has set buffer state and lastErrorCode | ||
540 | return NO; | ||
541 | } | ||
542 | } | ||
543 | |||
544 | #ifdef CD_DEBUG | ||
545 | //Check that sample rate matches mixer rate and warn if they do not | ||
546 | if (freq != (int)_mixerSampleRate) { | ||
547 | CDLOGINFO(@"Denshion::CDSoundEngine - WARNING sample rate does not match mixer sample rate performance may not be optimal."); | ||
548 | } | ||
549 | #endif | ||
550 | |||
551 | #ifdef CD_USE_STATIC_BUFFERS | ||
552 | alBufferDataStaticProc(_buffers[soundId].bufferId, format, soundData, size, freq); | ||
553 | _buffers[soundId].bufferData = data;//Save the pointer to the new data | ||
554 | #else | ||
555 | alBufferData(_buffers[soundId].bufferId, format, soundData, size, freq); | ||
556 | #endif | ||
557 | if((lastErrorCode_ = alGetError()) != AL_NO_ERROR) { | ||
558 | CDLOG(@"Denshion::CDSoundEngine - error attaching audio to buffer: %x", lastErrorCode_); | ||
559 | _buffers[soundId].bufferState = CD_BS_FAILED; | ||
560 | return FALSE; | ||
561 | } | ||
562 | } else { | ||
563 | CDLOG(@"Denshion::CDSoundEngine Buffer data is null!"); | ||
564 | _buffers[soundId].bufferState = CD_BS_FAILED; | ||
565 | return FALSE; | ||
566 | } | ||
567 | |||
568 | _buffers[soundId].format = format; | ||
569 | _buffers[soundId].sizeInBytes = size; | ||
570 | _buffers[soundId].frequencyInHertz = freq; | ||
571 | _buffers[soundId].bufferState = CD_BS_LOADED; | ||
572 | CDLOGINFO(@"Denshion::CDSoundEngine Buffer %i loaded format:%i freq:%i size:%i",soundId,format,freq,size); | ||
573 | return TRUE; | ||
574 | }//end mutex | ||
575 | } | ||
576 | |||
577 | /** | ||
578 | * Load sound data for later play back. | ||
579 | * @return TRUE if buffer loaded okay for play back otherwise false | ||
580 | */ | ||
581 | - (BOOL) loadBuffer:(int) soundId filePath:(NSString*) filePath | ||
582 | { | ||
583 | |||
584 | ALvoid* data; | ||
585 | ALenum format; | ||
586 | ALsizei size; | ||
587 | ALsizei freq; | ||
588 | |||
589 | CDLOGINFO(@"Denshion::CDSoundEngine - Loading openAL buffer %i %@", soundId, filePath); | ||
590 | |||
591 | CFURLRef fileURL = nil; | ||
592 | NSString *path = [CDUtilities fullPathFromRelativePath:filePath]; | ||
593 | if (path) { | ||
594 | fileURL = (CFURLRef)[[NSURL fileURLWithPath:path] retain]; | ||
595 | } | ||
596 | |||
597 | if (fileURL) | ||
598 | { | ||
599 | data = CDGetOpenALAudioData(fileURL, &size, &format, &freq); | ||
600 | CFRelease(fileURL); | ||
601 | BOOL result = [self loadBufferFromData:soundId soundData:data format:format size:size freq:freq]; | ||
602 | #ifndef CD_USE_STATIC_BUFFERS | ||
603 | free(data);//Data can be freed here because alBufferData performs a memcpy | ||
604 | #endif | ||
605 | return result; | ||
606 | } else { | ||
607 | CDLOG(@"Denshion::CDSoundEngine Could not find file!\n"); | ||
608 | //Don't change buffer state here as it will be the same as before method was called | ||
609 | return FALSE; | ||
610 | } | ||
611 | } | ||
612 | |||
613 | -(BOOL) validateBufferId:(int) soundId { | ||
614 | if (soundId < 0 || soundId >= bufferTotal) { | ||
615 | CDLOGINFO(@"Denshion::CDSoundEngine - validateBufferId buffer outside range %i",soundId); | ||
616 | return NO; | ||
617 | } else if (_buffers[soundId].bufferState != CD_BS_LOADED) { | ||
618 | CDLOGINFO(@"Denshion::CDSoundEngine - validateBufferId invalide buffer state %i",soundId); | ||
619 | return NO; | ||
620 | } else { | ||
621 | return YES; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | -(float) bufferDurationInSeconds:(int) soundId { | ||
626 | if ([self validateBufferId:soundId]) { | ||
627 | float factor = 0.0f; | ||
628 | switch (_buffers[soundId].format) { | ||
629 | case AL_FORMAT_MONO8: | ||
630 | factor = 1.0f; | ||
631 | break; | ||
632 | case AL_FORMAT_MONO16: | ||
633 | factor = 0.5f; | ||
634 | break; | ||
635 | case AL_FORMAT_STEREO8: | ||
636 | factor = 0.5f; | ||
637 | break; | ||
638 | case AL_FORMAT_STEREO16: | ||
639 | factor = 0.25f; | ||
640 | break; | ||
641 | } | ||
642 | return (float)_buffers[soundId].sizeInBytes/(float)_buffers[soundId].frequencyInHertz * factor; | ||
643 | } else { | ||
644 | return -1.0f; | ||
645 | } | ||
646 | } | ||
647 | |||
648 | -(ALsizei) bufferSizeInBytes:(int) soundId { | ||
649 | if ([self validateBufferId:soundId]) { | ||
650 | return _buffers[soundId].sizeInBytes; | ||
651 | } else { | ||
652 | return -1.0f; | ||
653 | } | ||
654 | } | ||
655 | |||
656 | -(ALsizei) bufferFrequencyInHertz:(int) soundId { | ||
657 | if ([self validateBufferId:soundId]) { | ||
658 | return _buffers[soundId].frequencyInHertz; | ||
659 | } else { | ||
660 | return -1.0f; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | - (ALfloat) masterGain { | ||
665 | if (mute_) { | ||
666 | //When mute the real gain will always be 0 therefore return the preMuteGain value | ||
667 | return _preMuteGain; | ||
668 | } else { | ||
669 | ALfloat gain; | ||
670 | alGetListenerf(AL_GAIN, &gain); | ||
671 | return gain; | ||
672 | } | ||
673 | } | ||
674 | |||
675 | /** | ||
676 | * Overall gain setting multiplier. e.g 0.5 is half the gain. | ||
677 | */ | ||
678 | - (void) setMasterGain:(ALfloat) newGainValue { | ||
679 | if (mute_) { | ||
680 | _preMuteGain = newGainValue; | ||
681 | } else { | ||
682 | alListenerf(AL_GAIN, newGainValue); | ||
683 | } | ||
684 | } | ||
685 | |||
686 | #pragma mark CDSoundEngine AudioInterrupt protocol | ||
687 | - (BOOL) mute { | ||
688 | return mute_; | ||
689 | } | ||
690 | |||
691 | /** | ||
692 | * Setting mute silences all sounds but playing sounds continue to advance playback | ||
693 | */ | ||
694 | - (void) setMute:(BOOL) newMuteValue { | ||
695 | |||
696 | if (newMuteValue == mute_) { | ||
697 | return; | ||
698 | } | ||
699 | |||
700 | mute_ = newMuteValue; | ||
701 | if (mute_) { | ||
702 | //Remember what the gain was | ||
703 | _preMuteGain = self.masterGain; | ||
704 | //Set gain to 0 - do not use the property as this will adjust preMuteGain when muted | ||
705 | alListenerf(AL_GAIN, 0.0f); | ||
706 | } else { | ||
707 | //Restore gain to what it was before being muted | ||
708 | self.masterGain = _preMuteGain; | ||
709 | } | ||
710 | } | ||
711 | |||
712 | - (BOOL) enabled { | ||
713 | return enabled_; | ||
714 | } | ||
715 | |||
716 | - (void) setEnabled:(BOOL)enabledValue | ||
717 | { | ||
718 | if (enabled_ == enabledValue) { | ||
719 | return; | ||
720 | } | ||
721 | enabled_ = enabledValue; | ||
722 | if (enabled_ == NO) { | ||
723 | [self stopAllSounds]; | ||
724 | } | ||
725 | } | ||
726 | |||
727 | -(void) _lockSource:(int) sourceIndex lock:(BOOL) lock { | ||
728 | BOOL found = NO; | ||
729 | for (int i=0; i < _sourceGroupTotal && !found; i++) { | ||
730 | if (_sourceGroups[i].sourceStatuses) { | ||
731 | for (int j=0; j < _sourceGroups[i].totalSources && !found; j++) { | ||
732 | //First bit is used to indicate whether source is locked, index is shifted back 1 bit | ||
733 | if((_sourceGroups[i].sourceStatuses[j] >> 1)==sourceIndex) { | ||
734 | if (lock) { | ||
735 | //Set first bit to lock this source | ||
736 | _sourceGroups[i].sourceStatuses[j] |= 1; | ||
737 | } else { | ||
738 | //Unset first bit to unlock this source | ||
739 | _sourceGroups[i].sourceStatuses[j] &= ~1; | ||
740 | } | ||
741 | found = YES; | ||
742 | } | ||
743 | } | ||
744 | } | ||
745 | } | ||
746 | } | ||
747 | |||
748 | -(int) _getSourceIndexForSourceGroup:(int)sourceGroupId | ||
749 | { | ||
750 | //Ensure source group id is valid to prevent memory corruption | ||
751 | if (sourceGroupId < 0 || sourceGroupId >= _sourceGroupTotal) { | ||
752 | CDLOG(@"Denshion::CDSoundEngine invalid source group id %i",sourceGroupId); | ||
753 | return CD_NO_SOURCE; | ||
754 | } | ||
755 | |||
756 | int sourceIndex = -1;//Using -1 to indicate no source found | ||
757 | BOOL complete = NO; | ||
758 | ALint sourceState = 0; | ||
759 | sourceGroup *thisSourceGroup = &_sourceGroups[sourceGroupId]; | ||
760 | thisSourceGroup->currentIndex = thisSourceGroup->startIndex; | ||
761 | while (!complete) { | ||
762 | //Iterate over sources looking for one that is not locked, first bit indicates if source is locked | ||
763 | if ((thisSourceGroup->sourceStatuses[thisSourceGroup->currentIndex] & 1) == 0) { | ||
764 | //This source is not locked | ||
765 | sourceIndex = thisSourceGroup->sourceStatuses[thisSourceGroup->currentIndex] >> 1;//shift back to get the index | ||
766 | if (thisSourceGroup->nonInterruptible) { | ||
767 | //Check if this source is playing, if so it can't be interrupted | ||
768 | alGetSourcei(_sources[sourceIndex].sourceId, AL_SOURCE_STATE, &sourceState); | ||
769 | if (sourceState != AL_PLAYING) { | ||
770 | //complete = YES; | ||
771 | //Set start index so next search starts at the next position | ||
772 | thisSourceGroup->startIndex = thisSourceGroup->currentIndex + 1; | ||
773 | break; | ||
774 | } else { | ||
775 | sourceIndex = -1;//The source index was no good because the source was playing | ||
776 | } | ||
777 | } else { | ||
778 | //complete = YES; | ||
779 | //Set start index so next search starts at the next position | ||
780 | thisSourceGroup->startIndex = thisSourceGroup->currentIndex + 1; | ||
781 | break; | ||
782 | } | ||
783 | } | ||
784 | thisSourceGroup->currentIndex++; | ||
785 | if (thisSourceGroup->currentIndex >= thisSourceGroup->totalSources) { | ||
786 | //Reset to the beginning | ||
787 | thisSourceGroup->currentIndex = 0; | ||
788 | } | ||
789 | if (thisSourceGroup->currentIndex == thisSourceGroup->startIndex) { | ||
790 | //We have looped around and got back to the start | ||
791 | complete = YES; | ||
792 | } | ||
793 | } | ||
794 | |||
795 | //Reset start index to beginning if beyond bounds | ||
796 | if (thisSourceGroup->startIndex >= thisSourceGroup->totalSources) { | ||
797 | thisSourceGroup->startIndex = 0; | ||
798 | } | ||
799 | |||
800 | if (sourceIndex >= 0) { | ||
801 | return sourceIndex; | ||
802 | } else { | ||
803 | return CD_NO_SOURCE; | ||
804 | } | ||
805 | |||
806 | } | ||
807 | |||
808 | /** | ||
809 | * Play a sound. | ||
810 | * @param soundId the id of the sound to play (buffer id). | ||
811 | * @param SourceGroupId the source group that will be used to play the sound. | ||
812 | * @param pitch pitch multiplier. e.g 1.0 is unaltered, 0.5 is 1 octave lower. | ||
813 | * @param pan stereo position. -1 is fully left, 0 is centre and 1 is fully right. | ||
814 | * @param gain gain multiplier. e.g. 1.0 is unaltered, 0.5 is half the gain | ||
815 | * @param loop should the sound be looped or one shot. | ||
816 | * @return the id of the source being used to play the sound or CD_MUTE if the sound engine is muted or non functioning | ||
817 | * or CD_NO_SOURCE if a problem occurs setting up the source | ||
818 | * | ||
819 | */ | ||
820 | - (ALuint)playSound:(int) soundId sourceGroupId:(int)sourceGroupId pitch:(float) pitch pan:(float) pan gain:(float) gain loop:(BOOL) loop { | ||
821 | |||
822 | #ifdef CD_DEBUG | ||
823 | //Sanity check parameters - only in DEBUG | ||
824 | NSAssert(soundId >= 0, @"soundId can not be negative"); | ||
825 | NSAssert(soundId < bufferTotal, @"soundId exceeds limit"); | ||
826 | NSAssert(sourceGroupId >= 0, @"sourceGroupId can not be negative"); | ||
827 | NSAssert(sourceGroupId < _sourceGroupTotal, @"sourceGroupId exceeds limit"); | ||
828 | NSAssert(pitch > 0, @"pitch must be greater than zero"); | ||
829 | NSAssert(pan >= -1 && pan <= 1, @"pan must be between -1 and 1"); | ||
830 | NSAssert(gain >= 0, @"gain can not be negative"); | ||
831 | #endif | ||
832 | //If mute or initialisation has failed or buffer is not loaded then do nothing | ||
833 | if (!enabled_ || !functioning_ || _buffers[soundId].bufferState != CD_BS_LOADED || _sourceGroups[sourceGroupId].enabled) { | ||
834 | #ifdef CD_DEBUG | ||
835 | if (!functioning_) { | ||
836 | CDLOGINFO(@"Denshion::CDSoundEngine - sound playback aborted because sound engine is not functioning"); | ||
837 | } else if (_buffers[soundId].bufferState != CD_BS_LOADED) { | ||
838 | CDLOGINFO(@"Denshion::CDSoundEngine - sound playback aborted because buffer %i is not loaded", soundId); | ||
839 | } | ||
840 | #endif | ||
841 | return CD_MUTE; | ||
842 | } | ||
843 | |||
844 | int sourceIndex = [self _getSourceIndexForSourceGroup:sourceGroupId];//This method ensures sourceIndex is valid | ||
845 | |||
846 | if (sourceIndex != CD_NO_SOURCE) { | ||
847 | ALint state; | ||
848 | ALuint source = _sources[sourceIndex].sourceId; | ||
849 | ALuint buffer = _buffers[soundId].bufferId; | ||
850 | alGetError();//Clear the error code | ||
851 | alGetSourcei(source, AL_SOURCE_STATE, &state); | ||
852 | if (state == AL_PLAYING) { | ||
853 | alSourceStop(source); | ||
854 | } | ||
855 | alSourcei(source, AL_BUFFER, buffer);//Attach to sound | ||
856 | alSourcef(source, AL_PITCH, pitch);//Set pitch | ||
857 | alSourcei(source, AL_LOOPING, loop);//Set looping | ||
858 | alSourcef(source, AL_GAIN, gain);//Set gain/volume | ||
859 | float sourcePosAL[] = {pan, 0.0f, 0.0f};//Set position - just using left and right panning | ||
860 | alSourcefv(source, AL_POSITION, sourcePosAL); | ||
861 | alGetError();//Clear the error code | ||
862 | alSourcePlay(source); | ||
863 | if((lastErrorCode_ = alGetError()) == AL_NO_ERROR) { | ||
864 | //Everything was okay | ||
865 | _sources[sourceIndex].attachedBufferId = buffer; | ||
866 | return source; | ||
867 | } else { | ||
868 | if (alcGetCurrentContext() == NULL) { | ||
869 | CDLOGINFO(@"Denshion::CDSoundEngine - posting bad OpenAL context message"); | ||
870 | [[NSNotificationCenter defaultCenter] postNotificationName:kCDN_BadAlContext object:nil]; | ||
871 | } | ||
872 | return CD_NO_SOURCE; | ||
873 | } | ||
874 | } else { | ||
875 | return CD_NO_SOURCE; | ||
876 | } | ||
877 | } | ||
878 | |||
879 | -(BOOL) _soundSourceAttachToBuffer:(CDSoundSource*) soundSource soundId:(int) soundId { | ||
880 | //Attach the source to the buffer | ||
881 | ALint state; | ||
882 | ALuint source = soundSource->_sourceId; | ||
883 | ALuint buffer = _buffers[soundId].bufferId; | ||
884 | alGetSourcei(source, AL_SOURCE_STATE, &state); | ||
885 | if (state == AL_PLAYING) { | ||
886 | alSourceStop(source); | ||
887 | } | ||
888 | alGetError();//Clear the error code | ||
889 | alSourcei(source, AL_BUFFER, buffer);//Attach to sound data | ||
890 | if((lastErrorCode_ = alGetError()) == AL_NO_ERROR) { | ||
891 | _sources[soundSource->_sourceIndex].attachedBufferId = buffer; | ||
892 | //_sourceBufferAttachments[soundSource->_sourceIndex] = buffer;//Keep track of which | ||
893 | soundSource->_soundId = soundId; | ||
894 | return YES; | ||
895 | } else { | ||
896 | return NO; | ||
897 | } | ||
898 | } | ||
899 | |||
900 | /** | ||
901 | * Get a sound source for the specified sound in the specified source group | ||
902 | */ | ||
903 | -(CDSoundSource *) soundSourceForSound:(int) soundId sourceGroupId:(int) sourceGroupId | ||
904 | { | ||
905 | if (!functioning_) { | ||
906 | return nil; | ||
907 | } | ||
908 | //Check if a source is available | ||
909 | int sourceIndex = [self _getSourceIndexForSourceGroup:sourceGroupId]; | ||
910 | if (sourceIndex != CD_NO_SOURCE) { | ||
911 | CDSoundSource *result = [[CDSoundSource alloc] init:_sources[sourceIndex].sourceId sourceIndex:sourceIndex soundEngine:self]; | ||
912 | [self _lockSource:sourceIndex lock:YES]; | ||
913 | //Try to attach to the buffer | ||
914 | if ([self _soundSourceAttachToBuffer:result soundId:soundId]) { | ||
915 | //Set to a known state | ||
916 | result.pitch = 1.0f; | ||
917 | result.pan = 0.0f; | ||
918 | result.gain = 1.0f; | ||
919 | result.looping = NO; | ||
920 | return [result autorelease]; | ||
921 | } else { | ||
922 | //Release the sound source we just created, this will also unlock the source | ||
923 | [result release]; | ||
924 | return nil; | ||
925 | } | ||
926 | } else { | ||
927 | //No available source within that source group | ||
928 | return nil; | ||
929 | } | ||
930 | } | ||
931 | |||
932 | -(void) _soundSourcePreRelease:(CDSoundSource *) soundSource { | ||
933 | CDLOGINFO(@"Denshion::CDSoundEngine _soundSourcePreRelease %i",soundSource->_sourceIndex); | ||
934 | //Unlock the sound source's source | ||
935 | [self _lockSource:soundSource->_sourceIndex lock:NO]; | ||
936 | } | ||
937 | |||
938 | /** | ||
939 | * Stop all sounds playing within a source group | ||
940 | */ | ||
941 | - (void) stopSourceGroup:(int) sourceGroupId { | ||
942 | |||
943 | if (!functioning_ || sourceGroupId >= _sourceGroupTotal || sourceGroupId < 0) { | ||
944 | return; | ||
945 | } | ||
946 | int sourceCount = _sourceGroups[sourceGroupId].totalSources; | ||
947 | for (int i=0; i < sourceCount; i++) { | ||
948 | int sourceIndex = _sourceGroups[sourceGroupId].sourceStatuses[i] >> 1; | ||
949 | alSourceStop(_sources[sourceIndex].sourceId); | ||
950 | } | ||
951 | alGetError();//Clear error in case we stopped any sounds that couldn't be stopped | ||
952 | } | ||
953 | |||
954 | /** | ||
955 | * Stop a sound playing. | ||
956 | * @param sourceId an OpenAL source identifier i.e. the return value of playSound | ||
957 | */ | ||
958 | - (void)stopSound:(ALuint) sourceId { | ||
959 | if (!functioning_) { | ||
960 | return; | ||
961 | } | ||
962 | alSourceStop(sourceId); | ||
963 | alGetError();//Clear error in case we stopped any sounds that couldn't be stopped | ||
964 | } | ||
965 | |||
966 | - (void) stopAllSounds { | ||
967 | for (int i=0; i < sourceTotal_; i++) { | ||
968 | alSourceStop(_sources[i].sourceId); | ||
969 | } | ||
970 | alGetError();//Clear error in case we stopped any sounds that couldn't be stopped | ||
971 | } | ||
972 | |||
973 | /** | ||
974 | * Set a source group as non interruptible. Default is that source groups are interruptible. | ||
975 | * Non interruptible means that if a request to play a sound is made for a source group and there are | ||
976 | * no free sources available then the play request will be ignored and CD_NO_SOURCE will be returned. | ||
977 | */ | ||
978 | - (void) setSourceGroupNonInterruptible:(int) sourceGroupId isNonInterruptible:(BOOL) isNonInterruptible { | ||
979 | //Ensure source group id is valid to prevent memory corruption | ||
980 | if (sourceGroupId < 0 || sourceGroupId >= _sourceGroupTotal) { | ||
981 | CDLOG(@"Denshion::CDSoundEngine setSourceGroupNonInterruptible invalid source group id %i",sourceGroupId); | ||
982 | return; | ||
983 | } | ||
984 | |||
985 | if (isNonInterruptible) { | ||
986 | _sourceGroups[sourceGroupId].nonInterruptible = true; | ||
987 | } else { | ||
988 | _sourceGroups[sourceGroupId].nonInterruptible = false; | ||
989 | } | ||
990 | } | ||
991 | |||
992 | /** | ||
993 | * Set the mute property for a source group. If mute is turned on any sounds in that source group | ||
994 | * will be stopped and further sounds in that source group will play. However, turning mute off | ||
995 | * will not restart any sounds that were playing when mute was turned on. Also the mute setting | ||
996 | * for the sound engine must be taken into account. If the sound engine is mute no sounds will play | ||
997 | * no matter what the source group mute setting is. | ||
998 | */ | ||
999 | - (void) setSourceGroupEnabled:(int) sourceGroupId enabled:(BOOL) enabled { | ||
1000 | //Ensure source group id is valid to prevent memory corruption | ||
1001 | if (sourceGroupId < 0 || sourceGroupId >= _sourceGroupTotal) { | ||
1002 | CDLOG(@"Denshion::CDSoundEngine setSourceGroupEnabled invalid source group id %i",sourceGroupId); | ||
1003 | return; | ||
1004 | } | ||
1005 | |||
1006 | if (enabled) { | ||
1007 | _sourceGroups[sourceGroupId].enabled = true; | ||
1008 | [self stopSourceGroup:sourceGroupId]; | ||
1009 | } else { | ||
1010 | _sourceGroups[sourceGroupId].enabled = false; | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | /** | ||
1015 | * Return the mute property for the source group identified by sourceGroupId | ||
1016 | */ | ||
1017 | - (BOOL) sourceGroupEnabled:(int) sourceGroupId { | ||
1018 | return _sourceGroups[sourceGroupId].enabled; | ||
1019 | } | ||
1020 | |||
1021 | -(ALCcontext *) openALContext { | ||
1022 | return context; | ||
1023 | } | ||
1024 | |||
1025 | - (void) _dumpSourceGroupsInfo { | ||
1026 | #ifdef CD_DEBUG | ||
1027 | CDLOGINFO(@"-------------- source Group Info --------------"); | ||
1028 | for (int i=0; i < _sourceGroupTotal; i++) { | ||
1029 | CDLOGINFO(@"Group: %i start:%i total:%i",i,_sourceGroups[i].startIndex, _sourceGroups[i].totalSources); | ||
1030 | CDLOGINFO(@"----- mute:%i nonInterruptible:%i",_sourceGroups[i].enabled, _sourceGroups[i].nonInterruptible); | ||
1031 | CDLOGINFO(@"----- Source statuses ----"); | ||
1032 | for (int j=0; j < _sourceGroups[i].totalSources; j++) { | ||
1033 | CDLOGINFO(@"Source status:%i index=%i locked=%i",j,_sourceGroups[i].sourceStatuses[j] >> 1, _sourceGroups[i].sourceStatuses[j] & 1); | ||
1034 | } | ||
1035 | } | ||
1036 | #endif | ||
1037 | } | ||
1038 | |||
1039 | @end | ||
1040 | |||
1041 | /////////////////////////////////////////////////////////////////////////////////////// | ||
1042 | @implementation CDSoundSource | ||
1043 | |||
1044 | @synthesize lastError; | ||
1045 | |||
1046 | //Macro for handling the al error code | ||
1047 | #define CDSOUNDSOURCE_UPDATE_LAST_ERROR (lastError = alGetError()) | ||
1048 | #define CDSOUNDSOURCE_ERROR_HANDLER ( CDSOUNDSOURCE_UPDATE_LAST_ERROR == AL_NO_ERROR) | ||
1049 | |||
1050 | -(id)init:(ALuint) theSourceId sourceIndex:(int) index soundEngine:(CDSoundEngine*) engine { | ||
1051 | if ((self = [super init])) { | ||
1052 | _sourceId = theSourceId; | ||
1053 | _engine = engine; | ||
1054 | _sourceIndex = index; | ||
1055 | enabled_ = YES; | ||
1056 | mute_ = NO; | ||
1057 | _preMuteGain = self.gain; | ||
1058 | } | ||
1059 | return self; | ||
1060 | } | ||
1061 | |||
1062 | -(void) dealloc | ||
1063 | { | ||
1064 | CDLOGINFO(@"Denshion::CDSoundSource deallocated %i",self->_sourceIndex); | ||
1065 | |||
1066 | //Notify sound engine we are about to release | ||
1067 | [_engine _soundSourcePreRelease:self]; | ||
1068 | [super dealloc]; | ||
1069 | } | ||
1070 | |||
1071 | - (void) setPitch:(float) newPitchValue { | ||
1072 | alSourcef(_sourceId, AL_PITCH, newPitchValue); | ||
1073 | CDSOUNDSOURCE_UPDATE_LAST_ERROR; | ||
1074 | } | ||
1075 | |||
1076 | - (void) setGain:(float) newGainValue { | ||
1077 | if (!mute_) { | ||
1078 | alSourcef(_sourceId, AL_GAIN, newGainValue); | ||
1079 | } else { | ||
1080 | _preMuteGain = newGainValue; | ||
1081 | } | ||
1082 | CDSOUNDSOURCE_UPDATE_LAST_ERROR; | ||
1083 | } | ||
1084 | |||
1085 | - (void) setPan:(float) newPanValue { | ||
1086 | float sourcePosAL[] = {newPanValue, 0.0f, 0.0f};//Set position - just using left and right panning | ||
1087 | alSourcefv(_sourceId, AL_POSITION, sourcePosAL); | ||
1088 | CDSOUNDSOURCE_UPDATE_LAST_ERROR; | ||
1089 | |||
1090 | } | ||
1091 | |||
1092 | - (void) setLooping:(BOOL) newLoopingValue { | ||
1093 | alSourcei(_sourceId, AL_LOOPING, newLoopingValue); | ||
1094 | CDSOUNDSOURCE_UPDATE_LAST_ERROR; | ||
1095 | |||
1096 | } | ||
1097 | |||
1098 | - (BOOL) isPlaying { | ||
1099 | ALint state; | ||
1100 | alGetSourcei(_sourceId, AL_SOURCE_STATE, &state); | ||
1101 | CDSOUNDSOURCE_UPDATE_LAST_ERROR; | ||
1102 | return (state == AL_PLAYING); | ||
1103 | } | ||
1104 | |||
1105 | - (float) pitch { | ||
1106 | ALfloat pitchVal; | ||
1107 | alGetSourcef(_sourceId, AL_PITCH, &pitchVal); | ||
1108 | CDSOUNDSOURCE_UPDATE_LAST_ERROR; | ||
1109 | return pitchVal; | ||
1110 | } | ||
1111 | |||
1112 | - (float) pan { | ||
1113 | ALfloat sourcePosAL[] = {0.0f,0.0f,0.0f}; | ||
1114 | alGetSourcefv(_sourceId, AL_POSITION, sourcePosAL); | ||
1115 | CDSOUNDSOURCE_UPDATE_LAST_ERROR; | ||
1116 | return sourcePosAL[0]; | ||
1117 | } | ||
1118 | |||
1119 | - (float) gain { | ||
1120 | if (!mute_) { | ||
1121 | ALfloat val; | ||
1122 | alGetSourcef(_sourceId, AL_GAIN, &val); | ||
1123 | CDSOUNDSOURCE_UPDATE_LAST_ERROR; | ||
1124 | return val; | ||
1125 | } else { | ||
1126 | return _preMuteGain; | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | - (BOOL) looping { | ||
1131 | ALfloat val; | ||
1132 | alGetSourcef(_sourceId, AL_LOOPING, &val); | ||
1133 | CDSOUNDSOURCE_UPDATE_LAST_ERROR; | ||
1134 | return val; | ||
1135 | } | ||
1136 | |||
1137 | -(BOOL) stop { | ||
1138 | alSourceStop(_sourceId); | ||
1139 | return CDSOUNDSOURCE_ERROR_HANDLER; | ||
1140 | } | ||
1141 | |||
1142 | -(BOOL) play { | ||
1143 | if (enabled_) { | ||
1144 | alSourcePlay(_sourceId); | ||
1145 | CDSOUNDSOURCE_UPDATE_LAST_ERROR; | ||
1146 | if (lastError != AL_NO_ERROR) { | ||
1147 | if (alcGetCurrentContext() == NULL) { | ||
1148 | CDLOGINFO(@"Denshion::CDSoundSource - posting bad OpenAL context message"); | ||
1149 | [[NSNotificationCenter defaultCenter] postNotificationName:kCDN_BadAlContext object:nil]; | ||
1150 | } | ||
1151 | return NO; | ||
1152 | } else { | ||
1153 | return YES; | ||
1154 | } | ||
1155 | } else { | ||
1156 | return NO; | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | -(BOOL) pause { | ||
1161 | alSourcePause(_sourceId); | ||
1162 | return CDSOUNDSOURCE_ERROR_HANDLER; | ||
1163 | } | ||
1164 | |||
1165 | -(BOOL) rewind { | ||
1166 | alSourceRewind(_sourceId); | ||
1167 | return CDSOUNDSOURCE_ERROR_HANDLER; | ||
1168 | } | ||
1169 | |||
1170 | -(void) setSoundId:(int) soundId { | ||
1171 | [_engine _soundSourceAttachToBuffer:self soundId:soundId]; | ||
1172 | } | ||
1173 | |||
1174 | -(int) soundId { | ||
1175 | return _soundId; | ||
1176 | } | ||
1177 | |||
1178 | -(float) durationInSeconds { | ||
1179 | return [_engine bufferDurationInSeconds:_soundId]; | ||
1180 | } | ||
1181 | |||
1182 | #pragma mark CDSoundSource AudioInterrupt protocol | ||
1183 | - (BOOL) mute { | ||
1184 | return mute_; | ||
1185 | } | ||
1186 | |||
1187 | /** | ||
1188 | * Setting mute silences all sounds but playing sounds continue to advance playback | ||
1189 | */ | ||
1190 | - (void) setMute:(BOOL) newMuteValue { | ||
1191 | |||
1192 | if (newMuteValue == mute_) { | ||
1193 | return; | ||
1194 | } | ||
1195 | |||
1196 | if (newMuteValue) { | ||
1197 | //Remember what the gain was | ||
1198 | _preMuteGain = self.gain; | ||
1199 | self.gain = 0.0f; | ||
1200 | mute_ = newMuteValue;//Make sure this is done after setting the gain property as the setter behaves differently depending on mute value | ||
1201 | } else { | ||
1202 | //Restore gain to what it was before being muted | ||
1203 | mute_ = newMuteValue; | ||
1204 | self.gain = _preMuteGain; | ||
1205 | } | ||
1206 | } | ||
1207 | |||
1208 | - (BOOL) enabled { | ||
1209 | return enabled_; | ||
1210 | } | ||
1211 | |||
1212 | - (void) setEnabled:(BOOL)enabledValue | ||
1213 | { | ||
1214 | if (enabled_ == enabledValue) { | ||
1215 | return; | ||
1216 | } | ||
1217 | enabled_ = enabledValue; | ||
1218 | if (enabled_ == NO) { | ||
1219 | [self stop]; | ||
1220 | } | ||
1221 | } | ||
1222 | |||
1223 | @end | ||
1224 | |||
1225 | //////////////////////////////////////////////////////////////////////////// | ||
1226 | #pragma mark - | ||
1227 | #pragma mark CDAudioInterruptTargetGroup | ||
1228 | |||
1229 | @implementation CDAudioInterruptTargetGroup | ||
1230 | |||
1231 | -(id) init { | ||
1232 | if ((self = [super init])) { | ||
1233 | children_ = [[NSMutableArray alloc] initWithCapacity:32]; | ||
1234 | enabled_ = YES; | ||
1235 | mute_ = NO; | ||
1236 | } | ||
1237 | return self; | ||
1238 | } | ||
1239 | |||
1240 | -(void) addAudioInterruptTarget:(NSObject<CDAudioInterruptProtocol>*) interruptibleTarget { | ||
1241 | //Synchronize child with group settings; | ||
1242 | [interruptibleTarget setMute:mute_]; | ||
1243 | [interruptibleTarget setEnabled:enabled_]; | ||
1244 | [children_ addObject:interruptibleTarget]; | ||
1245 | } | ||
1246 | |||
1247 | -(void) removeAudioInterruptTarget:(NSObject<CDAudioInterruptProtocol>*) interruptibleTarget { | ||
1248 | [children_ removeObjectIdenticalTo:interruptibleTarget]; | ||
1249 | } | ||
1250 | |||
1251 | - (BOOL) mute { | ||
1252 | return mute_; | ||
1253 | } | ||
1254 | |||
1255 | /** | ||
1256 | * Setting mute silences all sounds but playing sounds continue to advance playback | ||
1257 | */ | ||
1258 | - (void) setMute:(BOOL) newMuteValue { | ||
1259 | |||
1260 | if (newMuteValue == mute_) { | ||
1261 | return; | ||
1262 | } | ||
1263 | |||
1264 | for (NSObject<CDAudioInterruptProtocol>* target in children_) { | ||
1265 | [target setMute:newMuteValue]; | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | - (BOOL) enabled { | ||
1270 | return enabled_; | ||
1271 | } | ||
1272 | |||
1273 | - (void) setEnabled:(BOOL)enabledValue | ||
1274 | { | ||
1275 | if (enabledValue == enabled_) { | ||
1276 | return; | ||
1277 | } | ||
1278 | |||
1279 | for (NSObject<CDAudioInterruptProtocol>* target in children_) { | ||
1280 | [target setEnabled:enabledValue]; | ||
1281 | } | ||
1282 | } | ||
1283 | |||
1284 | @end | ||
1285 | |||
1286 | |||
1287 | |||
1288 | //////////////////////////////////////////////////////////////////////////// | ||
1289 | |||
1290 | #pragma mark - | ||
1291 | #pragma mark CDAsynchBufferLoader | ||
1292 | |||
1293 | @implementation CDAsynchBufferLoader | ||
1294 | |||
1295 | -(id) init:(NSArray *)loadRequests soundEngine:(CDSoundEngine *) theSoundEngine { | ||
1296 | if ((self = [super init])) { | ||
1297 | _loadRequests = loadRequests; | ||
1298 | [_loadRequests retain]; | ||
1299 | _soundEngine = theSoundEngine; | ||
1300 | [_soundEngine retain]; | ||
1301 | } | ||
1302 | return self; | ||
1303 | } | ||
1304 | |||
1305 | -(void) main { | ||
1306 | CDLOGINFO(@"Denshion::CDAsynchBufferLoader - loading buffers"); | ||
1307 | [super main]; | ||
1308 | _soundEngine.asynchLoadProgress = 0.0f; | ||
1309 | |||
1310 | if ([_loadRequests count] > 0) { | ||
1311 | float increment = 1.0f / [_loadRequests count]; | ||
1312 | //Iterate over load request and load | ||
1313 | for (CDBufferLoadRequest *loadRequest in _loadRequests) { | ||
1314 | [_soundEngine loadBuffer:loadRequest.soundId filePath:loadRequest.filePath]; | ||
1315 | _soundEngine.asynchLoadProgress += increment; | ||
1316 | } | ||
1317 | } | ||
1318 | |||
1319 | //Completed | ||
1320 | _soundEngine.asynchLoadProgress = 1.0f; | ||
1321 | [[NSNotificationCenter defaultCenter] postNotificationName:kCDN_AsynchLoadComplete object:nil]; | ||
1322 | |||
1323 | } | ||
1324 | |||
1325 | -(void) dealloc { | ||
1326 | [_loadRequests release]; | ||
1327 | [_soundEngine release]; | ||
1328 | [super dealloc]; | ||
1329 | } | ||
1330 | |||
1331 | @end | ||
1332 | |||
1333 | |||
1334 | /////////////////////////////////////////////////////////////////////////////////////// | ||
1335 | #pragma mark - | ||
1336 | #pragma mark CDBufferLoadRequest | ||
1337 | |||
1338 | @implementation CDBufferLoadRequest | ||
1339 | |||
1340 | @synthesize filePath, soundId; | ||
1341 | |||
1342 | -(id) init:(int) theSoundId filePath:(const NSString *) theFilePath { | ||
1343 | if ((self = [super init])) { | ||
1344 | soundId = theSoundId; | ||
1345 | filePath = [theFilePath copy];//TODO: is retain necessary or does copy set retain count | ||
1346 | [filePath retain]; | ||
1347 | } | ||
1348 | return self; | ||
1349 | } | ||
1350 | |||
1351 | -(void) dealloc { | ||
1352 | [filePath release]; | ||
1353 | [super dealloc]; | ||
1354 | } | ||
1355 | |||
1356 | @end | ||
1357 | |||
1358 | /////////////////////////////////////////////////////////////////////////////////////// | ||
1359 | #pragma mark - | ||
1360 | #pragma mark CDFloatInterpolator | ||
1361 | |||
1362 | @implementation CDFloatInterpolator | ||
1363 | @synthesize start,end,interpolationType; | ||
1364 | |||
1365 | -(float) interpolate:(float) t { | ||
1366 | |||
1367 | if (t < 1.0f) { | ||
1368 | switch (interpolationType) { | ||
1369 | case kIT_Linear: | ||
1370 | //Linear interpolation | ||
1371 | return ((end - start) * t) + start; | ||
1372 | |||
1373 | case kIT_SCurve: | ||
1374 | //Cubic s curve t^2 * (3 - 2t) | ||
1375 | return ((float)(t * t * (3.0 - (2.0 * t))) * (end - start)) + start; | ||
1376 | |||
1377 | case kIT_Exponential: | ||
1378 | //Formulas taken from EaseAction | ||
1379 | if (end > start) { | ||
1380 | //Fade in | ||
1381 | float logDelta = (t==0) ? 0 : powf(2, 10 * (t/1 - 1)) - 1 * 0.001f; | ||
1382 | return ((end - start) * logDelta) + start; | ||
1383 | } else { | ||
1384 | //Fade Out | ||
1385 | float logDelta = (-powf(2, -10 * t/1) + 1); | ||
1386 | return ((end - start) * logDelta) + start; | ||
1387 | } | ||
1388 | default: | ||
1389 | return 0.0f; | ||
1390 | } | ||
1391 | } else { | ||
1392 | return end; | ||
1393 | } | ||
1394 | } | ||
1395 | |||
1396 | -(id) init:(tCDInterpolationType) type startVal:(float) startVal endVal:(float) endVal { | ||
1397 | if ((self = [super init])) { | ||
1398 | start = startVal; | ||
1399 | end = endVal; | ||
1400 | interpolationType = type; | ||
1401 | } | ||
1402 | return self; | ||
1403 | } | ||
1404 | |||
1405 | @end | ||
1406 | |||
1407 | /////////////////////////////////////////////////////////////////////////////////////// | ||
1408 | #pragma mark - | ||
1409 | #pragma mark CDPropertyModifier | ||
1410 | |||
1411 | @implementation CDPropertyModifier | ||
1412 | |||
1413 | @synthesize stopTargetWhenComplete; | ||
1414 | |||
1415 | -(id) init:(id) theTarget interpolationType:(tCDInterpolationType) type startVal:(float) startVal endVal:(float) endVal { | ||
1416 | if ((self = [super init])) { | ||
1417 | if (target) { | ||
1418 | //Release the previous target if there is one | ||
1419 | [target release]; | ||
1420 | } | ||
1421 | target = theTarget; | ||
1422 | #if CD_DEBUG | ||
1423 | //Check target is of the required type | ||
1424 | if (![theTarget isMemberOfClass:[self _allowableType]] ) { | ||
1425 | CDLOG(@"Denshion::CDPropertyModifier target is not of type %@",[self _allowableType]); | ||
1426 | NSAssert([theTarget isKindOfClass:[CDSoundEngine class]], @"CDPropertyModifier target not of required type"); | ||
1427 | } | ||
1428 | #endif | ||
1429 | [target retain]; | ||
1430 | startValue = startVal; | ||
1431 | endValue = endVal; | ||
1432 | if (interpolator) { | ||
1433 | //Release previous interpolator if there is one | ||
1434 | [interpolator release]; | ||
1435 | } | ||
1436 | interpolator = [[CDFloatInterpolator alloc] init:type startVal:startVal endVal:endVal]; | ||
1437 | stopTargetWhenComplete = NO; | ||
1438 | } | ||
1439 | return self; | ||
1440 | } | ||
1441 | |||
1442 | -(void) dealloc { | ||
1443 | CDLOGINFO(@"Denshion::CDPropertyModifier deallocated %@",self); | ||
1444 | [target release]; | ||
1445 | [interpolator release]; | ||
1446 | [super dealloc]; | ||
1447 | } | ||
1448 | |||
1449 | -(void) modify:(float) t { | ||
1450 | if (t < 1.0) { | ||
1451 | [self _setTargetProperty:[interpolator interpolate:t]]; | ||
1452 | } else { | ||
1453 | //At the end | ||
1454 | [self _setTargetProperty:endValue]; | ||
1455 | if (stopTargetWhenComplete) { | ||
1456 | [self _stopTarget]; | ||
1457 | } | ||
1458 | } | ||
1459 | } | ||
1460 | |||
1461 | -(float) startValue { | ||
1462 | return startValue; | ||
1463 | } | ||
1464 | |||
1465 | -(void) setStartValue:(float) startVal | ||
1466 | { | ||
1467 | startValue = startVal; | ||
1468 | interpolator.start = startVal; | ||
1469 | } | ||
1470 | |||
1471 | -(float) endValue { | ||
1472 | return startValue; | ||
1473 | } | ||
1474 | |||
1475 | -(void) setEndValue:(float) endVal | ||
1476 | { | ||
1477 | endValue = endVal; | ||
1478 | interpolator.end = endVal; | ||
1479 | } | ||
1480 | |||
1481 | -(tCDInterpolationType) interpolationType { | ||
1482 | return interpolator.interpolationType; | ||
1483 | } | ||
1484 | |||
1485 | -(void) setInterpolationType:(tCDInterpolationType) interpolationType { | ||
1486 | interpolator.interpolationType = interpolationType; | ||
1487 | } | ||
1488 | |||
1489 | -(void) _setTargetProperty:(float) newVal { | ||
1490 | |||
1491 | } | ||
1492 | |||
1493 | -(float) _getTargetProperty { | ||
1494 | return 0.0f; | ||
1495 | } | ||
1496 | |||
1497 | -(void) _stopTarget { | ||
1498 | |||
1499 | } | ||
1500 | |||
1501 | -(Class) _allowableType { | ||
1502 | return [NSObject class]; | ||
1503 | } | ||
1504 | @end | ||
1505 | |||
1506 | /////////////////////////////////////////////////////////////////////////////////////// | ||
1507 | #pragma mark - | ||
1508 | #pragma mark CDSoundSourceFader | ||
1509 | |||
1510 | @implementation CDSoundSourceFader | ||
1511 | |||
1512 | -(void) _setTargetProperty:(float) newVal { | ||
1513 | ((CDSoundSource*)target).gain = newVal; | ||
1514 | } | ||
1515 | |||
1516 | -(float) _getTargetProperty { | ||
1517 | return ((CDSoundSource*)target).gain; | ||
1518 | } | ||
1519 | |||
1520 | -(void) _stopTarget { | ||
1521 | [((CDSoundSource*)target) stop]; | ||
1522 | } | ||
1523 | |||
1524 | -(Class) _allowableType { | ||
1525 | return [CDSoundSource class]; | ||
1526 | } | ||
1527 | |||
1528 | @end | ||
1529 | |||
1530 | /////////////////////////////////////////////////////////////////////////////////////// | ||
1531 | #pragma mark - | ||
1532 | #pragma mark CDSoundSourcePanner | ||
1533 | |||
1534 | @implementation CDSoundSourcePanner | ||
1535 | |||
1536 | -(void) _setTargetProperty:(float) newVal { | ||
1537 | ((CDSoundSource*)target).pan = newVal; | ||
1538 | } | ||
1539 | |||
1540 | -(float) _getTargetProperty { | ||
1541 | return ((CDSoundSource*)target).pan; | ||
1542 | } | ||
1543 | |||
1544 | -(void) _stopTarget { | ||
1545 | [((CDSoundSource*)target) stop]; | ||
1546 | } | ||
1547 | |||
1548 | -(Class) _allowableType { | ||
1549 | return [CDSoundSource class]; | ||
1550 | } | ||
1551 | |||
1552 | @end | ||
1553 | |||
1554 | /////////////////////////////////////////////////////////////////////////////////////// | ||
1555 | #pragma mark - | ||
1556 | #pragma mark CDSoundSourcePitchBender | ||
1557 | |||
1558 | @implementation CDSoundSourcePitchBender | ||
1559 | |||
1560 | -(void) _setTargetProperty:(float) newVal { | ||
1561 | ((CDSoundSource*)target).pitch = newVal; | ||
1562 | } | ||
1563 | |||
1564 | -(float) _getTargetProperty { | ||
1565 | return ((CDSoundSource*)target).pitch; | ||
1566 | } | ||
1567 | |||
1568 | -(void) _stopTarget { | ||
1569 | [((CDSoundSource*)target) stop]; | ||
1570 | } | ||
1571 | |||
1572 | -(Class) _allowableType { | ||
1573 | return [CDSoundSource class]; | ||
1574 | } | ||
1575 | |||
1576 | @end | ||
1577 | |||
1578 | /////////////////////////////////////////////////////////////////////////////////////// | ||
1579 | #pragma mark - | ||
1580 | #pragma mark CDSoundEngineFader | ||
1581 | |||
1582 | @implementation CDSoundEngineFader | ||
1583 | |||
1584 | -(void) _setTargetProperty:(float) newVal { | ||
1585 | ((CDSoundEngine*)target).masterGain = newVal; | ||
1586 | } | ||
1587 | |||
1588 | -(float) _getTargetProperty { | ||
1589 | return ((CDSoundEngine*)target).masterGain; | ||
1590 | } | ||
1591 | |||
1592 | -(void) _stopTarget { | ||
1593 | [((CDSoundEngine*)target) stopAllSounds]; | ||
1594 | } | ||
1595 | |||
1596 | -(Class) _allowableType { | ||
1597 | return [CDSoundEngine class]; | ||
1598 | } | ||
1599 | |||
1600 | @end | ||
1601 | |||
1602 | |||
diff --git a/libs/CocosDenshion/SimpleAudioEngine.h b/libs/CocosDenshion/SimpleAudioEngine.h new file mode 100755 index 0000000..35396c6 --- /dev/null +++ b/libs/CocosDenshion/SimpleAudioEngine.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | Copyright (c) 2010 Steve Oldmeadow | ||
3 | |||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | of this software and associated documentation files (the "Software"), to deal | ||
6 | in the Software without restriction, including without limitation the rights | ||
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
8 | copies of the Software, and to permit persons to whom the Software is | ||
9 | furnished to do so, subject to the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be included in | ||
12 | all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
20 | THE SOFTWARE. | ||
21 | |||
22 | $Id$ | ||
23 | */ | ||
24 | |||
25 | |||
26 | #import "CDAudioManager.h" | ||
27 | |||
28 | /** | ||
29 | A wrapper to the CDAudioManager object. | ||
30 | This is recommended for basic audio requirements. If you just want to play some sound fx | ||
31 | and some background music and have no interest in learning the lower level workings then | ||
32 | this is the interface to use. | ||
33 | |||
34 | Requirements: | ||
35 | - Firmware: OS 2.2 or greater | ||
36 | - Files: SimpleAudioEngine.*, CocosDenshion.* | ||
37 | - Frameworks: OpenAL, AudioToolbox, AVFoundation | ||
38 | @since v0.8 | ||
39 | */ | ||
40 | @interface SimpleAudioEngine : NSObject <CDAudioInterruptProtocol> { | ||
41 | |||
42 | BOOL mute_; | ||
43 | BOOL enabled_; | ||
44 | } | ||
45 | |||
46 | /** Background music volume. Range is 0.0f to 1.0f. This will only have an effect if willPlayBackgroundMusic returns YES */ | ||
47 | @property (readwrite) float backgroundMusicVolume; | ||
48 | /** Effects volume. Range is 0.0f to 1.0f */ | ||
49 | @property (readwrite) float effectsVolume; | ||
50 | /** If NO it indicates background music will not be played either because no background music is loaded or the audio session does not permit it.*/ | ||
51 | @property (readonly) BOOL willPlayBackgroundMusic; | ||
52 | |||
53 | /** returns the shared instance of the SimpleAudioEngine object */ | ||
54 | + (SimpleAudioEngine*) sharedEngine; | ||
55 | |||
56 | /** Preloads a music file so it will be ready to play as background music */ | ||
57 | -(void) preloadBackgroundMusic:(NSString*) filePath; | ||
58 | |||
59 | /** plays background music in a loop*/ | ||
60 | -(void) playBackgroundMusic:(NSString*) filePath; | ||
61 | /** plays background music, if loop is true the music will repeat otherwise it will be played once */ | ||
62 | -(void) playBackgroundMusic:(NSString*) filePath loop:(BOOL) loop; | ||
63 | /** stops playing background music */ | ||
64 | -(void) stopBackgroundMusic; | ||
65 | /** pauses the background music */ | ||
66 | -(void) pauseBackgroundMusic; | ||
67 | /** resume background music that has been paused */ | ||
68 | -(void) resumeBackgroundMusic; | ||
69 | /** rewind the background music */ | ||
70 | -(void) rewindBackgroundMusic; | ||
71 | /** returns whether or not the background music is playing */ | ||
72 | -(BOOL) isBackgroundMusicPlaying; | ||
73 | |||
74 | /** plays an audio effect with a file path*/ | ||
75 | -(ALuint) playEffect:(NSString*) filePath; | ||
76 | /** stop a sound that is playing, note you must pass in the soundId that is returned when you started playing the sound with playEffect */ | ||
77 | -(void) stopEffect:(ALuint) soundId; | ||
78 | /** plays an audio effect with a file path, pitch, pan and gain */ | ||
79 | -(ALuint) playEffect:(NSString*) filePath pitch:(Float32) pitch pan:(Float32) pan gain:(Float32) gain; | ||
80 | /** preloads an audio effect */ | ||
81 | -(void) preloadEffect:(NSString*) filePath; | ||
82 | /** unloads an audio effect from memory */ | ||
83 | -(void) unloadEffect:(NSString*) filePath; | ||
84 | /** Gets a CDSoundSource object set up to play the specified file. */ | ||
85 | -(CDSoundSource *) soundSourceForFile:(NSString*) filePath; | ||
86 | |||
87 | /** Shuts down the shared audio engine instance so that it can be reinitialised */ | ||
88 | +(void) end; | ||
89 | |||
90 | @end | ||
diff --git a/libs/CocosDenshion/SimpleAudioEngine.m b/libs/CocosDenshion/SimpleAudioEngine.m new file mode 100755 index 0000000..cdff26c --- /dev/null +++ b/libs/CocosDenshion/SimpleAudioEngine.m | |||
@@ -0,0 +1,220 @@ | |||
1 | /* | ||
2 | Copyright (c) 2010 Steve Oldmeadow | ||
3 | |||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | of this software and associated documentation files (the "Software"), to deal | ||
6 | in the Software without restriction, including without limitation the rights | ||
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
8 | copies of the Software, and to permit persons to whom the Software is | ||
9 | furnished to do so, subject to the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be included in | ||
12 | all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
20 | THE SOFTWARE. | ||
21 | |||
22 | $Id$ | ||
23 | */ | ||
24 | |||
25 | #import "SimpleAudioEngine.h" | ||
26 | |||
27 | @implementation SimpleAudioEngine | ||
28 | |||
29 | static SimpleAudioEngine *sharedEngine = nil; | ||
30 | static CDSoundEngine* soundEngine = nil; | ||
31 | static CDAudioManager *am = nil; | ||
32 | static CDBufferManager *bufferManager = nil; | ||
33 | |||
34 | // Init | ||
35 | + (SimpleAudioEngine *) sharedEngine | ||
36 | { | ||
37 | @synchronized(self) { | ||
38 | if (!sharedEngine) | ||
39 | sharedEngine = [[SimpleAudioEngine alloc] init]; | ||
40 | } | ||
41 | return sharedEngine; | ||
42 | } | ||
43 | |||
44 | + (id) alloc | ||
45 | { | ||
46 | @synchronized(self) { | ||
47 | NSAssert(sharedEngine == nil, @"Attempted to allocate a second instance of a singleton."); | ||
48 | return [super alloc]; | ||
49 | } | ||
50 | return nil; | ||
51 | } | ||
52 | |||
53 | -(id) init | ||
54 | { | ||
55 | if((self=[super init])) { | ||
56 | am = [CDAudioManager sharedManager]; | ||
57 | soundEngine = am.soundEngine; | ||
58 | bufferManager = [[CDBufferManager alloc] initWithEngine:soundEngine]; | ||
59 | mute_ = NO; | ||
60 | enabled_ = YES; | ||
61 | } | ||
62 | return self; | ||
63 | } | ||
64 | |||
65 | // Memory | ||
66 | - (void) dealloc | ||
67 | { | ||
68 | am = nil; | ||
69 | soundEngine = nil; | ||
70 | bufferManager = nil; | ||
71 | [super dealloc]; | ||
72 | } | ||
73 | |||
74 | +(void) end | ||
75 | { | ||
76 | am = nil; | ||
77 | [CDAudioManager end]; | ||
78 | [bufferManager release]; | ||
79 | [sharedEngine release]; | ||
80 | sharedEngine = nil; | ||
81 | } | ||
82 | |||
83 | #pragma mark SimpleAudioEngine - background music | ||
84 | |||
85 | -(void) preloadBackgroundMusic:(NSString*) filePath { | ||
86 | [am preloadBackgroundMusic:filePath]; | ||
87 | } | ||
88 | |||
89 | -(void) playBackgroundMusic:(NSString*) filePath | ||
90 | { | ||
91 | [am playBackgroundMusic:filePath loop:TRUE]; | ||
92 | } | ||
93 | |||
94 | -(void) playBackgroundMusic:(NSString*) filePath loop:(BOOL) loop | ||
95 | { | ||
96 | [am playBackgroundMusic:filePath loop:loop]; | ||
97 | } | ||
98 | |||
99 | -(void) stopBackgroundMusic | ||
100 | { | ||
101 | [am stopBackgroundMusic]; | ||
102 | } | ||
103 | |||
104 | -(void) pauseBackgroundMusic { | ||
105 | [am pauseBackgroundMusic]; | ||
106 | } | ||
107 | |||
108 | -(void) resumeBackgroundMusic { | ||
109 | [am resumeBackgroundMusic]; | ||
110 | } | ||
111 | |||
112 | -(void) rewindBackgroundMusic { | ||
113 | [am rewindBackgroundMusic]; | ||
114 | } | ||
115 | |||
116 | -(BOOL) isBackgroundMusicPlaying { | ||
117 | return [am isBackgroundMusicPlaying]; | ||
118 | } | ||
119 | |||
120 | -(BOOL) willPlayBackgroundMusic { | ||
121 | return [am willPlayBackgroundMusic]; | ||
122 | } | ||
123 | |||
124 | #pragma mark SimpleAudioEngine - sound effects | ||
125 | |||
126 | -(ALuint) playEffect:(NSString*) filePath | ||
127 | { | ||
128 | return [self playEffect:filePath pitch:1.0f pan:0.0f gain:1.0f]; | ||
129 | } | ||
130 | |||
131 | -(ALuint) playEffect:(NSString*) filePath pitch:(Float32) pitch pan:(Float32) pan gain:(Float32) gain | ||
132 | { | ||
133 | int soundId = [bufferManager bufferForFile:filePath create:YES]; | ||
134 | if (soundId != kCDNoBuffer) { | ||
135 | return [soundEngine playSound:soundId sourceGroupId:0 pitch:pitch pan:pan gain:gain loop:false]; | ||
136 | } else { | ||
137 | return CD_MUTE; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | -(void) stopEffect:(ALuint) soundId { | ||
142 | [soundEngine stopSound:soundId]; | ||
143 | } | ||
144 | |||
145 | -(void) preloadEffect:(NSString*) filePath | ||
146 | { | ||
147 | int soundId = [bufferManager bufferForFile:filePath create:YES]; | ||
148 | if (soundId == kCDNoBuffer) { | ||
149 | CDLOG(@"Denshion::SimpleAudioEngine sound failed to preload %@",filePath); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | -(void) unloadEffect:(NSString*) filePath | ||
154 | { | ||
155 | CDLOGINFO(@"Denshion::SimpleAudioEngine unloadedEffect %@",filePath); | ||
156 | [bufferManager releaseBufferForFile:filePath]; | ||
157 | } | ||
158 | |||
159 | #pragma mark Audio Interrupt Protocol | ||
160 | -(BOOL) mute | ||
161 | { | ||
162 | return mute_; | ||
163 | } | ||
164 | |||
165 | -(void) setMute:(BOOL) muteValue | ||
166 | { | ||
167 | if (mute_ != muteValue) { | ||
168 | mute_ = muteValue; | ||
169 | am.mute = mute_; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | -(BOOL) enabled | ||
174 | { | ||
175 | return enabled_; | ||
176 | } | ||
177 | |||
178 | -(void) setEnabled:(BOOL) enabledValue | ||
179 | { | ||
180 | if (enabled_ != enabledValue) { | ||
181 | enabled_ = enabledValue; | ||
182 | am.enabled = enabled_; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | |||
187 | #pragma mark SimpleAudioEngine - BackgroundMusicVolume | ||
188 | -(float) backgroundMusicVolume | ||
189 | { | ||
190 | return am.backgroundMusic.volume; | ||
191 | } | ||
192 | |||
193 | -(void) setBackgroundMusicVolume:(float) volume | ||
194 | { | ||
195 | am.backgroundMusic.volume = volume; | ||
196 | } | ||
197 | |||
198 | #pragma mark SimpleAudioEngine - EffectsVolume | ||
199 | -(float) effectsVolume | ||
200 | { | ||
201 | return am.soundEngine.masterGain; | ||
202 | } | ||
203 | |||
204 | -(void) setEffectsVolume:(float) volume | ||
205 | { | ||
206 | am.soundEngine.masterGain = volume; | ||
207 | } | ||
208 | |||
209 | -(CDSoundSource *) soundSourceForFile:(NSString*) filePath { | ||
210 | int soundId = [bufferManager bufferForFile:filePath create:YES]; | ||
211 | if (soundId != kCDNoBuffer) { | ||
212 | CDSoundSource *result = [soundEngine soundSourceForSound:soundId sourceGroupId:0]; | ||
213 | CDLOGINFO(@"Denshion::SimpleAudioEngine sound source created for %@",filePath); | ||
214 | return result; | ||
215 | } else { | ||
216 | return nil; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | @end | ||
diff --git a/libs/FontLabel/FontLabel.h b/libs/FontLabel/FontLabel.h new file mode 100755 index 0000000..6de9c2c --- /dev/null +++ b/libs/FontLabel/FontLabel.h | |||
@@ -0,0 +1,44 @@ | |||
1 | // | ||
2 | // FontLabel.h | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 5/8/09. | ||
6 | // Copyright © 2009 Zynga Game Networks | ||
7 | // | ||
8 | // | ||
9 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
10 | // you may not use this file except in compliance with the License. | ||
11 | // You may obtain a copy of the License at | ||
12 | // | ||
13 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
14 | // | ||
15 | // Unless required by applicable law or agreed to in writing, software | ||
16 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
18 | // See the License for the specific language governing permissions and | ||
19 | // limitations under the License. | ||
20 | // | ||
21 | |||
22 | #import <Foundation/Foundation.h> | ||
23 | #import <UIKit/UIKit.h> | ||
24 | |||
25 | @class ZFont; | ||
26 | @class ZAttributedString; | ||
27 | |||
28 | @interface FontLabel : UILabel { | ||
29 | void *reserved; // works around a bug in UILabel | ||
30 | ZFont *zFont; | ||
31 | ZAttributedString *zAttributedText; | ||
32 | } | ||
33 | @property (nonatomic, setter=setCGFont:) CGFontRef cgFont __AVAILABILITY_INTERNAL_DEPRECATED; | ||
34 | @property (nonatomic, assign) CGFloat pointSize __AVAILABILITY_INTERNAL_DEPRECATED; | ||
35 | @property (nonatomic, retain, setter=setZFont:) ZFont *zFont; | ||
36 | // if attributedText is nil, fall back on using the inherited UILabel properties | ||
37 | // if attributedText is non-nil, the font/text/textColor | ||
38 | // in addition, adjustsFontSizeToFitWidth does not work with attributed text | ||
39 | @property (nonatomic, copy) ZAttributedString *zAttributedText; | ||
40 | // -initWithFrame:fontName:pointSize: uses FontManager to look up the font name | ||
41 | - (id)initWithFrame:(CGRect)frame fontName:(NSString *)fontName pointSize:(CGFloat)pointSize; | ||
42 | - (id)initWithFrame:(CGRect)frame zFont:(ZFont *)font; | ||
43 | - (id)initWithFrame:(CGRect)frame font:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED; | ||
44 | @end | ||
diff --git a/libs/FontLabel/FontLabel.m b/libs/FontLabel/FontLabel.m new file mode 100755 index 0000000..58975b1 --- /dev/null +++ b/libs/FontLabel/FontLabel.m | |||
@@ -0,0 +1,195 @@ | |||
1 | // | ||
2 | // FontLabel.m | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 5/8/09. | ||
6 | // Copyright © 2009 Zynga Game Networks | ||
7 | // | ||
8 | // | ||
9 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
10 | // you may not use this file except in compliance with the License. | ||
11 | // You may obtain a copy of the License at | ||
12 | // | ||
13 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
14 | // | ||
15 | // Unless required by applicable law or agreed to in writing, software | ||
16 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
18 | // See the License for the specific language governing permissions and | ||
19 | // limitations under the License. | ||
20 | // | ||
21 | |||
22 | #import "FontLabel.h" | ||
23 | #import "FontManager.h" | ||
24 | #import "FontLabelStringDrawing.h" | ||
25 | #import "ZFont.h" | ||
26 | |||
27 | @interface ZFont (ZFontPrivate) | ||
28 | @property (nonatomic, readonly) CGFloat ratio; | ||
29 | @end | ||
30 | |||
31 | @implementation FontLabel | ||
32 | @synthesize zFont; | ||
33 | @synthesize zAttributedText; | ||
34 | |||
35 | - (id)initWithFrame:(CGRect)frame fontName:(NSString *)fontName pointSize:(CGFloat)pointSize { | ||
36 | return [self initWithFrame:frame zFont:[[FontManager sharedManager] zFontWithName:fontName pointSize:pointSize]]; | ||
37 | } | ||
38 | |||
39 | - (id)initWithFrame:(CGRect)frame zFont:(ZFont *)font { | ||
40 | if ((self = [super initWithFrame:frame])) { | ||
41 | zFont = [font retain]; | ||
42 | } | ||
43 | return self; | ||
44 | } | ||
45 | |||
46 | - (id)initWithFrame:(CGRect)frame font:(CGFontRef)font pointSize:(CGFloat)pointSize { | ||
47 | return [self initWithFrame:frame zFont:[ZFont fontWithCGFont:font size:pointSize]]; | ||
48 | } | ||
49 | |||
50 | - (CGFontRef)cgFont { | ||
51 | return self.zFont.cgFont; | ||
52 | } | ||
53 | |||
54 | - (void)setCGFont:(CGFontRef)font { | ||
55 | if (self.zFont.cgFont != font) { | ||
56 | self.zFont = [ZFont fontWithCGFont:font size:self.zFont.pointSize]; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | - (CGFloat)pointSize { | ||
61 | return self.zFont.pointSize; | ||
62 | } | ||
63 | |||
64 | - (void)setPointSize:(CGFloat)pointSize { | ||
65 | if (self.zFont.pointSize != pointSize) { | ||
66 | self.zFont = [ZFont fontWithCGFont:self.zFont.cgFont size:pointSize]; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | - (void)setZAttributedText:(ZAttributedString *)attStr { | ||
71 | if (zAttributedText != attStr) { | ||
72 | [zAttributedText release]; | ||
73 | zAttributedText = [attStr copy]; | ||
74 | [self setNeedsDisplay]; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | - (void)drawTextInRect:(CGRect)rect { | ||
79 | if (self.zFont == NULL && self.zAttributedText == nil) { | ||
80 | [super drawTextInRect:rect]; | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | if (self.zAttributedText == nil) { | ||
85 | // this method is documented as setting the text color for us, but that doesn't appear to be the case | ||
86 | if (self.highlighted) { | ||
87 | [(self.highlightedTextColor ?: [UIColor whiteColor]) setFill]; | ||
88 | } else { | ||
89 | [(self.textColor ?: [UIColor blackColor]) setFill]; | ||
90 | } | ||
91 | |||
92 | ZFont *actualFont = self.zFont; | ||
93 | CGSize origSize = rect.size; | ||
94 | if (self.numberOfLines == 1) { | ||
95 | origSize.height = actualFont.leading; | ||
96 | CGPoint point = CGPointMake(rect.origin.x, | ||
97 | rect.origin.y + roundf(((rect.size.height - actualFont.leading) / 2.0f))); | ||
98 | CGSize size = [self.text sizeWithZFont:actualFont]; | ||
99 | if (self.adjustsFontSizeToFitWidth && self.minimumFontSize < actualFont.pointSize) { | ||
100 | if (size.width > origSize.width) { | ||
101 | CGFloat desiredRatio = (origSize.width * actualFont.ratio) / size.width; | ||
102 | CGFloat desiredPointSize = desiredRatio * actualFont.pointSize / actualFont.ratio; | ||
103 | actualFont = [actualFont fontWithSize:MAX(MAX(desiredPointSize, self.minimumFontSize), 1.0f)]; | ||
104 | size = [self.text sizeWithZFont:actualFont]; | ||
105 | } | ||
106 | if (!CGSizeEqualToSize(origSize, size)) { | ||
107 | switch (self.baselineAdjustment) { | ||
108 | case UIBaselineAdjustmentAlignCenters: | ||
109 | point.y += roundf((origSize.height - size.height) / 2.0f); | ||
110 | break; | ||
111 | case UIBaselineAdjustmentAlignBaselines: | ||
112 | point.y += (self.zFont.ascender - actualFont.ascender); | ||
113 | break; | ||
114 | case UIBaselineAdjustmentNone: | ||
115 | break; | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | size.width = MIN(size.width, origSize.width); | ||
120 | // adjust the point for alignment | ||
121 | switch (self.textAlignment) { | ||
122 | case UITextAlignmentLeft: | ||
123 | break; | ||
124 | case UITextAlignmentCenter: | ||
125 | point.x += (origSize.width - size.width) / 2.0f; | ||
126 | break; | ||
127 | case UITextAlignmentRight: | ||
128 | point.x += origSize.width - size.width; | ||
129 | break; | ||
130 | } | ||
131 | [self.text drawAtPoint:point forWidth:size.width withZFont:actualFont lineBreakMode:self.lineBreakMode]; | ||
132 | } else { | ||
133 | CGSize size = [self.text sizeWithZFont:actualFont constrainedToSize:origSize lineBreakMode:self.lineBreakMode numberOfLines:self.numberOfLines]; | ||
134 | CGPoint point = rect.origin; | ||
135 | point.y += roundf((rect.size.height - size.height) / 2.0f); | ||
136 | rect = (CGRect){point, CGSizeMake(rect.size.width, size.height)}; | ||
137 | [self.text drawInRect:rect withZFont:actualFont lineBreakMode:self.lineBreakMode alignment:self.textAlignment numberOfLines:self.numberOfLines]; | ||
138 | } | ||
139 | } else { | ||
140 | ZAttributedString *attStr = self.zAttributedText; | ||
141 | if (self.highlighted) { | ||
142 | // modify the string to change the base color | ||
143 | ZMutableAttributedString *mutStr = [[attStr mutableCopy] autorelease]; | ||
144 | NSRange activeRange = NSMakeRange(0, attStr.length); | ||
145 | while (activeRange.length > 0) { | ||
146 | NSRange effective; | ||
147 | UIColor *color = [attStr attribute:ZForegroundColorAttributeName atIndex:activeRange.location | ||
148 | longestEffectiveRange:&effective inRange:activeRange]; | ||
149 | if (color == nil) { | ||
150 | [mutStr addAttribute:ZForegroundColorAttributeName value:[UIColor whiteColor] range:effective]; | ||
151 | } | ||
152 | activeRange.location += effective.length, activeRange.length -= effective.length; | ||
153 | } | ||
154 | attStr = mutStr; | ||
155 | } | ||
156 | CGSize size = [attStr sizeConstrainedToSize:rect.size lineBreakMode:self.lineBreakMode numberOfLines:self.numberOfLines]; | ||
157 | CGPoint point = rect.origin; | ||
158 | point.y += roundf((rect.size.height - size.height) / 2.0f); | ||
159 | rect = (CGRect){point, CGSizeMake(rect.size.width, size.height)}; | ||
160 | [attStr drawInRect:rect withLineBreakMode:self.lineBreakMode alignment:self.textAlignment numberOfLines:self.numberOfLines]; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | - (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines { | ||
165 | if (self.zFont == NULL && self.zAttributedText == nil) { | ||
166 | return [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines]; | ||
167 | } | ||
168 | |||
169 | if (numberOfLines == 1) { | ||
170 | // if numberOfLines == 1 we need to use the version that converts spaces | ||
171 | CGSize size; | ||
172 | if (self.zAttributedText == nil) { | ||
173 | size = [self.text sizeWithZFont:self.zFont]; | ||
174 | } else { | ||
175 | size = [self.zAttributedText size]; | ||
176 | } | ||
177 | bounds.size.width = MIN(bounds.size.width, size.width); | ||
178 | bounds.size.height = MIN(bounds.size.height, size.height); | ||
179 | } else { | ||
180 | if (numberOfLines > 0) bounds.size.height = MIN(bounds.size.height, self.zFont.leading * numberOfLines); | ||
181 | if (self.zAttributedText == nil) { | ||
182 | bounds.size = [self.text sizeWithZFont:self.zFont constrainedToSize:bounds.size lineBreakMode:self.lineBreakMode]; | ||
183 | } else { | ||
184 | bounds.size = [self.zAttributedText sizeConstrainedToSize:bounds.size lineBreakMode:self.lineBreakMode]; | ||
185 | } | ||
186 | } | ||
187 | return bounds; | ||
188 | } | ||
189 | |||
190 | - (void)dealloc { | ||
191 | [zFont release]; | ||
192 | [zAttributedText release]; | ||
193 | [super dealloc]; | ||
194 | } | ||
195 | @end | ||
diff --git a/libs/FontLabel/FontLabelStringDrawing.h b/libs/FontLabel/FontLabelStringDrawing.h new file mode 100755 index 0000000..821da22 --- /dev/null +++ b/libs/FontLabel/FontLabelStringDrawing.h | |||
@@ -0,0 +1,69 @@ | |||
1 | // | ||
2 | // FontLabelStringDrawing.h | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 5/5/09. | ||
6 | // Copyright © 2009 Zynga Game Networks | ||
7 | // | ||
8 | // | ||
9 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
10 | // you may not use this file except in compliance with the License. | ||
11 | // You may obtain a copy of the License at | ||
12 | // | ||
13 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
14 | // | ||
15 | // Unless required by applicable law or agreed to in writing, software | ||
16 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
18 | // See the License for the specific language governing permissions and | ||
19 | // limitations under the License. | ||
20 | // | ||
21 | |||
22 | #import <UIKit/UIKit.h> | ||
23 | #import "ZAttributedString.h" | ||
24 | |||
25 | @class ZFont; | ||
26 | |||
27 | @interface NSString (FontLabelStringDrawing) | ||
28 | // CGFontRef-based methods | ||
29 | - (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED; | ||
30 | - (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size __AVAILABILITY_INTERNAL_DEPRECATED; | ||
31 | - (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size | ||
32 | lineBreakMode:(UILineBreakMode)lineBreakMode __AVAILABILITY_INTERNAL_DEPRECATED; | ||
33 | - (CGSize)drawAtPoint:(CGPoint)point withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED; | ||
34 | - (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED; | ||
35 | - (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize | ||
36 | lineBreakMode:(UILineBreakMode)lineBreakMode __AVAILABILITY_INTERNAL_DEPRECATED; | ||
37 | - (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize | ||
38 | lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment __AVAILABILITY_INTERNAL_DEPRECATED; | ||
39 | |||
40 | // ZFont-based methods | ||
41 | - (CGSize)sizeWithZFont:(ZFont *)font; | ||
42 | - (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size; | ||
43 | - (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode; | ||
44 | - (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode | ||
45 | numberOfLines:(NSUInteger)numberOfLines; | ||
46 | - (CGSize)drawAtPoint:(CGPoint)point withZFont:(ZFont *)font; | ||
47 | - (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode; | ||
48 | - (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font; | ||
49 | - (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode; | ||
50 | - (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode | ||
51 | alignment:(UITextAlignment)alignment; | ||
52 | - (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode | ||
53 | alignment:(UITextAlignment)alignment numberOfLines:(NSUInteger)numberOfLines; | ||
54 | @end | ||
55 | |||
56 | @interface ZAttributedString (ZAttributedStringDrawing) | ||
57 | - (CGSize)size; | ||
58 | - (CGSize)sizeConstrainedToSize:(CGSize)size; | ||
59 | - (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode; | ||
60 | - (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode | ||
61 | numberOfLines:(NSUInteger)numberOfLines; | ||
62 | - (CGSize)drawAtPoint:(CGPoint)point; | ||
63 | - (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode; | ||
64 | - (CGSize)drawInRect:(CGRect)rect; | ||
65 | - (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode; | ||
66 | - (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment; | ||
67 | - (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment | ||
68 | numberOfLines:(NSUInteger)numberOfLines; | ||
69 | @end | ||
diff --git a/libs/FontLabel/FontLabelStringDrawing.m b/libs/FontLabel/FontLabelStringDrawing.m new file mode 100755 index 0000000..2907372 --- /dev/null +++ b/libs/FontLabel/FontLabelStringDrawing.m | |||
@@ -0,0 +1,892 @@ | |||
1 | // | ||
2 | // FontLabelStringDrawing.m | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 5/5/09. | ||
6 | // Copyright © 2009 Zynga Game Networks | ||
7 | // | ||
8 | // | ||
9 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
10 | // you may not use this file except in compliance with the License. | ||
11 | // You may obtain a copy of the License at | ||
12 | // | ||
13 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
14 | // | ||
15 | // Unless required by applicable law or agreed to in writing, software | ||
16 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
18 | // See the License for the specific language governing permissions and | ||
19 | // limitations under the License. | ||
20 | // | ||
21 | |||
22 | #import "FontLabelStringDrawing.h" | ||
23 | #import "ZFont.h" | ||
24 | #import "ZAttributedStringPrivate.h" | ||
25 | |||
26 | @interface ZFont (ZFontPrivate) | ||
27 | @property (nonatomic, readonly) CGFloat ratio; | ||
28 | @end | ||
29 | |||
30 | #define kUnicodeHighSurrogateStart 0xD800 | ||
31 | #define kUnicodeHighSurrogateEnd 0xDBFF | ||
32 | #define kUnicodeHighSurrogateMask kUnicodeHighSurrogateStart | ||
33 | #define kUnicodeLowSurrogateStart 0xDC00 | ||
34 | #define kUnicodeLowSurrogateEnd 0xDFFF | ||
35 | #define kUnicodeLowSurrogateMask kUnicodeLowSurrogateStart | ||
36 | #define kUnicodeSurrogateTypeMask 0xFC00 | ||
37 | #define UnicharIsHighSurrogate(c) ((c & kUnicodeSurrogateTypeMask) == kUnicodeHighSurrogateMask) | ||
38 | #define UnicharIsLowSurrogate(c) ((c & kUnicodeSurrogateTypeMask) == kUnicodeLowSurrogateMask) | ||
39 | #define ConvertSurrogatePairToUTF32(high, low) ((UInt32)((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)) | ||
40 | |||
41 | typedef enum { | ||
42 | kFontTableFormat4 = 4, | ||
43 | kFontTableFormat12 = 12, | ||
44 | } FontTableFormat; | ||
45 | |||
46 | typedef struct fontTable { | ||
47 | NSUInteger retainCount; | ||
48 | CFDataRef cmapTable; | ||
49 | FontTableFormat format; | ||
50 | union { | ||
51 | struct { | ||
52 | UInt16 segCountX2; | ||
53 | UInt16 *endCodes; | ||
54 | UInt16 *startCodes; | ||
55 | UInt16 *idDeltas; | ||
56 | UInt16 *idRangeOffsets; | ||
57 | } format4; | ||
58 | struct { | ||
59 | UInt32 nGroups; | ||
60 | struct { | ||
61 | UInt32 startCharCode; | ||
62 | UInt32 endCharCode; | ||
63 | UInt32 startGlyphCode; | ||
64 | } *groups; | ||
65 | } format12; | ||
66 | } cmap; | ||
67 | } fontTable; | ||
68 | |||
69 | static FontTableFormat supportedFormats[] = { kFontTableFormat4, kFontTableFormat12 }; | ||
70 | static size_t supportedFormatsCount = sizeof(supportedFormats) / sizeof(FontTableFormat); | ||
71 | |||
72 | static fontTable *newFontTable(CFDataRef cmapTable, FontTableFormat format) { | ||
73 | fontTable *table = (struct fontTable *)malloc(sizeof(struct fontTable)); | ||
74 | table->retainCount = 1; | ||
75 | table->cmapTable = CFRetain(cmapTable); | ||
76 | table->format = format; | ||
77 | return table; | ||
78 | } | ||
79 | |||
80 | static fontTable *retainFontTable(fontTable *table) { | ||
81 | if (table != NULL) { | ||
82 | table->retainCount++; | ||
83 | } | ||
84 | return table; | ||
85 | } | ||
86 | |||
87 | static void releaseFontTable(fontTable *table) { | ||
88 | if (table != NULL) { | ||
89 | if (table->retainCount <= 1) { | ||
90 | CFRelease(table->cmapTable); | ||
91 | free(table); | ||
92 | } else { | ||
93 | table->retainCount--; | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | |||
98 | static const void *fontTableRetainCallback(CFAllocatorRef allocator, const void *value) { | ||
99 | return retainFontTable((fontTable *)value); | ||
100 | } | ||
101 | |||
102 | static void fontTableReleaseCallback(CFAllocatorRef allocator, const void *value) { | ||
103 | releaseFontTable((fontTable *)value); | ||
104 | } | ||
105 | |||
106 | static const CFDictionaryValueCallBacks kFontTableDictionaryValueCallBacks = { | ||
107 | .version = 0, | ||
108 | .retain = &fontTableRetainCallback, | ||
109 | .release = &fontTableReleaseCallback, | ||
110 | .copyDescription = NULL, | ||
111 | .equal = NULL | ||
112 | }; | ||
113 | |||
114 | // read the cmap table from the font | ||
115 | // we only know how to understand some of the table formats at the moment | ||
116 | static fontTable *readFontTableFromCGFont(CGFontRef font) { | ||
117 | CFDataRef cmapTable = CGFontCopyTableForTag(font, 'cmap'); | ||
118 | NSCAssert1(cmapTable != NULL, @"CGFontCopyTableForTag returned NULL for 'cmap' tag in font %@", | ||
119 | (font ? [(id)CFCopyDescription(font) autorelease] : @"(null)")); | ||
120 | const UInt8 * const bytes = CFDataGetBytePtr(cmapTable); | ||
121 | NSCAssert1(OSReadBigInt16(bytes, 0) == 0, @"cmap table for font %@ has bad version number", | ||
122 | (font ? [(id)CFCopyDescription(font) autorelease] : @"(null)")); | ||
123 | UInt16 numberOfSubtables = OSReadBigInt16(bytes, 2); | ||
124 | const UInt8 *unicodeSubtable = NULL; | ||
125 | //UInt16 unicodeSubtablePlatformID; | ||
126 | UInt16 unicodeSubtablePlatformSpecificID; | ||
127 | FontTableFormat unicodeSubtableFormat; | ||
128 | const UInt8 * const encodingSubtables = &bytes[4]; | ||
129 | for (UInt16 i = 0; i < numberOfSubtables; i++) { | ||
130 | const UInt8 * const encodingSubtable = &encodingSubtables[8 * i]; | ||
131 | UInt16 platformID = OSReadBigInt16(encodingSubtable, 0); | ||
132 | UInt16 platformSpecificID = OSReadBigInt16(encodingSubtable, 2); | ||
133 | // find the best subtable | ||
134 | // best is defined by a combination of encoding and format | ||
135 | // At the moment we only support format 4, so ignore all other format tables | ||
136 | // We prefer platformID == 0, but we will also accept Microsoft's unicode format | ||
137 | if (platformID == 0 || (platformID == 3 && platformSpecificID == 1)) { | ||
138 | BOOL preferred = NO; | ||
139 | if (unicodeSubtable == NULL) { | ||
140 | preferred = YES; | ||
141 | } else if (platformID == 0 && platformSpecificID > unicodeSubtablePlatformSpecificID) { | ||
142 | preferred = YES; | ||
143 | } | ||
144 | if (preferred) { | ||
145 | UInt32 offset = OSReadBigInt32(encodingSubtable, 4); | ||
146 | const UInt8 *subtable = &bytes[offset]; | ||
147 | UInt16 format = OSReadBigInt16(subtable, 0); | ||
148 | for (size_t i = 0; i < supportedFormatsCount; i++) { | ||
149 | if (format == supportedFormats[i]) { | ||
150 | if (format >= 8) { | ||
151 | // the version is a fixed-point | ||
152 | UInt16 formatFrac = OSReadBigInt16(subtable, 2); | ||
153 | if (formatFrac != 0) { | ||
154 | // all the current formats with a Fixed version are always *.0 | ||
155 | continue; | ||
156 | } | ||
157 | } | ||
158 | unicodeSubtable = subtable; | ||
159 | //unicodeSubtablePlatformID = platformID; | ||
160 | unicodeSubtablePlatformSpecificID = platformSpecificID; | ||
161 | unicodeSubtableFormat = format; | ||
162 | break; | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | fontTable *table = NULL; | ||
169 | if (unicodeSubtable != NULL) { | ||
170 | table = newFontTable(cmapTable, unicodeSubtableFormat); | ||
171 | switch (unicodeSubtableFormat) { | ||
172 | case kFontTableFormat4: | ||
173 | // subtable format 4 | ||
174 | //UInt16 length = OSReadBigInt16(unicodeSubtable, 2); | ||
175 | //UInt16 language = OSReadBigInt16(unicodeSubtable, 4); | ||
176 | table->cmap.format4.segCountX2 = OSReadBigInt16(unicodeSubtable, 6); | ||
177 | //UInt16 searchRange = OSReadBigInt16(unicodeSubtable, 8); | ||
178 | //UInt16 entrySelector = OSReadBigInt16(unicodeSubtable, 10); | ||
179 | //UInt16 rangeShift = OSReadBigInt16(unicodeSubtable, 12); | ||
180 | table->cmap.format4.endCodes = (UInt16*)&unicodeSubtable[14]; | ||
181 | table->cmap.format4.startCodes = (UInt16*)&((UInt8*)table->cmap.format4.endCodes)[table->cmap.format4.segCountX2+2]; | ||
182 | table->cmap.format4.idDeltas = (UInt16*)&((UInt8*)table->cmap.format4.startCodes)[table->cmap.format4.segCountX2]; | ||
183 | table->cmap.format4.idRangeOffsets = (UInt16*)&((UInt8*)table->cmap.format4.idDeltas)[table->cmap.format4.segCountX2]; | ||
184 | //UInt16 *glyphIndexArray = &idRangeOffsets[segCountX2]; | ||
185 | break; | ||
186 | case kFontTableFormat12: | ||
187 | table->cmap.format12.nGroups = OSReadBigInt32(unicodeSubtable, 12); | ||
188 | table->cmap.format12.groups = (void *)&unicodeSubtable[16]; | ||
189 | break; | ||
190 | default: | ||
191 | releaseFontTable(table); | ||
192 | table = NULL; | ||
193 | } | ||
194 | } | ||
195 | CFRelease(cmapTable); | ||
196 | return table; | ||
197 | } | ||
198 | |||
199 | // outGlyphs must be at least size n | ||
200 | static void mapCharactersToGlyphsInFont(const fontTable *table, unichar characters[], size_t charLen, CGGlyph outGlyphs[], size_t *outGlyphLen) { | ||
201 | if (table != NULL) { | ||
202 | NSUInteger j = 0; | ||
203 | switch (table->format) { | ||
204 | case kFontTableFormat4: { | ||
205 | for (NSUInteger i = 0; i < charLen; i++, j++) { | ||
206 | unichar c = characters[i]; | ||
207 | UInt16 segOffset; | ||
208 | BOOL foundSegment = NO; | ||
209 | for (segOffset = 0; segOffset < table->cmap.format4.segCountX2; segOffset += 2) { | ||
210 | UInt16 endCode = OSReadBigInt16(table->cmap.format4.endCodes, segOffset); | ||
211 | if (endCode >= c) { | ||
212 | foundSegment = YES; | ||
213 | break; | ||
214 | } | ||
215 | } | ||
216 | if (!foundSegment) { | ||
217 | // no segment | ||
218 | // this is an invalid font | ||
219 | outGlyphs[j] = 0; | ||
220 | } else { | ||
221 | UInt16 startCode = OSReadBigInt16(table->cmap.format4.startCodes, segOffset); | ||
222 | if (!(startCode <= c)) { | ||
223 | // the code falls in a hole between segments | ||
224 | outGlyphs[j] = 0; | ||
225 | } else { | ||
226 | UInt16 idRangeOffset = OSReadBigInt16(table->cmap.format4.idRangeOffsets, segOffset); | ||
227 | if (idRangeOffset == 0) { | ||
228 | UInt16 idDelta = OSReadBigInt16(table->cmap.format4.idDeltas, segOffset); | ||
229 | outGlyphs[j] = (c + idDelta) % 65536; | ||
230 | } else { | ||
231 | // use the glyphIndexArray | ||
232 | UInt16 glyphOffset = idRangeOffset + 2 * (c - startCode); | ||
233 | outGlyphs[j] = OSReadBigInt16(&((UInt8*)table->cmap.format4.idRangeOffsets)[segOffset], glyphOffset); | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | break; | ||
239 | } | ||
240 | case kFontTableFormat12: { | ||
241 | UInt32 lastSegment = UINT32_MAX; | ||
242 | for (NSUInteger i = 0; i < charLen; i++, j++) { | ||
243 | unichar c = characters[i]; | ||
244 | UInt32 c32 = c; | ||
245 | if (UnicharIsHighSurrogate(c)) { | ||
246 | if (i+1 < charLen) { // do we have another character after this one? | ||
247 | unichar cc = characters[i+1]; | ||
248 | if (UnicharIsLowSurrogate(cc)) { | ||
249 | c32 = ConvertSurrogatePairToUTF32(c, cc); | ||
250 | i++; | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | // Start the heuristic search | ||
255 | // If this is an ASCII char, just do a linear search | ||
256 | // Otherwise do a hinted, modified binary search | ||
257 | // Start the first pivot at the last range found | ||
258 | // And when moving the pivot, limit the movement by increasing | ||
259 | // powers of two. This should help with locality | ||
260 | __typeof__(table->cmap.format12.groups[0]) *foundGroup = NULL; | ||
261 | if (c32 <= 0x7F) { | ||
262 | // ASCII | ||
263 | for (UInt32 idx = 0; idx < table->cmap.format12.nGroups; idx++) { | ||
264 | __typeof__(table->cmap.format12.groups[idx]) *group = &table->cmap.format12.groups[idx]; | ||
265 | if (c32 < OSSwapBigToHostInt32(group->startCharCode)) { | ||
266 | // we've fallen into a hole | ||
267 | break; | ||
268 | } else if (c32 <= OSSwapBigToHostInt32(group->endCharCode)) { | ||
269 | // this is the range | ||
270 | foundGroup = group; | ||
271 | break; | ||
272 | } | ||
273 | } | ||
274 | } else { | ||
275 | // heuristic search | ||
276 | UInt32 maxJump = (lastSegment == UINT32_MAX ? UINT32_MAX / 2 : 8); | ||
277 | UInt32 lowIdx = 0, highIdx = table->cmap.format12.nGroups; // highIdx is the first invalid idx | ||
278 | UInt32 pivot = (lastSegment == UINT32_MAX ? lowIdx + (highIdx - lowIdx) / 2 : lastSegment); | ||
279 | while (highIdx > lowIdx) { | ||
280 | __typeof__(table->cmap.format12.groups[pivot]) *group = &table->cmap.format12.groups[pivot]; | ||
281 | if (c32 < OSSwapBigToHostInt32(group->startCharCode)) { | ||
282 | highIdx = pivot; | ||
283 | } else if (c32 > OSSwapBigToHostInt32(group->endCharCode)) { | ||
284 | lowIdx = pivot + 1; | ||
285 | } else { | ||
286 | // we've hit the range | ||
287 | foundGroup = group; | ||
288 | break; | ||
289 | } | ||
290 | if (highIdx - lowIdx > maxJump * 2) { | ||
291 | if (highIdx == pivot) { | ||
292 | pivot -= maxJump; | ||
293 | } else { | ||
294 | pivot += maxJump; | ||
295 | } | ||
296 | maxJump *= 2; | ||
297 | } else { | ||
298 | pivot = lowIdx + (highIdx - lowIdx) / 2; | ||
299 | } | ||
300 | } | ||
301 | if (foundGroup != NULL) lastSegment = pivot; | ||
302 | } | ||
303 | if (foundGroup == NULL) { | ||
304 | outGlyphs[j] = 0; | ||
305 | } else { | ||
306 | outGlyphs[j] = (CGGlyph)(OSSwapBigToHostInt32(foundGroup->startGlyphCode) + | ||
307 | (c32 - OSSwapBigToHostInt32(foundGroup->startCharCode))); | ||
308 | } | ||
309 | } | ||
310 | break; | ||
311 | } | ||
312 | } | ||
313 | if (outGlyphLen != NULL) *outGlyphLen = j; | ||
314 | } else { | ||
315 | // we have no table, so just null out the glyphs | ||
316 | bzero(outGlyphs, charLen*sizeof(CGGlyph)); | ||
317 | if (outGlyphLen != NULL) *outGlyphLen = 0; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | static BOOL mapGlyphsToAdvancesInFont(ZFont *font, size_t n, CGGlyph glyphs[], CGFloat outAdvances[]) { | ||
322 | int advances[n]; | ||
323 | if (CGFontGetGlyphAdvances(font.cgFont, glyphs, n, advances)) { | ||
324 | CGFloat ratio = font.ratio; | ||
325 | |||
326 | for (size_t i = 0; i < n; i++) { | ||
327 | outAdvances[i] = advances[i]*ratio; | ||
328 | } | ||
329 | return YES; | ||
330 | } else { | ||
331 | bzero(outAdvances, n*sizeof(CGFloat)); | ||
332 | } | ||
333 | return NO; | ||
334 | } | ||
335 | |||
336 | static id getValueOrDefaultForRun(ZAttributeRun *run, NSString *key) { | ||
337 | id value = [run.attributes objectForKey:key]; | ||
338 | if (value == nil) { | ||
339 | static NSDictionary *defaultValues = nil; | ||
340 | if (defaultValues == nil) { | ||
341 | defaultValues = [[NSDictionary alloc] initWithObjectsAndKeys: | ||
342 | [ZFont fontWithUIFont:[UIFont systemFontOfSize:12]], ZFontAttributeName, | ||
343 | [UIColor blackColor], ZForegroundColorAttributeName, | ||
344 | [UIColor clearColor], ZBackgroundColorAttributeName, | ||
345 | [NSNumber numberWithInt:ZUnderlineStyleNone], ZUnderlineStyleAttributeName, | ||
346 | nil]; | ||
347 | } | ||
348 | value = [defaultValues objectForKey:key]; | ||
349 | } | ||
350 | return value; | ||
351 | } | ||
352 | |||
353 | static void readRunInformation(NSArray *attributes, NSUInteger len, CFMutableDictionaryRef fontTableMap, | ||
354 | NSUInteger index, ZAttributeRun **currentRun, NSUInteger *nextRunStart, | ||
355 | ZFont **currentFont, fontTable **currentTable) { | ||
356 | *currentRun = [attributes objectAtIndex:index]; | ||
357 | *nextRunStart = ([attributes count] > index+1 ? [[attributes objectAtIndex:index+1] index] : len); | ||
358 | *currentFont = getValueOrDefaultForRun(*currentRun, ZFontAttributeName); | ||
359 | if (!CFDictionaryGetValueIfPresent(fontTableMap, (*currentFont).cgFont, (const void **)currentTable)) { | ||
360 | *currentTable = readFontTableFromCGFont((*currentFont).cgFont); | ||
361 | CFDictionarySetValue(fontTableMap, (*currentFont).cgFont, *currentTable); | ||
362 | releaseFontTable(*currentTable); | ||
363 | } | ||
364 | } | ||
365 | |||
366 | static CGSize drawOrSizeTextConstrainedToSize(BOOL performDraw, NSString *string, NSArray *attributes, CGSize constrainedSize, NSUInteger maxLines, | ||
367 | UILineBreakMode lineBreakMode, UITextAlignment alignment, BOOL ignoreColor) { | ||
368 | NSUInteger len = [string length]; | ||
369 | NSUInteger idx = 0; | ||
370 | CGPoint drawPoint = CGPointZero; | ||
371 | CGSize retValue = CGSizeZero; | ||
372 | CGContextRef ctx = (performDraw ? UIGraphicsGetCurrentContext() : NULL); | ||
373 | |||
374 | BOOL convertNewlines = (maxLines == 1); | ||
375 | |||
376 | // Extract the characters from the string | ||
377 | // Convert newlines to spaces if necessary | ||
378 | unichar *characters = (unichar *)malloc(sizeof(unichar) * len); | ||
379 | if (convertNewlines) { | ||
380 | NSCharacterSet *charset = [NSCharacterSet newlineCharacterSet]; | ||
381 | NSRange range = NSMakeRange(0, len); | ||
382 | size_t cIdx = 0; | ||
383 | while (range.length > 0) { | ||
384 | NSRange newlineRange = [string rangeOfCharacterFromSet:charset options:0 range:range]; | ||
385 | if (newlineRange.location == NSNotFound) { | ||
386 | [string getCharacters:&characters[cIdx] range:range]; | ||
387 | cIdx += range.length; | ||
388 | break; | ||
389 | } else { | ||
390 | NSUInteger delta = newlineRange.location - range.location; | ||
391 | if (newlineRange.location > range.location) { | ||
392 | [string getCharacters:&characters[cIdx] range:NSMakeRange(range.location, delta)]; | ||
393 | } | ||
394 | cIdx += delta; | ||
395 | characters[cIdx] = (unichar)' '; | ||
396 | cIdx++; | ||
397 | delta += newlineRange.length; | ||
398 | range.location += delta, range.length -= delta; | ||
399 | if (newlineRange.length == 1 && range.length >= 1 && | ||
400 | [string characterAtIndex:newlineRange.location] == (unichar)'\r' && | ||
401 | [string characterAtIndex:range.location] == (unichar)'\n') { | ||
402 | // CRLF sequence, skip the LF | ||
403 | range.location += 1, range.length -= 1; | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | len = cIdx; | ||
408 | } else { | ||
409 | [string getCharacters:characters range:NSMakeRange(0, len)]; | ||
410 | } | ||
411 | |||
412 | // Create storage for glyphs and advances | ||
413 | CGGlyph *glyphs; | ||
414 | CGFloat *advances; | ||
415 | { | ||
416 | NSUInteger maxRunLength = 0; | ||
417 | ZAttributeRun *a = [attributes objectAtIndex:0]; | ||
418 | for (NSUInteger i = 1; i < [attributes count]; i++) { | ||
419 | ZAttributeRun *b = [attributes objectAtIndex:i]; | ||
420 | maxRunLength = MAX(maxRunLength, b.index - a.index); | ||
421 | a = b; | ||
422 | } | ||
423 | maxRunLength = MAX(maxRunLength, len - a.index); | ||
424 | maxRunLength++; // for a potential ellipsis | ||
425 | glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * maxRunLength); | ||
426 | advances = (CGFloat *)malloc(sizeof(CGFloat) * maxRunLength); | ||
427 | } | ||
428 | |||
429 | // Use this table to cache all fontTable objects | ||
430 | CFMutableDictionaryRef fontTableMap = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, | ||
431 | &kFontTableDictionaryValueCallBacks); | ||
432 | |||
433 | // Fetch initial style values | ||
434 | NSUInteger currentRunIdx = 0; | ||
435 | ZAttributeRun *currentRun; | ||
436 | NSUInteger nextRunStart; | ||
437 | ZFont *currentFont; | ||
438 | fontTable *currentTable; | ||
439 | |||
440 | #define READ_RUN() readRunInformation(attributes, len, fontTableMap, \ | ||
441 | currentRunIdx, ¤tRun, &nextRunStart, \ | ||
442 | ¤tFont, ¤tTable) | ||
443 | |||
444 | READ_RUN(); | ||
445 | |||
446 | // fetch the glyphs for the first run | ||
447 | size_t glyphCount; | ||
448 | NSUInteger glyphIdx; | ||
449 | |||
450 | #define READ_GLYPHS() do { \ | ||
451 | mapCharactersToGlyphsInFont(currentTable, &characters[currentRun.index], (nextRunStart - currentRun.index), glyphs, &glyphCount); \ | ||
452 | mapGlyphsToAdvancesInFont(currentFont, (nextRunStart - currentRun.index), glyphs, advances); \ | ||
453 | glyphIdx = 0; \ | ||
454 | } while (0) | ||
455 | |||
456 | READ_GLYPHS(); | ||
457 | |||
458 | NSMutableCharacterSet *alphaCharset = [NSMutableCharacterSet alphanumericCharacterSet]; | ||
459 | [alphaCharset addCharactersInString:@"([{'\"\u2019\u02BC"]; | ||
460 | |||
461 | // scan left-to-right looking for newlines or until we hit the width constraint | ||
462 | // When we hit a wrapping point, calculate truncation as follows: | ||
463 | // If we have room to draw at least one more character on the next line, no truncation | ||
464 | // Otherwise apply the truncation algorithm to the current line. | ||
465 | // After calculating any truncation, draw. | ||
466 | // Each time we hit the end of an attribute run, calculate the new font and make sure | ||
467 | // it fits (vertically) within the size constraint. If not, truncate this line. | ||
468 | // When we draw, iterate over the attribute runs for this line and draw each run separately | ||
469 | BOOL lastLine = NO; // used to indicate truncation and to stop the iterating | ||
470 | NSUInteger lineCount = 1; | ||
471 | while (idx < len && !lastLine) { | ||
472 | if (maxLines > 0 && lineCount == maxLines) { | ||
473 | lastLine = YES; | ||
474 | } | ||
475 | // scan left-to-right | ||
476 | struct { | ||
477 | NSUInteger index; | ||
478 | NSUInteger glyphIndex; | ||
479 | NSUInteger currentRunIdx; | ||
480 | } indexCache = { idx, glyphIdx, currentRunIdx }; | ||
481 | CGSize lineSize = CGSizeMake(0, currentFont.leading); | ||
482 | CGFloat lineAscender = currentFont.ascender; | ||
483 | struct { | ||
484 | NSUInteger index; | ||
485 | NSUInteger glyphIndex; | ||
486 | NSUInteger currentRunIdx; | ||
487 | CGSize lineSize; | ||
488 | } lastWrapCache = {0, 0, 0, CGSizeZero}; | ||
489 | BOOL inAlpha = NO; // used for calculating wrap points | ||
490 | |||
491 | BOOL finishLine = NO; | ||
492 | for (;idx <= len && !finishLine;) { | ||
493 | NSUInteger skipCount = 0; | ||
494 | if (idx == len) { | ||
495 | finishLine = YES; | ||
496 | lastLine = YES; | ||
497 | } else { | ||
498 | if (idx >= nextRunStart) { | ||
499 | // cycle the font and table and grab the next set of glyphs | ||
500 | do { | ||
501 | currentRunIdx++; | ||
502 | READ_RUN(); | ||
503 | } while (idx >= nextRunStart); | ||
504 | READ_GLYPHS(); | ||
505 | // re-scan the characters to synchronize the glyph index | ||
506 | for (NSUInteger j = currentRun.index; j < idx; j++) { | ||
507 | if (UnicharIsHighSurrogate(characters[j]) && j+1<len && UnicharIsLowSurrogate(characters[j+1])) { | ||
508 | j++; | ||
509 | } | ||
510 | glyphIdx++; | ||
511 | } | ||
512 | if (currentFont.leading > lineSize.height) { | ||
513 | lineSize.height = currentFont.leading; | ||
514 | if (retValue.height + currentFont.ascender > constrainedSize.height) { | ||
515 | lastLine = YES; | ||
516 | finishLine = YES; | ||
517 | } | ||
518 | } | ||
519 | lineAscender = MAX(lineAscender, currentFont.ascender); | ||
520 | } | ||
521 | unichar c = characters[idx]; | ||
522 | // Mark a wrap point before spaces and after any stretch of non-alpha characters | ||
523 | BOOL markWrap = NO; | ||
524 | if (c == (unichar)' ') { | ||
525 | markWrap = YES; | ||
526 | } else if ([alphaCharset characterIsMember:c]) { | ||
527 | if (!inAlpha) { | ||
528 | markWrap = YES; | ||
529 | inAlpha = YES; | ||
530 | } | ||
531 | } else { | ||
532 | inAlpha = NO; | ||
533 | } | ||
534 | if (markWrap) { | ||
535 | lastWrapCache = (__typeof__(lastWrapCache)){ | ||
536 | .index = idx, | ||
537 | .glyphIndex = glyphIdx, | ||
538 | .currentRunIdx = currentRunIdx, | ||
539 | .lineSize = lineSize | ||
540 | }; | ||
541 | } | ||
542 | // process the line | ||
543 | if (c == (unichar)'\n' || c == 0x0085) { // U+0085 is the NEXT_LINE unicode character | ||
544 | finishLine = YES; | ||
545 | skipCount = 1; | ||
546 | } else if (c == (unichar)'\r') { | ||
547 | finishLine = YES; | ||
548 | // check for CRLF | ||
549 | if (idx+1 < len && characters[idx+1] == (unichar)'\n') { | ||
550 | skipCount = 2; | ||
551 | } else { | ||
552 | skipCount = 1; | ||
553 | } | ||
554 | } else if (lineSize.width + advances[glyphIdx] > constrainedSize.width) { | ||
555 | finishLine = YES; | ||
556 | if (retValue.height + lineSize.height + currentFont.ascender > constrainedSize.height) { | ||
557 | lastLine = YES; | ||
558 | } | ||
559 | // walk backwards if wrapping is necessary | ||
560 | if (lastWrapCache.index > indexCache.index && lineBreakMode != UILineBreakModeCharacterWrap && | ||
561 | (!lastLine || lineBreakMode != UILineBreakModeClip)) { | ||
562 | // we're doing some sort of word wrapping | ||
563 | idx = lastWrapCache.index; | ||
564 | lineSize = lastWrapCache.lineSize; | ||
565 | if (!lastLine) { | ||
566 | // re-check if this is the last line | ||
567 | if (lastWrapCache.currentRunIdx != currentRunIdx) { | ||
568 | currentRunIdx = lastWrapCache.currentRunIdx; | ||
569 | READ_RUN(); | ||
570 | READ_GLYPHS(); | ||
571 | } | ||
572 | if (retValue.height + lineSize.height + currentFont.ascender > constrainedSize.height) { | ||
573 | lastLine = YES; | ||
574 | } | ||
575 | } | ||
576 | glyphIdx = lastWrapCache.glyphIndex; | ||
577 | // skip any spaces | ||
578 | for (NSUInteger j = idx; j < len && characters[j] == (unichar)' '; j++) { | ||
579 | skipCount++; | ||
580 | } | ||
581 | } | ||
582 | } | ||
583 | } | ||
584 | if (finishLine) { | ||
585 | // TODO: support head/middle truncation | ||
586 | if (lastLine && idx < len && lineBreakMode == UILineBreakModeTailTruncation) { | ||
587 | // truncate | ||
588 | unichar ellipsis = 0x2026; // ellipsis (…) | ||
589 | CGGlyph ellipsisGlyph; | ||
590 | mapCharactersToGlyphsInFont(currentTable, &ellipsis, 1, &ellipsisGlyph, NULL); | ||
591 | CGFloat ellipsisWidth; | ||
592 | mapGlyphsToAdvancesInFont(currentFont, 1, &ellipsisGlyph, &ellipsisWidth); | ||
593 | while ((idx - indexCache.index) > 1 && lineSize.width + ellipsisWidth > constrainedSize.width) { | ||
594 | // we have more than 1 character and we're too wide, so back up | ||
595 | idx--; | ||
596 | if (UnicharIsHighSurrogate(characters[idx]) && UnicharIsLowSurrogate(characters[idx+1])) { | ||
597 | idx--; | ||
598 | } | ||
599 | if (idx < currentRun.index) { | ||
600 | ZFont *oldFont = currentFont; | ||
601 | do { | ||
602 | currentRunIdx--; | ||
603 | READ_RUN(); | ||
604 | } while (idx < currentRun.index); | ||
605 | READ_GLYPHS(); | ||
606 | glyphIdx = glyphCount-1; | ||
607 | if (oldFont != currentFont) { | ||
608 | mapCharactersToGlyphsInFont(currentTable, &ellipsis, 1, &ellipsisGlyph, NULL); | ||
609 | mapGlyphsToAdvancesInFont(currentFont, 1, &ellipsisGlyph, &ellipsisWidth); | ||
610 | } | ||
611 | } else { | ||
612 | glyphIdx--; | ||
613 | } | ||
614 | lineSize.width -= advances[glyphIdx]; | ||
615 | } | ||
616 | // skip any spaces before truncating | ||
617 | while ((idx - indexCache.index) > 1 && characters[idx-1] == (unichar)' ') { | ||
618 | idx--; | ||
619 | if (idx < currentRun.index) { | ||
620 | currentRunIdx--; | ||
621 | READ_RUN(); | ||
622 | READ_GLYPHS(); | ||
623 | glyphIdx = glyphCount-1; | ||
624 | } else { | ||
625 | glyphIdx--; | ||
626 | } | ||
627 | lineSize.width -= advances[glyphIdx]; | ||
628 | } | ||
629 | lineSize.width += ellipsisWidth; | ||
630 | glyphs[glyphIdx] = ellipsisGlyph; | ||
631 | idx++; | ||
632 | glyphIdx++; | ||
633 | } | ||
634 | retValue.width = MAX(retValue.width, lineSize.width); | ||
635 | retValue.height += lineSize.height; | ||
636 | |||
637 | // draw | ||
638 | if (performDraw) { | ||
639 | switch (alignment) { | ||
640 | case UITextAlignmentLeft: | ||
641 | drawPoint.x = 0; | ||
642 | break; | ||
643 | case UITextAlignmentCenter: | ||
644 | drawPoint.x = (constrainedSize.width - lineSize.width) / 2.0f; | ||
645 | break; | ||
646 | case UITextAlignmentRight: | ||
647 | drawPoint.x = constrainedSize.width - lineSize.width; | ||
648 | break; | ||
649 | } | ||
650 | NSUInteger stopGlyphIdx = glyphIdx; | ||
651 | NSUInteger lastRunIdx = currentRunIdx; | ||
652 | NSUInteger stopCharIdx = idx; | ||
653 | idx = indexCache.index; | ||
654 | if (currentRunIdx != indexCache.currentRunIdx) { | ||
655 | currentRunIdx = indexCache.currentRunIdx; | ||
656 | READ_RUN(); | ||
657 | READ_GLYPHS(); | ||
658 | } | ||
659 | glyphIdx = indexCache.glyphIndex; | ||
660 | for (NSUInteger drawIdx = currentRunIdx; drawIdx <= lastRunIdx; drawIdx++) { | ||
661 | if (drawIdx != currentRunIdx) { | ||
662 | currentRunIdx = drawIdx; | ||
663 | READ_RUN(); | ||
664 | READ_GLYPHS(); | ||
665 | } | ||
666 | NSUInteger numGlyphs; | ||
667 | if (drawIdx == lastRunIdx) { | ||
668 | numGlyphs = stopGlyphIdx - glyphIdx; | ||
669 | idx = stopCharIdx; | ||
670 | } else { | ||
671 | numGlyphs = glyphCount - glyphIdx; | ||
672 | idx = nextRunStart; | ||
673 | } | ||
674 | CGContextSetFont(ctx, currentFont.cgFont); | ||
675 | CGContextSetFontSize(ctx, currentFont.pointSize); | ||
676 | // calculate the fragment size | ||
677 | CGFloat fragmentWidth = 0; | ||
678 | for (NSUInteger g = 0; g < numGlyphs; g++) { | ||
679 | fragmentWidth += advances[glyphIdx + g]; | ||
680 | } | ||
681 | |||
682 | if (!ignoreColor) { | ||
683 | UIColor *foregroundColor = getValueOrDefaultForRun(currentRun, ZForegroundColorAttributeName); | ||
684 | UIColor *backgroundColor = getValueOrDefaultForRun(currentRun, ZBackgroundColorAttributeName); | ||
685 | if (backgroundColor != nil && ![backgroundColor isEqual:[UIColor clearColor]]) { | ||
686 | [backgroundColor setFill]; | ||
687 | UIRectFillUsingBlendMode((CGRect){ drawPoint, { fragmentWidth, lineSize.height } }, kCGBlendModeNormal); | ||
688 | } | ||
689 | [foregroundColor setFill]; | ||
690 | } | ||
691 | |||
692 | CGContextShowGlyphsAtPoint(ctx, drawPoint.x, drawPoint.y + lineAscender, &glyphs[glyphIdx], numGlyphs); | ||
693 | NSNumber *underlineStyle = getValueOrDefaultForRun(currentRun, ZUnderlineStyleAttributeName); | ||
694 | if ([underlineStyle integerValue] & ZUnderlineStyleMask) { | ||
695 | // we only support single for the time being | ||
696 | UIRectFill(CGRectMake(drawPoint.x, drawPoint.y + lineAscender, fragmentWidth, 1)); | ||
697 | } | ||
698 | drawPoint.x += fragmentWidth; | ||
699 | glyphIdx += numGlyphs; | ||
700 | } | ||
701 | drawPoint.y += lineSize.height; | ||
702 | } | ||
703 | idx += skipCount; | ||
704 | glyphIdx += skipCount; | ||
705 | lineCount++; | ||
706 | } else { | ||
707 | lineSize.width += advances[glyphIdx]; | ||
708 | glyphIdx++; | ||
709 | idx++; | ||
710 | if (idx < len && UnicharIsHighSurrogate(characters[idx-1]) && UnicharIsLowSurrogate(characters[idx])) { | ||
711 | // skip the second half of the surrogate pair | ||
712 | idx++; | ||
713 | } | ||
714 | } | ||
715 | } | ||
716 | } | ||
717 | CFRelease(fontTableMap); | ||
718 | free(glyphs); | ||
719 | free(advances); | ||
720 | free(characters); | ||
721 | |||
722 | #undef READ_GLYPHS | ||
723 | #undef READ_RUN | ||
724 | |||
725 | return retValue; | ||
726 | } | ||
727 | |||
728 | static NSArray *attributeRunForFont(ZFont *font) { | ||
729 | return [NSArray arrayWithObject:[ZAttributeRun attributeRunWithIndex:0 | ||
730 | attributes:[NSDictionary dictionaryWithObject:font | ||
731 | forKey:ZFontAttributeName]]]; | ||
732 | } | ||
733 | |||
734 | static CGSize drawTextInRect(CGRect rect, NSString *text, NSArray *attributes, UILineBreakMode lineBreakMode, | ||
735 | UITextAlignment alignment, NSUInteger numberOfLines, BOOL ignoreColor) { | ||
736 | CGContextRef ctx = UIGraphicsGetCurrentContext(); | ||
737 | |||
738 | CGContextSaveGState(ctx); | ||
739 | |||
740 | // flip it upside-down because our 0,0 is upper-left, whereas ttfs are for screens where 0,0 is lower-left | ||
741 | CGAffineTransform textTransform = CGAffineTransformMake(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f); | ||
742 | CGContextSetTextMatrix(ctx, textTransform); | ||
743 | |||
744 | CGContextTranslateCTM(ctx, rect.origin.x, rect.origin.y); | ||
745 | |||
746 | CGContextSetTextDrawingMode(ctx, kCGTextFill); | ||
747 | CGSize size = drawOrSizeTextConstrainedToSize(YES, text, attributes, rect.size, numberOfLines, lineBreakMode, alignment, ignoreColor); | ||
748 | |||
749 | CGContextRestoreGState(ctx); | ||
750 | |||
751 | return size; | ||
752 | } | ||
753 | |||
754 | @implementation NSString (FontLabelStringDrawing) | ||
755 | // CGFontRef-based methods | ||
756 | - (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize { | ||
757 | return [self sizeWithZFont:[ZFont fontWithCGFont:font size:pointSize]]; | ||
758 | } | ||
759 | |||
760 | - (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size { | ||
761 | return [self sizeWithZFont:[ZFont fontWithCGFont:font size:pointSize] constrainedToSize:size]; | ||
762 | } | ||
763 | |||
764 | - (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size | ||
765 | lineBreakMode:(UILineBreakMode)lineBreakMode { | ||
766 | return [self sizeWithZFont:[ZFont fontWithCGFont:font size:pointSize] constrainedToSize:size lineBreakMode:lineBreakMode]; | ||
767 | } | ||
768 | |||
769 | - (CGSize)drawAtPoint:(CGPoint)point withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize { | ||
770 | return [self drawAtPoint:point withZFont:[ZFont fontWithCGFont:font size:pointSize]]; | ||
771 | } | ||
772 | |||
773 | - (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize { | ||
774 | return [self drawInRect:rect withZFont:[ZFont fontWithCGFont:font size:pointSize]]; | ||
775 | } | ||
776 | |||
777 | - (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize lineBreakMode:(UILineBreakMode)lineBreakMode { | ||
778 | return [self drawInRect:rect withZFont:[ZFont fontWithCGFont:font size:pointSize] lineBreakMode:lineBreakMode]; | ||
779 | } | ||
780 | |||
781 | - (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize | ||
782 | lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment { | ||
783 | return [self drawInRect:rect withZFont:[ZFont fontWithCGFont:font size:pointSize] lineBreakMode:lineBreakMode alignment:alignment]; | ||
784 | } | ||
785 | |||
786 | // ZFont-based methods | ||
787 | - (CGSize)sizeWithZFont:(ZFont *)font { | ||
788 | CGSize size = drawOrSizeTextConstrainedToSize(NO, self, attributeRunForFont(font), CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX), 1, | ||
789 | UILineBreakModeClip, UITextAlignmentLeft, YES); | ||
790 | return CGSizeMake(ceilf(size.width), ceilf(size.height)); | ||
791 | } | ||
792 | |||
793 | - (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size { | ||
794 | return [self sizeWithZFont:font constrainedToSize:size lineBreakMode:UILineBreakModeWordWrap]; | ||
795 | } | ||
796 | |||
797 | /* | ||
798 | According to experimentation with UIStringDrawing, this can actually return a CGSize whose height is greater | ||
799 | than the one passed in. The two cases are as follows: | ||
800 | 1. If the given size parameter's height is smaller than a single line, the returned value will | ||
801 | be the height of one line. | ||
802 | 2. If the given size parameter's height falls between multiples of a line height, and the wrapped string | ||
803 | actually extends past the size.height, and the difference between size.height and the previous multiple | ||
804 | of a line height is >= the font's ascender, then the returned size's height is extended to the next line. | ||
805 | To put it simply, if the baseline point of a given line falls in the given size, the entire line will | ||
806 | be present in the output size. | ||
807 | */ | ||
808 | - (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode { | ||
809 | size = drawOrSizeTextConstrainedToSize(NO, self, attributeRunForFont(font), size, 0, lineBreakMode, UITextAlignmentLeft, YES); | ||
810 | return CGSizeMake(ceilf(size.width), ceilf(size.height)); | ||
811 | } | ||
812 | |||
813 | - (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode | ||
814 | numberOfLines:(NSUInteger)numberOfLines { | ||
815 | size = drawOrSizeTextConstrainedToSize(NO, self, attributeRunForFont(font), size, numberOfLines, lineBreakMode, UITextAlignmentLeft, YES); | ||
816 | return CGSizeMake(ceilf(size.width), ceilf(size.height)); | ||
817 | } | ||
818 | |||
819 | - (CGSize)drawAtPoint:(CGPoint)point withZFont:(ZFont *)font { | ||
820 | return [self drawAtPoint:point forWidth:CGFLOAT_MAX withZFont:font lineBreakMode:UILineBreakModeClip]; | ||
821 | } | ||
822 | |||
823 | - (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode { | ||
824 | return drawTextInRect((CGRect){ point, { width, CGFLOAT_MAX } }, self, attributeRunForFont(font), lineBreakMode, UITextAlignmentLeft, 1, YES); | ||
825 | } | ||
826 | |||
827 | - (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font { | ||
828 | return [self drawInRect:rect withZFont:font lineBreakMode:UILineBreakModeWordWrap]; | ||
829 | } | ||
830 | |||
831 | - (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode { | ||
832 | return [self drawInRect:rect withZFont:font lineBreakMode:lineBreakMode alignment:UITextAlignmentLeft]; | ||
833 | } | ||
834 | |||
835 | - (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode | ||
836 | alignment:(UITextAlignment)alignment { | ||
837 | return drawTextInRect(rect, self, attributeRunForFont(font), lineBreakMode, alignment, 0, YES); | ||
838 | } | ||
839 | |||
840 | - (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode | ||
841 | alignment:(UITextAlignment)alignment numberOfLines:(NSUInteger)numberOfLines { | ||
842 | return drawTextInRect(rect, self, attributeRunForFont(font), lineBreakMode, alignment, numberOfLines, YES); | ||
843 | } | ||
844 | @end | ||
845 | |||
846 | @implementation ZAttributedString (ZAttributedStringDrawing) | ||
847 | - (CGSize)size { | ||
848 | CGSize size = drawOrSizeTextConstrainedToSize(NO, self.string, self.attributes, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX), 1, | ||
849 | UILineBreakModeClip, UITextAlignmentLeft, NO); | ||
850 | return CGSizeMake(ceilf(size.width), ceilf(size.height)); | ||
851 | } | ||
852 | |||
853 | - (CGSize)sizeConstrainedToSize:(CGSize)size { | ||
854 | return [self sizeConstrainedToSize:size lineBreakMode:UILineBreakModeWordWrap]; | ||
855 | } | ||
856 | |||
857 | - (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode { | ||
858 | size = drawOrSizeTextConstrainedToSize(NO, self.string, self.attributes, size, 0, lineBreakMode, UITextAlignmentLeft, NO); | ||
859 | return CGSizeMake(ceilf(size.width), ceilf(size.height)); | ||
860 | } | ||
861 | |||
862 | - (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode | ||
863 | numberOfLines:(NSUInteger)numberOfLines { | ||
864 | size = drawOrSizeTextConstrainedToSize(NO, self.string, self.attributes, size, numberOfLines, lineBreakMode, UITextAlignmentLeft, NO); | ||
865 | return CGSizeMake(ceilf(size.width), ceilf(size.height)); | ||
866 | } | ||
867 | |||
868 | - (CGSize)drawAtPoint:(CGPoint)point { | ||
869 | return [self drawAtPoint:point forWidth:CGFLOAT_MAX lineBreakMode:UILineBreakModeClip]; | ||
870 | } | ||
871 | |||
872 | - (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode { | ||
873 | return drawTextInRect((CGRect){ point, { width, CGFLOAT_MAX } }, self.string, self.attributes, lineBreakMode, UITextAlignmentLeft, 1, NO); | ||
874 | } | ||
875 | |||
876 | - (CGSize)drawInRect:(CGRect)rect { | ||
877 | return [self drawInRect:rect withLineBreakMode:UILineBreakModeWordWrap]; | ||
878 | } | ||
879 | |||
880 | - (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode { | ||
881 | return [self drawInRect:rect withLineBreakMode:lineBreakMode alignment:UITextAlignmentLeft]; | ||
882 | } | ||
883 | |||
884 | - (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment { | ||
885 | return drawTextInRect(rect, self.string, self.attributes, lineBreakMode, alignment, 0, NO); | ||
886 | } | ||
887 | |||
888 | - (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment | ||
889 | numberOfLines:(NSUInteger)numberOfLines { | ||
890 | return drawTextInRect(rect, self.string, self.attributes, lineBreakMode, alignment, numberOfLines, NO); | ||
891 | } | ||
892 | @end | ||
diff --git a/libs/FontLabel/FontManager.h b/libs/FontLabel/FontManager.h new file mode 100755 index 0000000..1592b8a --- /dev/null +++ b/libs/FontLabel/FontManager.h | |||
@@ -0,0 +1,85 @@ | |||
1 | // | ||
2 | // FontManager.h | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 5/5/09. | ||
6 | // Copyright © 2009 Zynga Game Networks | ||
7 | // | ||
8 | // | ||
9 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
10 | // you may not use this file except in compliance with the License. | ||
11 | // You may obtain a copy of the License at | ||
12 | // | ||
13 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
14 | // | ||
15 | // Unless required by applicable law or agreed to in writing, software | ||
16 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
18 | // See the License for the specific language governing permissions and | ||
19 | // limitations under the License. | ||
20 | // | ||
21 | |||
22 | #import <Foundation/Foundation.h> | ||
23 | #import <CoreGraphics/CoreGraphics.h> | ||
24 | |||
25 | @class ZFont; | ||
26 | |||
27 | @interface FontManager : NSObject { | ||
28 | CFMutableDictionaryRef fonts; | ||
29 | NSMutableDictionary *urls; | ||
30 | } | ||
31 | + (FontManager *)sharedManager; | ||
32 | /*! | ||
33 | @method | ||
34 | @abstract Loads a TTF font from the main bundle | ||
35 | @param filename The name of the font file to load (with or without extension). | ||
36 | @return YES if the font was loaded, NO if an error occurred | ||
37 | @discussion If the font has already been loaded, this method does nothing and returns YES. | ||
38 | This method first attempts to load the font by appending .ttf to the filename. | ||
39 | If that file does not exist, it tries the filename exactly as given. | ||
40 | */ | ||
41 | - (BOOL)loadFont:(NSString *)filename; | ||
42 | /*! | ||
43 | @method | ||
44 | @abstract Loads a font from the given file URL | ||
45 | @param url A file URL that points to a font file | ||
46 | @return YES if the font was loaded, NO if an error occurred | ||
47 | @discussion If the font has already been loaded, this method does nothing and returns YES. | ||
48 | */ | ||
49 | - (BOOL)loadFontURL:(NSURL *)url; | ||
50 | /*! | ||
51 | @method | ||
52 | @abstract Returns the loaded font with the given filename | ||
53 | @param filename The name of the font file that was given to -loadFont: | ||
54 | @return A CGFontRef, or NULL if the specified font cannot be found | ||
55 | @discussion If the font has not been loaded yet, -loadFont: will be | ||
56 | called with the given name first. | ||
57 | */ | ||
58 | - (CGFontRef)fontWithName:(NSString *)filename __AVAILABILITY_INTERNAL_DEPRECATED; | ||
59 | /*! | ||
60 | @method | ||
61 | @abstract Returns a ZFont object corresponding to the loaded font with the given filename and point size | ||
62 | @param filename The name of the font file that was given to -loadFont: | ||
63 | @param pointSize The point size of the font | ||
64 | @return A ZFont, or NULL if the specified font cannot be found | ||
65 | @discussion If the font has not been loaded yet, -loadFont: will be | ||
66 | called with the given name first. | ||
67 | */ | ||
68 | - (ZFont *)zFontWithName:(NSString *)filename pointSize:(CGFloat)pointSize; | ||
69 | /*! | ||
70 | @method | ||
71 | @abstract Returns a ZFont object corresponding to the loaded font with the given file URL and point size | ||
72 | @param url A file URL that points to a font file | ||
73 | @param pointSize The point size of the font | ||
74 | @return A ZFont, or NULL if the specified font cannot be loaded | ||
75 | @discussion If the font has not been loaded yet, -loadFontURL: will be called with the given URL first. | ||
76 | */ | ||
77 | - (ZFont *)zFontWithURL:(NSURL *)url pointSize:(CGFloat)pointSize; | ||
78 | /*! | ||
79 | @method | ||
80 | @abstract Returns a CFArrayRef of all loaded CGFont objects | ||
81 | @return A CFArrayRef of all loaded CGFont objects | ||
82 | @description You are responsible for releasing the CFArrayRef | ||
83 | */ | ||
84 | - (CFArrayRef)copyAllFonts; | ||
85 | @end | ||
diff --git a/libs/FontLabel/FontManager.m b/libs/FontLabel/FontManager.m new file mode 100755 index 0000000..12eac2d --- /dev/null +++ b/libs/FontLabel/FontManager.m | |||
@@ -0,0 +1,123 @@ | |||
1 | // | ||
2 | // FontManager.m | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 5/5/09. | ||
6 | // Copyright © 2009 Zynga Game Networks | ||
7 | // | ||
8 | // | ||
9 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
10 | // you may not use this file except in compliance with the License. | ||
11 | // You may obtain a copy of the License at | ||
12 | // | ||
13 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
14 | // | ||
15 | // Unless required by applicable law or agreed to in writing, software | ||
16 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
18 | // See the License for the specific language governing permissions and | ||
19 | // limitations under the License. | ||
20 | // | ||
21 | |||
22 | #import "FontManager.h" | ||
23 | #import "ZFont.h" | ||
24 | |||
25 | static FontManager *sharedFontManager = nil; | ||
26 | |||
27 | @implementation FontManager | ||
28 | + (FontManager *)sharedManager { | ||
29 | @synchronized(self) { | ||
30 | if (sharedFontManager == nil) { | ||
31 | sharedFontManager = [[self alloc] init]; | ||
32 | } | ||
33 | } | ||
34 | return sharedFontManager; | ||
35 | } | ||
36 | |||
37 | - (id)init { | ||
38 | if ((self = [super init])) { | ||
39 | fonts = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | ||
40 | urls = [[NSMutableDictionary alloc] init]; | ||
41 | } | ||
42 | return self; | ||
43 | } | ||
44 | |||
45 | - (BOOL)loadFont:(NSString *)filename { | ||
46 | NSString *fontPath = [[NSBundle mainBundle] pathForResource:filename ofType:@"ttf"]; | ||
47 | if (fontPath == nil) { | ||
48 | fontPath = [[NSBundle mainBundle] pathForResource:filename ofType:nil]; | ||
49 | } | ||
50 | if (fontPath == nil) return NO; | ||
51 | |||
52 | NSURL *url = [NSURL fileURLWithPath:fontPath]; | ||
53 | if ([self loadFontURL:url]) { | ||
54 | [urls setObject:url forKey:filename]; | ||
55 | return YES; | ||
56 | } | ||
57 | return NO; | ||
58 | } | ||
59 | |||
60 | - (BOOL)loadFontURL:(NSURL *)url { | ||
61 | CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((CFURLRef)url); | ||
62 | if (fontDataProvider == NULL) return NO; | ||
63 | CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider); | ||
64 | CGDataProviderRelease(fontDataProvider); | ||
65 | if (newFont == NULL) return NO; | ||
66 | |||
67 | CFDictionarySetValue(fonts, url, newFont); | ||
68 | CGFontRelease(newFont); | ||
69 | return YES; | ||
70 | } | ||
71 | |||
72 | - (CGFontRef)fontWithName:(NSString *)filename { | ||
73 | CGFontRef font = NULL; | ||
74 | NSURL *url = [urls objectForKey:filename]; | ||
75 | if (url == nil && [self loadFont:filename]) { | ||
76 | url = [urls objectForKey:filename]; | ||
77 | } | ||
78 | if (url != nil) { | ||
79 | font = (CGFontRef)CFDictionaryGetValue(fonts, url); | ||
80 | } | ||
81 | return font; | ||
82 | } | ||
83 | |||
84 | - (ZFont *)zFontWithName:(NSString *)filename pointSize:(CGFloat)pointSize { | ||
85 | NSURL *url = [urls objectForKey:filename]; | ||
86 | if (url == nil && [self loadFont:filename]) { | ||
87 | url = [urls objectForKey:filename]; | ||
88 | } | ||
89 | if (url != nil) { | ||
90 | CGFontRef cgFont = (CGFontRef)CFDictionaryGetValue(fonts, url); | ||
91 | if (cgFont != NULL) { | ||
92 | return [ZFont fontWithCGFont:cgFont size:pointSize]; | ||
93 | } | ||
94 | } | ||
95 | return nil; | ||
96 | } | ||
97 | |||
98 | - (ZFont *)zFontWithURL:(NSURL *)url pointSize:(CGFloat)pointSize { | ||
99 | CGFontRef cgFont = (CGFontRef)CFDictionaryGetValue(fonts, url); | ||
100 | if (cgFont == NULL && [self loadFontURL:url]) { | ||
101 | cgFont = (CGFontRef)CFDictionaryGetValue(fonts, url); | ||
102 | } | ||
103 | if (cgFont != NULL) { | ||
104 | return [ZFont fontWithCGFont:cgFont size:pointSize]; | ||
105 | } | ||
106 | return nil; | ||
107 | } | ||
108 | |||
109 | - (CFArrayRef)copyAllFonts { | ||
110 | CFIndex count = CFDictionaryGetCount(fonts); | ||
111 | CGFontRef *values = (CGFontRef *)malloc(sizeof(CGFontRef) * count); | ||
112 | CFDictionaryGetKeysAndValues(fonts, NULL, (const void **)values); | ||
113 | CFArrayRef array = CFArrayCreate(NULL, (const void **)values, count, &kCFTypeArrayCallBacks); | ||
114 | free(values); | ||
115 | return array; | ||
116 | } | ||
117 | |||
118 | - (void)dealloc { | ||
119 | CFRelease(fonts); | ||
120 | [urls release]; | ||
121 | [super dealloc]; | ||
122 | } | ||
123 | @end | ||
diff --git a/libs/FontLabel/ZAttributedString.h b/libs/FontLabel/ZAttributedString.h new file mode 100755 index 0000000..e194c81 --- /dev/null +++ b/libs/FontLabel/ZAttributedString.h | |||
@@ -0,0 +1,77 @@ | |||
1 | // | ||
2 | // ZAttributedString.h | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 9/22/09. | ||
6 | // Copyright 2009 Zynga Game Networks. All rights reserved. | ||
7 | // | ||
8 | |||
9 | #import <Foundation/Foundation.h> | ||
10 | |||
11 | #if NS_BLOCKS_AVAILABLE | ||
12 | #define Z_BLOCKS 1 | ||
13 | #else | ||
14 | // set this to 1 if you are using PLBlocks | ||
15 | #define Z_BLOCKS 0 | ||
16 | #endif | ||
17 | |||
18 | #if Z_BLOCKS | ||
19 | enum { | ||
20 | ZAttributedStringEnumerationReverse = (1UL << 1), | ||
21 | ZAttributedStringEnumerationLongestEffectiveRangeNotRequired = (1UL << 20) | ||
22 | }; | ||
23 | typedef NSUInteger ZAttributedStringEnumerationOptions; | ||
24 | #endif | ||
25 | |||
26 | @interface ZAttributedString : NSObject <NSCoding, NSCopying, NSMutableCopying> { | ||
27 | NSMutableString *_buffer; | ||
28 | NSMutableArray *_attributes; | ||
29 | } | ||
30 | @property (nonatomic, readonly) NSUInteger length; | ||
31 | @property (nonatomic, readonly) NSString *string; | ||
32 | - (id)initWithAttributedString:(ZAttributedString *)attr; | ||
33 | - (id)initWithString:(NSString *)str; | ||
34 | - (id)initWithString:(NSString *)str attributes:(NSDictionary *)attributes; | ||
35 | - (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange; | ||
36 | - (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit; | ||
37 | - (ZAttributedString *)attributedSubstringFromRange:(NSRange)aRange; | ||
38 | - (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange; | ||
39 | - (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit; | ||
40 | #if Z_BLOCKS | ||
41 | - (void)enumerateAttribute:(NSString *)attrName inRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts | ||
42 | usingBlock:(void (^)(id value, NSRange range, BOOL *stop))block; | ||
43 | - (void)enumerateAttributesInRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts | ||
44 | usingBlock:(void (^)(NSDictionary *attrs, NSRange range, BOOL *stop))block; | ||
45 | #endif | ||
46 | - (BOOL)isEqualToAttributedString:(ZAttributedString *)otherString; | ||
47 | @end | ||
48 | |||
49 | @interface ZMutableAttributedString : ZAttributedString { | ||
50 | } | ||
51 | - (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range; | ||
52 | - (void)addAttributes:(NSDictionary *)attributes range:(NSRange)range; | ||
53 | - (void)appendAttributedString:(ZAttributedString *)str; | ||
54 | - (void)deleteCharactersInRange:(NSRange)range; | ||
55 | - (void)insertAttributedString:(ZAttributedString *)str atIndex:(NSUInteger)idx; | ||
56 | - (void)removeAttribute:(NSString *)name range:(NSRange)range; | ||
57 | - (void)replaceCharactersInRange:(NSRange)range withAttributedString:(ZAttributedString *)str; | ||
58 | - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str; | ||
59 | - (void)setAttributedString:(ZAttributedString *)str; | ||
60 | - (void)setAttributes:(NSDictionary *)attributes range:(NSRange)range; | ||
61 | @end | ||
62 | |||
63 | extern NSString * const ZFontAttributeName; | ||
64 | extern NSString * const ZForegroundColorAttributeName; | ||
65 | extern NSString * const ZBackgroundColorAttributeName; | ||
66 | extern NSString * const ZUnderlineStyleAttributeName; | ||
67 | |||
68 | enum { | ||
69 | ZUnderlineStyleNone = 0x00, | ||
70 | ZUnderlineStyleSingle = 0x01 | ||
71 | }; | ||
72 | #define ZUnderlineStyleMask 0x00FF | ||
73 | |||
74 | enum { | ||
75 | ZUnderlinePatternSolid = 0x0000 | ||
76 | }; | ||
77 | #define ZUnderlinePatternMask 0xFF00 | ||
diff --git a/libs/FontLabel/ZAttributedString.m b/libs/FontLabel/ZAttributedString.m new file mode 100755 index 0000000..a4163bc --- /dev/null +++ b/libs/FontLabel/ZAttributedString.m | |||
@@ -0,0 +1,597 @@ | |||
1 | // | ||
2 | // ZAttributedString.m | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 9/22/09. | ||
6 | // Copyright 2009 Zynga Game Networks. All rights reserved. | ||
7 | // | ||
8 | |||
9 | #import "ZAttributedString.h" | ||
10 | #import "ZAttributedStringPrivate.h" | ||
11 | |||
12 | @interface ZAttributedString () | ||
13 | - (NSUInteger)indexOfEffectiveAttributeRunForIndex:(NSUInteger)index; | ||
14 | - (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange uniquingOnName:(NSString *)attributeName; | ||
15 | - (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange | ||
16 | inRange:(NSRange)rangeLimit uniquingOnName:(NSString *)attributeName; | ||
17 | @end | ||
18 | |||
19 | @interface ZAttributedString () | ||
20 | @property (nonatomic, readonly) NSArray *attributes; | ||
21 | @end | ||
22 | |||
23 | @implementation ZAttributedString | ||
24 | @synthesize string = _buffer; | ||
25 | @synthesize attributes = _attributes; | ||
26 | |||
27 | - (id)initWithAttributedString:(ZAttributedString *)attr { | ||
28 | NSParameterAssert(attr != nil); | ||
29 | if ((self = [super init])) { | ||
30 | _buffer = [attr->_buffer mutableCopy]; | ||
31 | _attributes = [[NSMutableArray alloc] initWithArray:attr->_attributes copyItems:YES]; | ||
32 | } | ||
33 | return self; | ||
34 | } | ||
35 | |||
36 | - (id)initWithString:(NSString *)str { | ||
37 | return [self initWithString:str attributes:nil]; | ||
38 | } | ||
39 | |||
40 | - (id)initWithString:(NSString *)str attributes:(NSDictionary *)attributes { | ||
41 | if ((self = [super init])) { | ||
42 | _buffer = [str mutableCopy]; | ||
43 | _attributes = [[NSMutableArray alloc] initWithObjects:[ZAttributeRun attributeRunWithIndex:0 attributes:attributes], nil]; | ||
44 | } | ||
45 | return self; | ||
46 | } | ||
47 | |||
48 | - (id)init { | ||
49 | return [self initWithString:@"" attributes:nil]; | ||
50 | } | ||
51 | |||
52 | - (id)initWithCoder:(NSCoder *)decoder { | ||
53 | if ((self = [super init])) { | ||
54 | _buffer = [[decoder decodeObjectForKey:@"buffer"] mutableCopy]; | ||
55 | _attributes = [[decoder decodeObjectForKey:@"attributes"] mutableCopy]; | ||
56 | } | ||
57 | return self; | ||
58 | } | ||
59 | |||
60 | - (void)encodeWithCoder:(NSCoder *)aCoder { | ||
61 | [aCoder encodeObject:_buffer forKey:@"buffer"]; | ||
62 | [aCoder encodeObject:_attributes forKey:@"attributes"]; | ||
63 | } | ||
64 | |||
65 | - (id)copyWithZone:(NSZone *)zone { | ||
66 | return [self retain]; | ||
67 | } | ||
68 | |||
69 | - (id)mutableCopyWithZone:(NSZone *)zone { | ||
70 | return [(ZMutableAttributedString *)[ZMutableAttributedString allocWithZone:zone] initWithAttributedString:self]; | ||
71 | } | ||
72 | |||
73 | - (NSUInteger)length { | ||
74 | return [_buffer length]; | ||
75 | } | ||
76 | |||
77 | - (NSString *)description { | ||
78 | NSMutableArray *components = [NSMutableArray arrayWithCapacity:[_attributes count]*2]; | ||
79 | NSRange range = NSMakeRange(0, 0); | ||
80 | for (NSUInteger i = 0; i <= [_attributes count]; i++) { | ||
81 | range.location = NSMaxRange(range); | ||
82 | ZAttributeRun *run; | ||
83 | if (i < [_attributes count]) { | ||
84 | run = [_attributes objectAtIndex:i]; | ||
85 | range.length = run.index - range.location; | ||
86 | } else { | ||
87 | run = nil; | ||
88 | range.length = [_buffer length] - range.location; | ||
89 | } | ||
90 | if (range.length > 0) { | ||
91 | [components addObject:[NSString stringWithFormat:@"\"%@\"", [_buffer substringWithRange:range]]]; | ||
92 | } | ||
93 | if (run != nil) { | ||
94 | NSMutableArray *attrDesc = [NSMutableArray arrayWithCapacity:[run.attributes count]]; | ||
95 | for (id key in run.attributes) { | ||
96 | [attrDesc addObject:[NSString stringWithFormat:@"%@: %@", key, [run.attributes objectForKey:key]]]; | ||
97 | } | ||
98 | [components addObject:[NSString stringWithFormat:@"{%@}", [attrDesc componentsJoinedByString:@", "]]]; | ||
99 | } | ||
100 | } | ||
101 | return [NSString stringWithFormat:@"%@", [components componentsJoinedByString:@" "]]; | ||
102 | } | ||
103 | |||
104 | - (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange { | ||
105 | NSParameterAssert(attributeName != nil); | ||
106 | return [[self attributesAtIndex:index effectiveRange:aRange uniquingOnName:attributeName] objectForKey:attributeName]; | ||
107 | } | ||
108 | |||
109 | - (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit { | ||
110 | NSParameterAssert(attributeName != nil); | ||
111 | return [[self attributesAtIndex:index longestEffectiveRange:aRange inRange:rangeLimit uniquingOnName:attributeName] objectForKey:attributeName]; | ||
112 | } | ||
113 | |||
114 | - (ZAttributedString *)attributedSubstringFromRange:(NSRange)aRange { | ||
115 | if (NSMaxRange(aRange) > [_buffer length]) { | ||
116 | @throw [NSException exceptionWithName:NSRangeException reason:@"range was outisde of the attributed string" userInfo:nil]; | ||
117 | } | ||
118 | ZMutableAttributedString *newStr = [self mutableCopy]; | ||
119 | if (aRange.location > 0) { | ||
120 | [newStr deleteCharactersInRange:NSMakeRange(0, aRange.location)]; | ||
121 | } | ||
122 | if (NSMaxRange(aRange) < [_buffer length]) { | ||
123 | [newStr deleteCharactersInRange:NSMakeRange(aRange.length, [_buffer length] - NSMaxRange(aRange))]; | ||
124 | } | ||
125 | return [newStr autorelease]; | ||
126 | } | ||
127 | |||
128 | - (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange { | ||
129 | return [NSDictionary dictionaryWithDictionary:[self attributesAtIndex:index effectiveRange:aRange uniquingOnName:nil]]; | ||
130 | } | ||
131 | |||
132 | - (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit { | ||
133 | return [NSDictionary dictionaryWithDictionary:[self attributesAtIndex:index longestEffectiveRange:aRange inRange:rangeLimit uniquingOnName:nil]]; | ||
134 | } | ||
135 | |||
136 | #if Z_BLOCKS | ||
137 | // Warning: this code has not been tested. The only guarantee is that it compiles. | ||
138 | - (void)enumerateAttribute:(NSString *)attrName inRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts | ||
139 | usingBlock:(void (^)(id, NSRange, BOOL*))block { | ||
140 | if (opts & ZAttributedStringEnumerationLongestEffectiveRangeNotRequired) { | ||
141 | [self enumerateAttributesInRange:enumerationRange options:opts usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) { | ||
142 | id value = [attrs objectForKey:attrName]; | ||
143 | if (value != nil) { | ||
144 | block(value, range, stop); | ||
145 | } | ||
146 | }]; | ||
147 | } else { | ||
148 | __block id oldValue = nil; | ||
149 | __block NSRange effectiveRange = NSMakeRange(0, 0); | ||
150 | [self enumerateAttributesInRange:enumerationRange options:opts usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) { | ||
151 | id value = [attrs objectForKey:attrName]; | ||
152 | if (oldValue == nil) { | ||
153 | oldValue = value; | ||
154 | effectiveRange = range; | ||
155 | } else if (value != nil && [oldValue isEqual:value]) { | ||
156 | // combine the attributes | ||
157 | effectiveRange = NSUnionRange(effectiveRange, range); | ||
158 | } else { | ||
159 | BOOL innerStop = NO; | ||
160 | block(oldValue, effectiveRange, &innerStop); | ||
161 | if (innerStop) { | ||
162 | *stop = YES; | ||
163 | oldValue = nil; | ||
164 | } else { | ||
165 | oldValue = value; | ||
166 | } | ||
167 | } | ||
168 | }]; | ||
169 | if (oldValue != nil) { | ||
170 | BOOL innerStop = NO; // necessary for the block, but unused | ||
171 | block(oldValue, effectiveRange, &innerStop); | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | - (void)enumerateAttributesInRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts | ||
177 | usingBlock:(void (^)(NSDictionary*, NSRange, BOOL*))block { | ||
178 | // copy the attributes so we can mutate the string if necessary during enumeration | ||
179 | // also clip the array during copy to only the subarray of attributes that cover the requested range | ||
180 | NSArray *attrs; | ||
181 | if (NSEqualRanges(enumerationRange, NSMakeRange(0, 0))) { | ||
182 | attrs = [NSArray arrayWithArray:_attributes]; | ||
183 | } else { | ||
184 | // in this binary search, last is the first run after the range | ||
185 | NSUInteger first = 0, last = [_attributes count]; | ||
186 | while (last > first+1) { | ||
187 | NSUInteger pivot = (last + first) / 2; | ||
188 | ZAttributeRun *run = [_attributes objectAtIndex:pivot]; | ||
189 | if (run.index < enumerationRange.location) { | ||
190 | first = pivot; | ||
191 | } else if (run.index >= NSMaxRange(enumerationRange)) { | ||
192 | last = pivot; | ||
193 | } | ||
194 | } | ||
195 | attrs = [_attributes subarrayWithRange:NSMakeRange(first, last-first)]; | ||
196 | } | ||
197 | if (opts & ZAttributedStringEnumerationReverse) { | ||
198 | NSUInteger end = [_buffer length]; | ||
199 | for (ZAttributeRun *run in [attrs reverseObjectEnumerator]) { | ||
200 | BOOL stop = NO; | ||
201 | NSUInteger start = run.index; | ||
202 | // clip to enumerationRange | ||
203 | start = MAX(start, enumerationRange.location); | ||
204 | end = MIN(end, NSMaxRange(enumerationRange)); | ||
205 | block(run.attributes, NSMakeRange(start, end - start), &stop); | ||
206 | if (stop) break; | ||
207 | end = run.index; | ||
208 | } | ||
209 | } else { | ||
210 | NSUInteger start = 0; | ||
211 | ZAttributeRun *run = [attrs objectAtIndex:0]; | ||
212 | NSInteger offset = 0; | ||
213 | NSInteger oldLength = [_buffer length]; | ||
214 | for (NSUInteger i = 1;;i++) { | ||
215 | NSUInteger end; | ||
216 | if (i >= [attrs count]) { | ||
217 | end = oldLength; | ||
218 | } else { | ||
219 | end = [[attrs objectAtIndex:i] index]; | ||
220 | } | ||
221 | BOOL stop = NO; | ||
222 | NSUInteger clippedStart = MAX(start, enumerationRange.location); | ||
223 | NSUInteger clippedEnd = MIN(end, NSMaxRange(enumerationRange)); | ||
224 | block(run.attributes, NSMakeRange(clippedStart + offset, clippedEnd - start), &stop); | ||
225 | if (stop || i >= [attrs count]) break; | ||
226 | start = end; | ||
227 | NSUInteger newLength = [_buffer length]; | ||
228 | offset += (newLength - oldLength); | ||
229 | oldLength = newLength; | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | #endif | ||
234 | |||
235 | - (BOOL)isEqualToAttributedString:(ZAttributedString *)otherString { | ||
236 | return ([_buffer isEqualToString:otherString->_buffer] && [_attributes isEqualToArray:otherString->_attributes]); | ||
237 | } | ||
238 | |||
239 | - (BOOL)isEqual:(id)object { | ||
240 | return [object isKindOfClass:[ZAttributedString class]] && [self isEqualToAttributedString:(ZAttributedString *)object]; | ||
241 | } | ||
242 | |||
243 | #pragma mark - | ||
244 | |||
245 | - (NSUInteger)indexOfEffectiveAttributeRunForIndex:(NSUInteger)index { | ||
246 | NSUInteger first = 0, last = [_attributes count]; | ||
247 | while (last > first + 1) { | ||
248 | NSUInteger pivot = (last + first) / 2; | ||
249 | ZAttributeRun *run = [_attributes objectAtIndex:pivot]; | ||
250 | if (run.index > index) { | ||
251 | last = pivot; | ||
252 | } else if (run.index < index) { | ||
253 | first = pivot; | ||
254 | } else { | ||
255 | first = pivot; | ||
256 | break; | ||
257 | } | ||
258 | } | ||
259 | return first; | ||
260 | } | ||
261 | |||
262 | - (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange uniquingOnName:(NSString *)attributeName { | ||
263 | if (index >= [_buffer length]) { | ||
264 | @throw [NSException exceptionWithName:NSRangeException reason:@"index beyond range of attributed string" userInfo:nil]; | ||
265 | } | ||
266 | NSUInteger runIndex = [self indexOfEffectiveAttributeRunForIndex:index]; | ||
267 | ZAttributeRun *run = [_attributes objectAtIndex:runIndex]; | ||
268 | if (aRange != NULL) { | ||
269 | aRange->location = run.index; | ||
270 | runIndex++; | ||
271 | if (runIndex < [_attributes count]) { | ||
272 | aRange->length = [[_attributes objectAtIndex:runIndex] index] - aRange->location; | ||
273 | } else { | ||
274 | aRange->length = [_buffer length] - aRange->location; | ||
275 | } | ||
276 | } | ||
277 | return run.attributes; | ||
278 | } | ||
279 | - (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange | ||
280 | inRange:(NSRange)rangeLimit uniquingOnName:(NSString *)attributeName { | ||
281 | if (index >= [_buffer length]) { | ||
282 | @throw [NSException exceptionWithName:NSRangeException reason:@"index beyond range of attributed string" userInfo:nil]; | ||
283 | } else if (NSMaxRange(rangeLimit) > [_buffer length]) { | ||
284 | @throw [NSException exceptionWithName:NSRangeException reason:@"rangeLimit beyond range of attributed string" userInfo:nil]; | ||
285 | } | ||
286 | NSUInteger runIndex = [self indexOfEffectiveAttributeRunForIndex:index]; | ||
287 | ZAttributeRun *run = [_attributes objectAtIndex:runIndex]; | ||
288 | if (aRange != NULL) { | ||
289 | if (attributeName != nil) { | ||
290 | id value = [run.attributes objectForKey:attributeName]; | ||
291 | NSUInteger endRunIndex = runIndex+1; | ||
292 | runIndex--; | ||
293 | // search backwards | ||
294 | while (1) { | ||
295 | if (run.index <= rangeLimit.location) { | ||
296 | break; | ||
297 | } | ||
298 | ZAttributeRun *prevRun = [_attributes objectAtIndex:runIndex]; | ||
299 | id prevValue = [prevRun.attributes objectForKey:attributeName]; | ||
300 | if (prevValue == value || (value != nil && [prevValue isEqual:value])) { | ||
301 | runIndex--; | ||
302 | run = prevRun; | ||
303 | } else { | ||
304 | break; | ||
305 | } | ||
306 | } | ||
307 | // search forwards | ||
308 | ZAttributeRun *endRun = nil; | ||
309 | while (endRunIndex < [_attributes count]) { | ||
310 | ZAttributeRun *nextRun = [_attributes objectAtIndex:endRunIndex]; | ||
311 | if (nextRun.index >= NSMaxRange(rangeLimit)) { | ||
312 | endRun = nextRun; | ||
313 | break; | ||
314 | } | ||
315 | id nextValue = [nextRun.attributes objectForKey:attributeName]; | ||
316 | if (nextValue == value || (value != nil && [nextValue isEqual:value])) { | ||
317 | endRunIndex++; | ||
318 | } else { | ||
319 | endRun = nextRun; | ||
320 | break; | ||
321 | } | ||
322 | } | ||
323 | aRange->location = MAX(run.index, rangeLimit.location); | ||
324 | aRange->length = MIN((endRun ? endRun.index : [_buffer length]), NSMaxRange(rangeLimit)) - aRange->location; | ||
325 | } else { | ||
326 | // with no attribute name, we don't need to do any real searching, | ||
327 | // as we already guarantee each run has unique attributes. | ||
328 | // just make sure to clip the range to the rangeLimit | ||
329 | aRange->location = MAX(run.index, rangeLimit.location); | ||
330 | ZAttributeRun *endRun = (runIndex+1 < [_attributes count] ? [_attributes objectAtIndex:runIndex+1] : nil); | ||
331 | aRange->length = MIN((endRun ? endRun.index : [_buffer length]), NSMaxRange(rangeLimit)) - aRange->location; | ||
332 | } | ||
333 | } | ||
334 | return run.attributes; | ||
335 | } | ||
336 | |||
337 | - (void)dealloc { | ||
338 | [_buffer release]; | ||
339 | [_attributes release]; | ||
340 | [super dealloc]; | ||
341 | } | ||
342 | @end | ||
343 | |||
344 | @interface ZMutableAttributedString () | ||
345 | - (void)cleanupAttributesInRange:(NSRange)range; | ||
346 | - (NSRange)rangeOfAttributeRunsForRange:(NSRange)range; | ||
347 | - (void)offsetRunsInRange:(NSRange )range byOffset:(NSInteger)offset; | ||
348 | @end | ||
349 | |||
350 | @implementation ZMutableAttributedString | ||
351 | - (id)copyWithZone:(NSZone *)zone { | ||
352 | return [(ZAttributedString *)[ZAttributedString allocWithZone:zone] initWithAttributedString:self]; | ||
353 | } | ||
354 | |||
355 | - (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range { | ||
356 | range = [self rangeOfAttributeRunsForRange:range]; | ||
357 | for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) { | ||
358 | [run.attributes setObject:value forKey:name]; | ||
359 | } | ||
360 | [self cleanupAttributesInRange:range]; | ||
361 | } | ||
362 | |||
363 | - (void)addAttributes:(NSDictionary *)attributes range:(NSRange)range { | ||
364 | range = [self rangeOfAttributeRunsForRange:range]; | ||
365 | for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) { | ||
366 | [run.attributes addEntriesFromDictionary:attributes]; | ||
367 | } | ||
368 | [self cleanupAttributesInRange:range]; | ||
369 | } | ||
370 | |||
371 | - (void)appendAttributedString:(ZAttributedString *)str { | ||
372 | [self insertAttributedString:str atIndex:[_buffer length]]; | ||
373 | } | ||
374 | |||
375 | - (void)deleteCharactersInRange:(NSRange)range { | ||
376 | NSRange runRange = [self rangeOfAttributeRunsForRange:range]; | ||
377 | [_buffer replaceCharactersInRange:range withString:@""]; | ||
378 | [_attributes removeObjectsInRange:runRange]; | ||
379 | for (NSUInteger i = runRange.location; i < [_attributes count]; i++) { | ||
380 | ZAttributeRun *run = [_attributes objectAtIndex:i]; | ||
381 | ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:(run.index - range.length) attributes:run.attributes]; | ||
382 | [_attributes replaceObjectAtIndex:i withObject:newRun]; | ||
383 | [newRun release]; | ||
384 | } | ||
385 | [self cleanupAttributesInRange:NSMakeRange(runRange.location, 0)]; | ||
386 | } | ||
387 | |||
388 | - (void)insertAttributedString:(ZAttributedString *)str atIndex:(NSUInteger)idx { | ||
389 | [self replaceCharactersInRange:NSMakeRange(idx, 0) withAttributedString:str]; | ||
390 | } | ||
391 | |||
392 | - (void)removeAttribute:(NSString *)name range:(NSRange)range { | ||
393 | range = [self rangeOfAttributeRunsForRange:range]; | ||
394 | for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) { | ||
395 | [run.attributes removeObjectForKey:name]; | ||
396 | } | ||
397 | [self cleanupAttributesInRange:range]; | ||
398 | } | ||
399 | |||
400 | - (void)replaceCharactersInRange:(NSRange)range withAttributedString:(ZAttributedString *)str { | ||
401 | NSRange replaceRange = [self rangeOfAttributeRunsForRange:range]; | ||
402 | NSInteger offset = [str->_buffer length] - range.length; | ||
403 | [_buffer replaceCharactersInRange:range withString:str->_buffer]; | ||
404 | [_attributes replaceObjectsInRange:replaceRange withObjectsFromArray:str->_attributes]; | ||
405 | NSRange newRange = NSMakeRange(replaceRange.location, [str->_attributes count]); | ||
406 | [self offsetRunsInRange:newRange byOffset:range.location]; | ||
407 | [self offsetRunsInRange:NSMakeRange(NSMaxRange(newRange), [_attributes count] - NSMaxRange(newRange)) byOffset:offset]; | ||
408 | [self cleanupAttributesInRange:NSMakeRange(newRange.location, 0)]; | ||
409 | [self cleanupAttributesInRange:NSMakeRange(NSMaxRange(newRange), 0)]; | ||
410 | } | ||
411 | |||
412 | - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str { | ||
413 | [self replaceCharactersInRange:range withAttributedString:[[[ZAttributedString alloc] initWithString:str] autorelease]]; | ||
414 | } | ||
415 | |||
416 | - (void)setAttributedString:(ZAttributedString *)str { | ||
417 | [_buffer release], _buffer = [str->_buffer mutableCopy]; | ||
418 | [_attributes release], _attributes = [str->_attributes mutableCopy]; | ||
419 | } | ||
420 | |||
421 | - (void)setAttributes:(NSDictionary *)attributes range:(NSRange)range { | ||
422 | range = [self rangeOfAttributeRunsForRange:range]; | ||
423 | for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) { | ||
424 | [run.attributes setDictionary:attributes]; | ||
425 | } | ||
426 | [self cleanupAttributesInRange:range]; | ||
427 | } | ||
428 | |||
429 | #pragma mark - | ||
430 | |||
431 | // splits the existing runs to provide one or more new runs for the given range | ||
432 | - (NSRange)rangeOfAttributeRunsForRange:(NSRange)range { | ||
433 | NSParameterAssert(NSMaxRange(range) <= [_buffer length]); | ||
434 | |||
435 | // find (or create) the first run | ||
436 | NSUInteger first = 0; | ||
437 | ZAttributeRun *lastRun = nil; | ||
438 | for (;;first++) { | ||
439 | if (first >= [_attributes count]) { | ||
440 | // we didn't find a run | ||
441 | first = [_attributes count]; | ||
442 | ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:range.location attributes:lastRun.attributes]; | ||
443 | [_attributes addObject:newRun]; | ||
444 | [newRun release]; | ||
445 | break; | ||
446 | } | ||
447 | ZAttributeRun *run = [_attributes objectAtIndex:first]; | ||
448 | if (run.index == range.location) { | ||
449 | break; | ||
450 | } else if (run.index > range.location) { | ||
451 | ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:range.location attributes:lastRun.attributes]; | ||
452 | [_attributes insertObject:newRun atIndex:first]; | ||
453 | [newRun release]; | ||
454 | break; | ||
455 | } | ||
456 | lastRun = run; | ||
457 | } | ||
458 | |||
459 | if (((ZAttributeRun *)[_attributes lastObject]).index < NSMaxRange(range)) { | ||
460 | NSRange subrange = NSMakeRange(first, [_attributes count] - first); | ||
461 | if (NSMaxRange(range) < [_buffer length]) { | ||
462 | ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:NSMaxRange(range) | ||
463 | attributes:(NSDictionary*)[(ZAttributeRun *)[_attributes lastObject] attributes]]; | ||
464 | [_attributes addObject:newRun]; | ||
465 | [newRun release]; | ||
466 | } | ||
467 | return subrange; | ||
468 | } else { | ||
469 | // find the last run within and the first run after the range | ||
470 | NSUInteger lastIn = first, firstAfter = [_attributes count]-1; | ||
471 | while (firstAfter > lastIn + 1) { | ||
472 | NSUInteger idx = (firstAfter + lastIn) / 2; | ||
473 | ZAttributeRun *run = [_attributes objectAtIndex:idx]; | ||
474 | if (run.index < range.location) { | ||
475 | lastIn = idx; | ||
476 | } else if (run.index > range.location) { | ||
477 | firstAfter = idx; | ||
478 | } else { | ||
479 | // this is definitively the first run after the range | ||
480 | firstAfter = idx; | ||
481 | break; | ||
482 | } | ||
483 | } | ||
484 | if ([[_attributes objectAtIndex:firstAfter] index] > NSMaxRange(range)) { | ||
485 | // the first after is too far after, insert another run! | ||
486 | ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:NSMaxRange(range) | ||
487 | attributes:[(ZAttributeRun *)[_attributes objectAtIndex:firstAfter-1] attributes]]; | ||
488 | [_attributes insertObject:newRun atIndex:firstAfter]; | ||
489 | [newRun release]; | ||
490 | } | ||
491 | return NSMakeRange(lastIn, firstAfter - lastIn); | ||
492 | } | ||
493 | } | ||
494 | |||
495 | - (void)cleanupAttributesInRange:(NSRange)range { | ||
496 | // expand the range to include one surrounding attribute on each side | ||
497 | if (range.location > 0) { | ||
498 | range.location -= 1; | ||
499 | range.length += 1; | ||
500 | } | ||
501 | if (NSMaxRange(range) < [_attributes count]) { | ||
502 | range.length += 1; | ||
503 | } else { | ||
504 | // make sure the range is capped to the attributes count | ||
505 | range.length = [_attributes count] - range.location; | ||
506 | } | ||
507 | if (range.length == 0) return; | ||
508 | ZAttributeRun *lastRun = [_attributes objectAtIndex:range.location]; | ||
509 | for (NSUInteger i = range.location+1; i < NSMaxRange(range);) { | ||
510 | ZAttributeRun *run = [_attributes objectAtIndex:i]; | ||
511 | if ([lastRun.attributes isEqualToDictionary:run.attributes]) { | ||
512 | [_attributes removeObjectAtIndex:i]; | ||
513 | range.length -= 1; | ||
514 | } else { | ||
515 | lastRun = run; | ||
516 | i++; | ||
517 | } | ||
518 | } | ||
519 | } | ||
520 | |||
521 | - (void)offsetRunsInRange:(NSRange)range byOffset:(NSInteger)offset { | ||
522 | for (NSUInteger i = range.location; i < NSMaxRange(range); i++) { | ||
523 | ZAttributeRun *run = [_attributes objectAtIndex:i]; | ||
524 | ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:run.index + offset attributes:run.attributes]; | ||
525 | [_attributes replaceObjectAtIndex:i withObject:newRun]; | ||
526 | [newRun release]; | ||
527 | } | ||
528 | } | ||
529 | @end | ||
530 | |||
531 | @implementation ZAttributeRun | ||
532 | @synthesize index = _index; | ||
533 | @synthesize attributes = _attributes; | ||
534 | |||
535 | + (id)attributeRunWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs { | ||
536 | return [[[self alloc] initWithIndex:idx attributes:attrs] autorelease]; | ||
537 | } | ||
538 | |||
539 | - (id)initWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs { | ||
540 | NSParameterAssert(idx >= 0); | ||
541 | if ((self = [super init])) { | ||
542 | _index = idx; | ||
543 | if (attrs == nil) { | ||
544 | _attributes = [[NSMutableDictionary alloc] init]; | ||
545 | } else { | ||
546 | _attributes = [attrs mutableCopy]; | ||
547 | } | ||
548 | } | ||
549 | return self; | ||
550 | } | ||
551 | |||
552 | - (id)initWithCoder:(NSCoder *)decoder { | ||
553 | if ((self = [super init])) { | ||
554 | _index = [[decoder decodeObjectForKey:@"index"] unsignedIntegerValue]; | ||
555 | _attributes = [[decoder decodeObjectForKey:@"attributes"] mutableCopy]; | ||
556 | } | ||
557 | return self; | ||
558 | } | ||
559 | |||
560 | - (id)init { | ||
561 | return [self initWithIndex:0 attributes:[NSDictionary dictionary]]; | ||
562 | } | ||
563 | |||
564 | - (id)copyWithZone:(NSZone *)zone { | ||
565 | return [[ZAttributeRun allocWithZone:zone] initWithIndex:_index attributes:_attributes]; | ||
566 | } | ||
567 | |||
568 | - (void)encodeWithCoder:(NSCoder *)aCoder { | ||
569 | [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:_index] forKey:@"index"]; | ||
570 | [aCoder encodeObject:_attributes forKey:@"attributes"]; | ||
571 | } | ||
572 | |||
573 | - (NSString *)description { | ||
574 | NSMutableArray *components = [NSMutableArray arrayWithCapacity:[_attributes count]]; | ||
575 | for (id key in _attributes) { | ||
576 | [components addObject:[NSString stringWithFormat:@"%@=%@", key, [_attributes objectForKey:key]]]; | ||
577 | } | ||
578 | return [NSString stringWithFormat:@"<%@: %p index=%lu attributes={%@}>", | ||
579 | NSStringFromClass([self class]), self, (unsigned long)_index, [components componentsJoinedByString:@" "]]; | ||
580 | } | ||
581 | |||
582 | - (BOOL)isEqual:(id)object { | ||
583 | if (![object isKindOfClass:[ZAttributeRun class]]) return NO; | ||
584 | ZAttributeRun *other = (ZAttributeRun *)object; | ||
585 | return _index == other->_index && [_attributes isEqualToDictionary:other->_attributes]; | ||
586 | } | ||
587 | |||
588 | - (void)dealloc { | ||
589 | [_attributes release]; | ||
590 | [super dealloc]; | ||
591 | } | ||
592 | @end | ||
593 | |||
594 | NSString * const ZFontAttributeName = @"ZFontAttributeName"; | ||
595 | NSString * const ZForegroundColorAttributeName = @"ZForegroundColorAttributeName"; | ||
596 | NSString * const ZBackgroundColorAttributeName = @"ZBackgroundColorAttributeName"; | ||
597 | NSString * const ZUnderlineStyleAttributeName = @"ZUnderlineStyleAttributeName"; | ||
diff --git a/libs/FontLabel/ZAttributedStringPrivate.h b/libs/FontLabel/ZAttributedStringPrivate.h new file mode 100755 index 0000000..1021d7b --- /dev/null +++ b/libs/FontLabel/ZAttributedStringPrivate.h | |||
@@ -0,0 +1,24 @@ | |||
1 | // | ||
2 | // ZAttributedStringPrivate.h | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 9/23/09. | ||
6 | // Copyright 2009 Zynga Game Networks. All rights reserved. | ||
7 | // | ||
8 | |||
9 | #import <Foundation/Foundation.h> | ||
10 | #import "ZAttributedString.h" | ||
11 | |||
12 | @interface ZAttributeRun : NSObject <NSCopying, NSCoding> { | ||
13 | NSUInteger _index; | ||
14 | NSMutableDictionary *_attributes; | ||
15 | } | ||
16 | @property (nonatomic, readonly) NSUInteger index; | ||
17 | @property (nonatomic, readonly) NSMutableDictionary *attributes; | ||
18 | + (id)attributeRunWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs; | ||
19 | - (id)initWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs; | ||
20 | @end | ||
21 | |||
22 | @interface ZAttributedString (ZAttributedStringPrivate) | ||
23 | @property (nonatomic, readonly) NSArray *attributes; | ||
24 | @end | ||
diff --git a/libs/FontLabel/ZFont.h b/libs/FontLabel/ZFont.h new file mode 100755 index 0000000..05ae823 --- /dev/null +++ b/libs/FontLabel/ZFont.h | |||
@@ -0,0 +1,47 @@ | |||
1 | // | ||
2 | // ZFont.h | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 7/2/09. | ||
6 | // Copyright © 2009 Zynga Game Networks | ||
7 | // | ||
8 | // | ||
9 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
10 | // you may not use this file except in compliance with the License. | ||
11 | // You may obtain a copy of the License at | ||
12 | // | ||
13 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
14 | // | ||
15 | // Unless required by applicable law or agreed to in writing, software | ||
16 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
18 | // See the License for the specific language governing permissions and | ||
19 | // limitations under the License. | ||
20 | // | ||
21 | |||
22 | #import <Foundation/Foundation.h> | ||
23 | #import <UIKit/UIKit.h> | ||
24 | |||
25 | @interface ZFont : NSObject { | ||
26 | CGFontRef _cgFont; | ||
27 | CGFloat _pointSize; | ||
28 | CGFloat _ratio; | ||
29 | NSString *_familyName; | ||
30 | NSString *_fontName; | ||
31 | NSString *_postScriptName; | ||
32 | } | ||
33 | @property (nonatomic, readonly) CGFontRef cgFont; | ||
34 | @property (nonatomic, readonly) CGFloat pointSize; | ||
35 | @property (nonatomic, readonly) CGFloat ascender; | ||
36 | @property (nonatomic, readonly) CGFloat descender; | ||
37 | @property (nonatomic, readonly) CGFloat leading; | ||
38 | @property (nonatomic, readonly) CGFloat xHeight; | ||
39 | @property (nonatomic, readonly) CGFloat capHeight; | ||
40 | @property (nonatomic, readonly) NSString *familyName; | ||
41 | @property (nonatomic, readonly) NSString *fontName; | ||
42 | @property (nonatomic, readonly) NSString *postScriptName; | ||
43 | + (ZFont *)fontWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize; | ||
44 | + (ZFont *)fontWithUIFont:(UIFont *)uiFont; | ||
45 | - (id)initWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize; | ||
46 | - (ZFont *)fontWithSize:(CGFloat)fontSize; | ||
47 | @end | ||
diff --git a/libs/FontLabel/ZFont.m b/libs/FontLabel/ZFont.m new file mode 100755 index 0000000..793b13a --- /dev/null +++ b/libs/FontLabel/ZFont.m | |||
@@ -0,0 +1,170 @@ | |||
1 | // | ||
2 | // ZFont.m | ||
3 | // FontLabel | ||
4 | // | ||
5 | // Created by Kevin Ballard on 7/2/09. | ||
6 | // Copyright © 2009 Zynga Game Networks | ||
7 | // | ||
8 | // | ||
9 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
10 | // you may not use this file except in compliance with the License. | ||
11 | // You may obtain a copy of the License at | ||
12 | // | ||
13 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
14 | // | ||
15 | // Unless required by applicable law or agreed to in writing, software | ||
16 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
18 | // See the License for the specific language governing permissions and | ||
19 | // limitations under the License. | ||
20 | // | ||
21 | |||
22 | #import "ZFont.h" | ||
23 | |||
24 | @interface ZFont () | ||
25 | @property (nonatomic, readonly) CGFloat ratio; | ||
26 | - (NSString *)copyNameTableEntryForID:(UInt16)nameID; | ||
27 | @end | ||
28 | |||
29 | @implementation ZFont | ||
30 | @synthesize cgFont=_cgFont, pointSize=_pointSize, ratio=_ratio; | ||
31 | |||
32 | + (ZFont *)fontWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize { | ||
33 | return [[[self alloc] initWithCGFont:cgFont size:fontSize] autorelease]; | ||
34 | } | ||
35 | |||
36 | + (ZFont *)fontWithUIFont:(UIFont *)uiFont { | ||
37 | NSParameterAssert(uiFont != nil); | ||
38 | CGFontRef cgFont = CGFontCreateWithFontName((CFStringRef)uiFont.fontName); | ||
39 | ZFont *zFont = [[self alloc] initWithCGFont:cgFont size:uiFont.pointSize]; | ||
40 | CGFontRelease(cgFont); | ||
41 | return [zFont autorelease]; | ||
42 | } | ||
43 | |||
44 | - (id)initWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize { | ||
45 | if ((self = [super init])) { | ||
46 | _cgFont = CGFontRetain(cgFont); | ||
47 | _pointSize = fontSize; | ||
48 | _ratio = fontSize/CGFontGetUnitsPerEm(cgFont); | ||
49 | } | ||
50 | return self; | ||
51 | } | ||
52 | |||
53 | - (id)init { | ||
54 | NSAssert(NO, @"-init is not valid for ZFont"); | ||
55 | return nil; | ||
56 | } | ||
57 | |||
58 | - (CGFloat)ascender { | ||
59 | return ceilf(self.ratio * CGFontGetAscent(self.cgFont)); | ||
60 | } | ||
61 | |||
62 | - (CGFloat)descender { | ||
63 | return floorf(self.ratio * CGFontGetDescent(self.cgFont)); | ||
64 | } | ||
65 | |||
66 | - (CGFloat)leading { | ||
67 | return (self.ascender - self.descender); | ||
68 | } | ||
69 | |||
70 | - (CGFloat)capHeight { | ||
71 | return ceilf(self.ratio * CGFontGetCapHeight(self.cgFont)); | ||
72 | } | ||
73 | |||
74 | - (CGFloat)xHeight { | ||
75 | return ceilf(self.ratio * CGFontGetXHeight(self.cgFont)); | ||
76 | } | ||
77 | |||
78 | - (NSString *)familyName { | ||
79 | if (_familyName == nil) { | ||
80 | _familyName = [self copyNameTableEntryForID:1]; | ||
81 | } | ||
82 | return _familyName; | ||
83 | } | ||
84 | |||
85 | - (NSString *)fontName { | ||
86 | if (_fontName == nil) { | ||
87 | _fontName = [self copyNameTableEntryForID:4]; | ||
88 | } | ||
89 | return _fontName; | ||
90 | } | ||
91 | |||
92 | - (NSString *)postScriptName { | ||
93 | if (_postScriptName == nil) { | ||
94 | _postScriptName = [self copyNameTableEntryForID:6]; | ||
95 | } | ||
96 | return _postScriptName; | ||
97 | } | ||
98 | |||
99 | - (ZFont *)fontWithSize:(CGFloat)fontSize { | ||
100 | if (fontSize == self.pointSize) return self; | ||
101 | NSParameterAssert(fontSize > 0.0); | ||
102 | return [[[ZFont alloc] initWithCGFont:self.cgFont size:fontSize] autorelease]; | ||
103 | } | ||
104 | |||
105 | - (BOOL)isEqual:(id)object { | ||
106 | if (![object isKindOfClass:[ZFont class]]) return NO; | ||
107 | ZFont *font = (ZFont *)object; | ||
108 | return (font.cgFont == self.cgFont && font.pointSize == self.pointSize); | ||
109 | } | ||
110 | |||
111 | - (NSString *)copyNameTableEntryForID:(UInt16)aNameID { | ||
112 | CFDataRef nameTable = CGFontCopyTableForTag(self.cgFont, 'name'); | ||
113 | NSAssert1(nameTable != NULL, @"CGFontCopyTableForTag returned NULL for 'name' tag in font %@", | ||
114 | [(id)CFCopyDescription(self.cgFont) autorelease]); | ||
115 | const UInt8 * const bytes = CFDataGetBytePtr(nameTable); | ||
116 | NSAssert1(OSReadBigInt16(bytes, 0) == 0, @"name table for font %@ has bad version number", | ||
117 | [(id)CFCopyDescription(self.cgFont) autorelease]); | ||
118 | const UInt16 count = OSReadBigInt16(bytes, 2); | ||
119 | const UInt16 stringOffset = OSReadBigInt16(bytes, 4); | ||
120 | const UInt8 * const nameRecords = &bytes[6]; | ||
121 | UInt16 nameLength = 0; | ||
122 | UInt16 nameOffset = 0; | ||
123 | NSStringEncoding encoding = 0; | ||
124 | for (UInt16 idx = 0; idx < count; idx++) { | ||
125 | const uintptr_t recordOffset = 12 * idx; | ||
126 | const UInt16 nameID = OSReadBigInt16(nameRecords, recordOffset + 6); | ||
127 | if (nameID != aNameID) continue; | ||
128 | const UInt16 platformID = OSReadBigInt16(nameRecords, recordOffset + 0); | ||
129 | const UInt16 platformSpecificID = OSReadBigInt16(nameRecords, recordOffset + 2); | ||
130 | encoding = 0; | ||
131 | // for now, we only support a subset of encodings | ||
132 | switch (platformID) { | ||
133 | case 0: // Unicode | ||
134 | encoding = NSUTF16StringEncoding; | ||
135 | break; | ||
136 | case 1: // Macintosh | ||
137 | switch (platformSpecificID) { | ||
138 | case 0: | ||
139 | encoding = NSMacOSRomanStringEncoding; | ||
140 | break; | ||
141 | } | ||
142 | case 3: // Microsoft | ||
143 | switch (platformSpecificID) { | ||
144 | case 1: | ||
145 | encoding = NSUTF16StringEncoding; | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | if (encoding == 0) continue; | ||
150 | nameLength = OSReadBigInt16(nameRecords, recordOffset + 8); | ||
151 | nameOffset = OSReadBigInt16(nameRecords, recordOffset + 10); | ||
152 | break; | ||
153 | } | ||
154 | NSString *result = nil; | ||
155 | if (nameOffset > 0) { | ||
156 | const UInt8 *nameBytes = &bytes[stringOffset + nameOffset]; | ||
157 | result = [[NSString alloc] initWithBytes:nameBytes length:nameLength encoding:encoding]; | ||
158 | } | ||
159 | CFRelease(nameTable); | ||
160 | return result; | ||
161 | } | ||
162 | |||
163 | - (void)dealloc { | ||
164 | CGFontRelease(_cgFont); | ||
165 | [_familyName release]; | ||
166 | [_fontName release]; | ||
167 | [_postScriptName release]; | ||
168 | [super dealloc]; | ||
169 | } | ||
170 | @end | ||
diff --git a/libs/README b/libs/README new file mode 100755 index 0000000..0d4d8fc --- /dev/null +++ b/libs/README | |||
@@ -0,0 +1 @@ | |||
This directory contains the libraries used in cocos2d | |||
diff --git a/libs/TouchJSON/CDataScanner.h b/libs/TouchJSON/CDataScanner.h new file mode 100755 index 0000000..41f68e8 --- /dev/null +++ b/libs/TouchJSON/CDataScanner.h | |||
@@ -0,0 +1,71 @@ | |||
1 | // | ||
2 | // CDataScanner.h | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 04/16/08. | ||
6 | // Copyright 2008 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import <Foundation/Foundation.h> | ||
31 | |||
32 | // NSScanner | ||
33 | |||
34 | @interface CDataScanner : NSObject { | ||
35 | NSData *data; | ||
36 | |||
37 | u_int8_t *start; | ||
38 | u_int8_t *end; | ||
39 | u_int8_t *current; | ||
40 | NSUInteger length; | ||
41 | } | ||
42 | |||
43 | @property (readwrite, nonatomic, retain) NSData *data; | ||
44 | @property (readwrite, nonatomic, assign) NSUInteger scanLocation; | ||
45 | @property (readonly, nonatomic, assign) NSUInteger bytesRemaining; | ||
46 | @property (readonly, nonatomic, assign) BOOL isAtEnd; | ||
47 | |||
48 | - (id)initWithData:(NSData *)inData; | ||
49 | |||
50 | - (unichar)currentCharacter; | ||
51 | - (unichar)scanCharacter; | ||
52 | - (BOOL)scanCharacter:(unichar)inCharacter; | ||
53 | |||
54 | - (BOOL)scanUTF8String:(const char *)inString intoString:(NSString **)outValue; | ||
55 | - (BOOL)scanString:(NSString *)inString intoString:(NSString **)outValue; | ||
56 | - (BOOL)scanCharactersFromSet:(NSCharacterSet *)inSet intoString:(NSString **)outValue; // inSet must only contain 7-bit ASCII characters | ||
57 | |||
58 | - (BOOL)scanUpToString:(NSString *)string intoString:(NSString **)outValue; | ||
59 | - (BOOL)scanUpToCharactersFromSet:(NSCharacterSet *)set intoString:(NSString **)outValue; // inSet must only contain 7-bit ASCII characters | ||
60 | |||
61 | - (BOOL)scanNumber:(NSNumber **)outValue; | ||
62 | - (BOOL)scanDecimalNumber:(NSDecimalNumber **)outValue; | ||
63 | |||
64 | - (BOOL)scanDataOfLength:(NSUInteger)inLength intoData:(NSData **)outData; | ||
65 | |||
66 | - (void)skipWhitespace; | ||
67 | |||
68 | - (NSString *)remainingString; | ||
69 | - (NSData *)remainingData; | ||
70 | |||
71 | @end | ||
diff --git a/libs/TouchJSON/CDataScanner.m b/libs/TouchJSON/CDataScanner.m new file mode 100755 index 0000000..b3cee6f --- /dev/null +++ b/libs/TouchJSON/CDataScanner.m | |||
@@ -0,0 +1,340 @@ | |||
1 | // | ||
2 | // CDataScanner.m | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 04/16/08. | ||
6 | // Copyright 2008 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import "CDataScanner.h" | ||
31 | |||
32 | #import "CDataScanner_Extensions.h" | ||
33 | |||
34 | @interface CDataScanner () | ||
35 | @end | ||
36 | |||
37 | #pragma mark - | ||
38 | |||
39 | inline static unichar CharacterAtPointer(void *start, void *end) | ||
40 | { | ||
41 | #pragma unused(end) | ||
42 | |||
43 | const u_int8_t theByte = *(u_int8_t *)start; | ||
44 | if (theByte & 0x80) | ||
45 | { | ||
46 | // TODO -- UNICODE!!!! (well in theory nothing todo here) | ||
47 | } | ||
48 | const unichar theCharacter = theByte; | ||
49 | return(theCharacter); | ||
50 | } | ||
51 | |||
52 | static NSCharacterSet *sDoubleCharacters = NULL; | ||
53 | |||
54 | @implementation CDataScanner | ||
55 | |||
56 | - (id)init | ||
57 | { | ||
58 | if ((self = [super init]) != NULL) | ||
59 | { | ||
60 | } | ||
61 | return(self); | ||
62 | } | ||
63 | |||
64 | - (id)initWithData:(NSData *)inData; | ||
65 | { | ||
66 | if ((self = [self init]) != NULL) | ||
67 | { | ||
68 | [self setData:inData]; | ||
69 | } | ||
70 | return(self); | ||
71 | } | ||
72 | |||
73 | + (void)initialize | ||
74 | { | ||
75 | if (sDoubleCharacters == NULL) | ||
76 | { | ||
77 | sDoubleCharacters = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789eE-+."] retain]; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | - (void)dealloc | ||
82 | { | ||
83 | [data release]; | ||
84 | data = NULL; | ||
85 | // | ||
86 | [super dealloc]; | ||
87 | } | ||
88 | |||
89 | - (NSUInteger)scanLocation | ||
90 | { | ||
91 | return(current - start); | ||
92 | } | ||
93 | |||
94 | - (NSUInteger)bytesRemaining | ||
95 | { | ||
96 | return(end - current); | ||
97 | } | ||
98 | |||
99 | - (NSData *)data | ||
100 | { | ||
101 | return(data); | ||
102 | } | ||
103 | |||
104 | - (void)setData:(NSData *)inData | ||
105 | { | ||
106 | if (data != inData) | ||
107 | { | ||
108 | [data release]; | ||
109 | data = [inData retain]; | ||
110 | } | ||
111 | |||
112 | if (data) | ||
113 | { | ||
114 | start = (u_int8_t *)data.bytes; | ||
115 | end = start + data.length; | ||
116 | current = start; | ||
117 | length = data.length; | ||
118 | } | ||
119 | else | ||
120 | { | ||
121 | start = NULL; | ||
122 | end = NULL; | ||
123 | current = NULL; | ||
124 | length = 0; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | - (void)setScanLocation:(NSUInteger)inScanLocation | ||
129 | { | ||
130 | current = start + inScanLocation; | ||
131 | } | ||
132 | |||
133 | - (BOOL)isAtEnd | ||
134 | { | ||
135 | return(self.scanLocation >= length); | ||
136 | } | ||
137 | |||
138 | - (unichar)currentCharacter | ||
139 | { | ||
140 | return(CharacterAtPointer(current, end)); | ||
141 | } | ||
142 | |||
143 | #pragma mark - | ||
144 | |||
145 | - (unichar)scanCharacter | ||
146 | { | ||
147 | const unichar theCharacter = CharacterAtPointer(current++, end); | ||
148 | return(theCharacter); | ||
149 | } | ||
150 | |||
151 | - (BOOL)scanCharacter:(unichar)inCharacter | ||
152 | { | ||
153 | unichar theCharacter = CharacterAtPointer(current, end); | ||
154 | if (theCharacter == inCharacter) | ||
155 | { | ||
156 | ++current; | ||
157 | return(YES); | ||
158 | } | ||
159 | else | ||
160 | return(NO); | ||
161 | } | ||
162 | |||
163 | - (BOOL)scanUTF8String:(const char *)inString intoString:(NSString **)outValue | ||
164 | { | ||
165 | const size_t theLength = strlen(inString); | ||
166 | if ((size_t)(end - current) < theLength) | ||
167 | return(NO); | ||
168 | if (strncmp((char *)current, inString, theLength) == 0) | ||
169 | { | ||
170 | current += theLength; | ||
171 | if (outValue) | ||
172 | *outValue = [NSString stringWithUTF8String:inString]; | ||
173 | return(YES); | ||
174 | } | ||
175 | return(NO); | ||
176 | } | ||
177 | |||
178 | - (BOOL)scanString:(NSString *)inString intoString:(NSString **)outValue | ||
179 | { | ||
180 | if ((size_t)(end - current) < inString.length) | ||
181 | return(NO); | ||
182 | if (strncmp((char *)current, [inString UTF8String], inString.length) == 0) | ||
183 | { | ||
184 | current += inString.length; | ||
185 | if (outValue) | ||
186 | *outValue = inString; | ||
187 | return(YES); | ||
188 | } | ||
189 | return(NO); | ||
190 | } | ||
191 | |||
192 | - (BOOL)scanCharactersFromSet:(NSCharacterSet *)inSet intoString:(NSString **)outValue | ||
193 | { | ||
194 | u_int8_t *P; | ||
195 | for (P = current; P < end && [inSet characterIsMember:*P] == YES; ++P) | ||
196 | ; | ||
197 | |||
198 | if (P == current) | ||
199 | { | ||
200 | return(NO); | ||
201 | } | ||
202 | |||
203 | if (outValue) | ||
204 | { | ||
205 | *outValue = [[[NSString alloc] initWithBytes:current length:P - current encoding:NSUTF8StringEncoding] autorelease]; | ||
206 | } | ||
207 | |||
208 | current = P; | ||
209 | |||
210 | return(YES); | ||
211 | } | ||
212 | |||
213 | - (BOOL)scanUpToString:(NSString *)inString intoString:(NSString **)outValue | ||
214 | { | ||
215 | const char *theToken = [inString UTF8String]; | ||
216 | const char *theResult = strnstr((char *)current, theToken, end - current); | ||
217 | if (theResult == NULL) | ||
218 | { | ||
219 | return(NO); | ||
220 | } | ||
221 | |||
222 | if (outValue) | ||
223 | { | ||
224 | *outValue = [[[NSString alloc] initWithBytes:current length:theResult - (char *)current encoding:NSUTF8StringEncoding] autorelease]; | ||
225 | } | ||
226 | |||
227 | current = (u_int8_t *)theResult; | ||
228 | |||
229 | return(YES); | ||
230 | } | ||
231 | |||
232 | - (BOOL)scanUpToCharactersFromSet:(NSCharacterSet *)inSet intoString:(NSString **)outValue | ||
233 | { | ||
234 | u_int8_t *P; | ||
235 | for (P = current; P < end && [inSet characterIsMember:*P] == NO; ++P) | ||
236 | ; | ||
237 | |||
238 | if (P == current) | ||
239 | { | ||
240 | return(NO); | ||
241 | } | ||
242 | |||
243 | if (outValue) | ||
244 | { | ||
245 | *outValue = [[[NSString alloc] initWithBytes:current length:P - current encoding:NSUTF8StringEncoding] autorelease]; | ||
246 | } | ||
247 | |||
248 | current = P; | ||
249 | |||
250 | return(YES); | ||
251 | } | ||
252 | |||
253 | - (BOOL)scanNumber:(NSNumber **)outValue | ||
254 | { | ||
255 | NSString *theString = NULL; | ||
256 | if ([self scanCharactersFromSet:sDoubleCharacters intoString:&theString]) | ||
257 | { | ||
258 | if ([theString rangeOfString:@"."].location != NSNotFound) | ||
259 | { | ||
260 | if (outValue) | ||
261 | { | ||
262 | *outValue = [NSDecimalNumber decimalNumberWithString:theString]; | ||
263 | } | ||
264 | return(YES); | ||
265 | } | ||
266 | else if ([theString rangeOfString:@"-"].location != NSNotFound) | ||
267 | { | ||
268 | if (outValue != NULL) | ||
269 | { | ||
270 | *outValue = [NSNumber numberWithLongLong:[theString longLongValue]]; | ||
271 | } | ||
272 | return(YES); | ||
273 | } | ||
274 | else | ||
275 | { | ||
276 | if (outValue != NULL) | ||
277 | { | ||
278 | *outValue = [NSNumber numberWithUnsignedLongLong:strtoull([theString UTF8String], NULL, 0)]; | ||
279 | } | ||
280 | return(YES); | ||
281 | } | ||
282 | |||
283 | } | ||
284 | return(NO); | ||
285 | } | ||
286 | |||
287 | - (BOOL)scanDecimalNumber:(NSDecimalNumber **)outValue; | ||
288 | { | ||
289 | NSString *theString = NULL; | ||
290 | if ([self scanCharactersFromSet:sDoubleCharacters intoString:&theString]) | ||
291 | { | ||
292 | if (outValue) | ||
293 | { | ||
294 | *outValue = [NSDecimalNumber decimalNumberWithString:theString]; | ||
295 | } | ||
296 | return(YES); | ||
297 | } | ||
298 | return(NO); | ||
299 | } | ||
300 | |||
301 | - (BOOL)scanDataOfLength:(NSUInteger)inLength intoData:(NSData **)outData; | ||
302 | { | ||
303 | if (self.bytesRemaining < inLength) | ||
304 | { | ||
305 | return(NO); | ||
306 | } | ||
307 | |||
308 | if (outData) | ||
309 | { | ||
310 | *outData = [NSData dataWithBytes:current length:inLength]; | ||
311 | } | ||
312 | |||
313 | current += inLength; | ||
314 | return(YES); | ||
315 | } | ||
316 | |||
317 | |||
318 | - (void)skipWhitespace | ||
319 | { | ||
320 | u_int8_t *P; | ||
321 | for (P = current; P < end && (isspace(*P)); ++P) | ||
322 | ; | ||
323 | |||
324 | current = P; | ||
325 | } | ||
326 | |||
327 | - (NSString *)remainingString | ||
328 | { | ||
329 | NSData *theRemainingData = [NSData dataWithBytes:current length:end - current]; | ||
330 | NSString *theString = [[[NSString alloc] initWithData:theRemainingData encoding:NSUTF8StringEncoding] autorelease]; | ||
331 | return(theString); | ||
332 | } | ||
333 | |||
334 | - (NSData *)remainingData; | ||
335 | { | ||
336 | NSData *theRemainingData = [NSData dataWithBytes:current length:end - current]; | ||
337 | return(theRemainingData); | ||
338 | } | ||
339 | |||
340 | @end | ||
diff --git a/libs/TouchJSON/Extensions/CDataScanner_Extensions.h b/libs/TouchJSON/Extensions/CDataScanner_Extensions.h new file mode 100755 index 0000000..cde1dbb --- /dev/null +++ b/libs/TouchJSON/Extensions/CDataScanner_Extensions.h | |||
@@ -0,0 +1,40 @@ | |||
1 | // | ||
2 | // CDataScanner_Extensions.h | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 12/08/2005. | ||
6 | // Copyright 2005 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import "CDataScanner.h" | ||
31 | |||
32 | @interface CDataScanner (CDataScanner_Extensions) | ||
33 | |||
34 | - (BOOL)scanCStyleComment:(NSString **)outComment; | ||
35 | - (BOOL)scanCPlusPlusStyleComment:(NSString **)outComment; | ||
36 | |||
37 | - (NSUInteger)lineOfScanLocation; | ||
38 | - (NSDictionary *)userInfoForScanLocation; | ||
39 | |||
40 | @end | ||
diff --git a/libs/TouchJSON/Extensions/CDataScanner_Extensions.m b/libs/TouchJSON/Extensions/CDataScanner_Extensions.m new file mode 100755 index 0000000..90dbbda --- /dev/null +++ b/libs/TouchJSON/Extensions/CDataScanner_Extensions.m | |||
@@ -0,0 +1,135 @@ | |||
1 | // | ||
2 | // CDataScanner_Extensions.m | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 12/08/2005. | ||
6 | // Copyright 2005 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import "CDataScanner_Extensions.h" | ||
31 | |||
32 | #define LF 0x000a // Line Feed | ||
33 | #define FF 0x000c // Form Feed | ||
34 | #define CR 0x000d // Carriage Return | ||
35 | #define NEL 0x0085 // Next Line | ||
36 | #define LS 0x2028 // Line Separator | ||
37 | #define PS 0x2029 // Paragraph Separator | ||
38 | |||
39 | @implementation CDataScanner (CDataScanner_Extensions) | ||
40 | |||
41 | - (BOOL)scanCStyleComment:(NSString **)outComment | ||
42 | { | ||
43 | if ([self scanString:@"/*" intoString:NULL] == YES) | ||
44 | { | ||
45 | NSString *theComment = NULL; | ||
46 | if ([self scanUpToString:@"*/" intoString:&theComment] == NO) | ||
47 | [NSException raise:NSGenericException format:@"Started to scan a C style comment but it wasn't terminated."]; | ||
48 | |||
49 | if ([theComment rangeOfString:@"/*"].location != NSNotFound) | ||
50 | [NSException raise:NSGenericException format:@"C style comments should not be nested."]; | ||
51 | |||
52 | if ([self scanString:@"*/" intoString:NULL] == NO) | ||
53 | [NSException raise:NSGenericException format:@"C style comment did not end correctly."]; | ||
54 | |||
55 | if (outComment != NULL) | ||
56 | *outComment = theComment; | ||
57 | |||
58 | return(YES); | ||
59 | } | ||
60 | else | ||
61 | { | ||
62 | return(NO); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | - (BOOL)scanCPlusPlusStyleComment:(NSString **)outComment | ||
67 | { | ||
68 | if ([self scanString:@"//" intoString:NULL] == YES) | ||
69 | { | ||
70 | unichar theCharacters[] = { LF, FF, CR, NEL, LS, PS, }; | ||
71 | NSCharacterSet *theLineBreaksCharacterSet = [NSCharacterSet characterSetWithCharactersInString:[NSString stringWithCharacters:theCharacters length:sizeof(theCharacters) / sizeof(*theCharacters)]]; | ||
72 | |||
73 | NSString *theComment = NULL; | ||
74 | [self scanUpToCharactersFromSet:theLineBreaksCharacterSet intoString:&theComment]; | ||
75 | [self scanCharactersFromSet:theLineBreaksCharacterSet intoString:NULL]; | ||
76 | |||
77 | if (outComment != NULL) | ||
78 | *outComment = theComment; | ||
79 | |||
80 | return(YES); | ||
81 | } | ||
82 | else | ||
83 | { | ||
84 | return(NO); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | - (NSUInteger)lineOfScanLocation | ||
89 | { | ||
90 | NSUInteger theLine = 0; | ||
91 | for (const u_int8_t *C = start; C < current; ++C) | ||
92 | { | ||
93 | // TODO: JIW What about MS-DOS line endings you bastard! (Also other unicode line endings) | ||
94 | if (*C == '\n' || *C == '\r') | ||
95 | { | ||
96 | ++theLine; | ||
97 | } | ||
98 | } | ||
99 | return(theLine); | ||
100 | } | ||
101 | |||
102 | - (NSDictionary *)userInfoForScanLocation | ||
103 | { | ||
104 | NSUInteger theLine = 0; | ||
105 | const u_int8_t *theLineStart = start; | ||
106 | for (const u_int8_t *C = start; C < current; ++C) | ||
107 | { | ||
108 | if (*C == '\n' || *C == '\r') | ||
109 | { | ||
110 | theLineStart = C - 1; | ||
111 | ++theLine; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | NSUInteger theCharacter = current - theLineStart; | ||
116 | |||
117 | NSRange theStartRange = NSIntersectionRange((NSRange){ .location = MAX((NSInteger)self.scanLocation - 20, 0), .length = 20 + (NSInteger)self.scanLocation - 20 }, (NSRange){ .location = 0, .length = self.data.length }); | ||
118 | NSRange theEndRange = NSIntersectionRange((NSRange){ .location = self.scanLocation, .length = 20 }, (NSRange){ .location = 0, .length = self.data.length }); | ||
119 | |||
120 | |||
121 | NSString *theSnippet = [NSString stringWithFormat:@"%@!HERE>!%@", | ||
122 | [[[NSString alloc] initWithData:[self.data subdataWithRange:theStartRange] encoding:NSUTF8StringEncoding] autorelease], | ||
123 | [[[NSString alloc] initWithData:[self.data subdataWithRange:theEndRange] encoding:NSUTF8StringEncoding] autorelease] | ||
124 | ]; | ||
125 | |||
126 | NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: | ||
127 | [NSNumber numberWithUnsignedInteger:theLine], @"line", | ||
128 | [NSNumber numberWithUnsignedInteger:theCharacter], @"character", | ||
129 | [NSNumber numberWithUnsignedInteger:self.scanLocation], @"location", | ||
130 | theSnippet, @"snippet", | ||
131 | NULL]; | ||
132 | return(theUserInfo); | ||
133 | } | ||
134 | |||
135 | @end | ||
diff --git a/libs/TouchJSON/Extensions/NSDictionary_JSONExtensions.h b/libs/TouchJSON/Extensions/NSDictionary_JSONExtensions.h new file mode 100755 index 0000000..6e611d0 --- /dev/null +++ b/libs/TouchJSON/Extensions/NSDictionary_JSONExtensions.h | |||
@@ -0,0 +1,37 @@ | |||
1 | // | ||
2 | // NSDictionary_JSONExtensions.h | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 04/17/08. | ||
6 | // Copyright 2008 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import <Foundation/Foundation.h> | ||
31 | |||
32 | @interface NSDictionary (NSDictionary_JSONExtensions) | ||
33 | |||
34 | + (id)dictionaryWithJSONData:(NSData *)inData error:(NSError **)outError; | ||
35 | + (id)dictionaryWithJSONString:(NSString *)inJSON error:(NSError **)outError; | ||
36 | |||
37 | @end | ||
diff --git a/libs/TouchJSON/Extensions/NSDictionary_JSONExtensions.m b/libs/TouchJSON/Extensions/NSDictionary_JSONExtensions.m new file mode 100755 index 0000000..c0bb43c --- /dev/null +++ b/libs/TouchJSON/Extensions/NSDictionary_JSONExtensions.m | |||
@@ -0,0 +1,47 @@ | |||
1 | // | ||
2 | // NSDictionary_JSONExtensions.m | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 04/17/08. | ||
6 | // Copyright 2008 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import "NSDictionary_JSONExtensions.h" | ||
31 | |||
32 | #import "CJSONDeserializer.h" | ||
33 | |||
34 | @implementation NSDictionary (NSDictionary_JSONExtensions) | ||
35 | |||
36 | + (id)dictionaryWithJSONData:(NSData *)inData error:(NSError **)outError | ||
37 | { | ||
38 | return([[CJSONDeserializer deserializer] deserialize:inData error:outError]); | ||
39 | } | ||
40 | |||
41 | + (id)dictionaryWithJSONString:(NSString *)inJSON error:(NSError **)outError; | ||
42 | { | ||
43 | NSData *theData = [inJSON dataUsingEncoding:NSUTF8StringEncoding]; | ||
44 | return([self dictionaryWithJSONData:theData error:outError]); | ||
45 | } | ||
46 | |||
47 | @end | ||
diff --git a/libs/TouchJSON/JSON/CJSONDeserializer.h b/libs/TouchJSON/JSON/CJSONDeserializer.h new file mode 100755 index 0000000..0c3ed02 --- /dev/null +++ b/libs/TouchJSON/JSON/CJSONDeserializer.h | |||
@@ -0,0 +1,63 @@ | |||
1 | // | ||
2 | // CJSONDeserializer.h | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 12/15/2005. | ||
6 | // Copyright 2005 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import <Foundation/Foundation.h> | ||
31 | |||
32 | #import "CJSONScanner.h" | ||
33 | |||
34 | extern NSString *const kJSONDeserializerErrorDomain /* = @"CJSONDeserializerErrorDomain" */; | ||
35 | |||
36 | enum { | ||
37 | kJSONDeserializationOptions_MutableContainers = kJSONScannerOptions_MutableContainers, | ||
38 | kJSONDeserializationOptions_MutableLeaves = kJSONScannerOptions_MutableLeaves, | ||
39 | }; | ||
40 | typedef NSUInteger EJSONDeserializationOptions; | ||
41 | |||
42 | @class CJSONScanner; | ||
43 | |||
44 | @interface CJSONDeserializer : NSObject { | ||
45 | CJSONScanner *scanner; | ||
46 | EJSONDeserializationOptions options; | ||
47 | } | ||
48 | |||
49 | @property (readwrite, nonatomic, retain) CJSONScanner *scanner; | ||
50 | /// Object to return instead when a null encountered in the JSON. Defaults to NSNull. Setting to null causes the scanner to skip null values. | ||
51 | @property (readwrite, nonatomic, retain) id nullObject; | ||
52 | /// JSON must be encoded in Unicode (UTF-8, UTF-16 or UTF-32). Use this if you expect to get the JSON in another encoding. | ||
53 | @property (readwrite, nonatomic, assign) NSStringEncoding allowedEncoding; | ||
54 | @property (readwrite, nonatomic, assign) EJSONDeserializationOptions options; | ||
55 | |||
56 | + (id)deserializer; | ||
57 | |||
58 | - (id)deserialize:(NSData *)inData error:(NSError **)outError; | ||
59 | |||
60 | - (id)deserializeAsDictionary:(NSData *)inData error:(NSError **)outError; | ||
61 | - (id)deserializeAsArray:(NSData *)inData error:(NSError **)outError; | ||
62 | |||
63 | @end | ||
diff --git a/libs/TouchJSON/JSON/CJSONDeserializer.m b/libs/TouchJSON/JSON/CJSONDeserializer.m new file mode 100755 index 0000000..27a2d03 --- /dev/null +++ b/libs/TouchJSON/JSON/CJSONDeserializer.m | |||
@@ -0,0 +1,161 @@ | |||
1 | // | ||
2 | // CJSONDeserializer.m | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 12/15/2005. | ||
6 | // Copyright 2005 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import "CJSONDeserializer.h" | ||
31 | |||
32 | #import "CJSONScanner.h" | ||
33 | #import "CDataScanner.h" | ||
34 | |||
35 | NSString *const kJSONDeserializerErrorDomain = @"CJSONDeserializerErrorDomain"; | ||
36 | |||
37 | @interface CJSONDeserializer () | ||
38 | @end | ||
39 | |||
40 | @implementation CJSONDeserializer | ||
41 | |||
42 | @synthesize scanner; | ||
43 | @synthesize options; | ||
44 | |||
45 | + (id)deserializer | ||
46 | { | ||
47 | return([[[self alloc] init] autorelease]); | ||
48 | } | ||
49 | |||
50 | - (id)init | ||
51 | { | ||
52 | if ((self = [super init]) != NULL) | ||
53 | { | ||
54 | } | ||
55 | return(self); | ||
56 | } | ||
57 | |||
58 | - (void)dealloc | ||
59 | { | ||
60 | [scanner release]; | ||
61 | scanner = NULL; | ||
62 | // | ||
63 | [super dealloc]; | ||
64 | } | ||
65 | |||
66 | #pragma mark - | ||
67 | |||
68 | - (CJSONScanner *)scanner | ||
69 | { | ||
70 | if (scanner == NULL) | ||
71 | { | ||
72 | scanner = [[CJSONScanner alloc] init]; | ||
73 | } | ||
74 | return(scanner); | ||
75 | } | ||
76 | |||
77 | - (id)nullObject | ||
78 | { | ||
79 | return(self.scanner.nullObject); | ||
80 | } | ||
81 | |||
82 | - (void)setNullObject:(id)inNullObject | ||
83 | { | ||
84 | self.scanner.nullObject = inNullObject; | ||
85 | } | ||
86 | |||
87 | #pragma mark - | ||
88 | |||
89 | - (NSStringEncoding)allowedEncoding | ||
90 | { | ||
91 | return(self.scanner.allowedEncoding); | ||
92 | } | ||
93 | |||
94 | - (void)setAllowedEncoding:(NSStringEncoding)inAllowedEncoding | ||
95 | { | ||
96 | self.scanner.allowedEncoding = inAllowedEncoding; | ||
97 | } | ||
98 | |||
99 | #pragma mark - | ||
100 | |||
101 | - (id)deserialize:(NSData *)inData error:(NSError **)outError | ||
102 | { | ||
103 | if (inData == NULL || [inData length] == 0) | ||
104 | { | ||
105 | if (outError) | ||
106 | *outError = [NSError errorWithDomain:kJSONDeserializerErrorDomain code:kJSONScannerErrorCode_NothingToScan userInfo:NULL]; | ||
107 | |||
108 | return(NULL); | ||
109 | } | ||
110 | if ([self.scanner setData:inData error:outError] == NO) | ||
111 | { | ||
112 | return(NULL); | ||
113 | } | ||
114 | id theObject = NULL; | ||
115 | if ([self.scanner scanJSONObject:&theObject error:outError] == YES) | ||
116 | return(theObject); | ||
117 | else | ||
118 | return(NULL); | ||
119 | } | ||
120 | |||
121 | - (id)deserializeAsDictionary:(NSData *)inData error:(NSError **)outError | ||
122 | { | ||
123 | if (inData == NULL || [inData length] == 0) | ||
124 | { | ||
125 | if (outError) | ||
126 | *outError = [NSError errorWithDomain:kJSONDeserializerErrorDomain code:kJSONScannerErrorCode_NothingToScan userInfo:NULL]; | ||
127 | |||
128 | return(NULL); | ||
129 | } | ||
130 | if ([self.scanner setData:inData error:outError] == NO) | ||
131 | { | ||
132 | return(NULL); | ||
133 | } | ||
134 | NSDictionary *theDictionary = NULL; | ||
135 | if ([self.scanner scanJSONDictionary:&theDictionary error:outError] == YES) | ||
136 | return(theDictionary); | ||
137 | else | ||
138 | return(NULL); | ||
139 | } | ||
140 | |||
141 | - (id)deserializeAsArray:(NSData *)inData error:(NSError **)outError | ||
142 | { | ||
143 | if (inData == NULL || [inData length] == 0) | ||
144 | { | ||
145 | if (outError) | ||
146 | *outError = [NSError errorWithDomain:kJSONDeserializerErrorDomain code:kJSONScannerErrorCode_NothingToScan userInfo:NULL]; | ||
147 | |||
148 | return(NULL); | ||
149 | } | ||
150 | if ([self.scanner setData:inData error:outError] == NO) | ||
151 | { | ||
152 | return(NULL); | ||
153 | } | ||
154 | NSArray *theArray = NULL; | ||
155 | if ([self.scanner scanJSONArray:&theArray error:outError] == YES) | ||
156 | return(theArray); | ||
157 | else | ||
158 | return(NULL); | ||
159 | } | ||
160 | |||
161 | @end | ||
diff --git a/libs/TouchJSON/JSON/CJSONScanner.h b/libs/TouchJSON/JSON/CJSONScanner.h new file mode 100755 index 0000000..d410893 --- /dev/null +++ b/libs/TouchJSON/JSON/CJSONScanner.h | |||
@@ -0,0 +1,95 @@ | |||
1 | // | ||
2 | // CJSONScanner.h | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 12/07/2005. | ||
6 | // Copyright 2005 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import "CDataScanner.h" | ||
31 | |||
32 | enum { | ||
33 | kJSONScannerOptions_MutableContainers = 0x1, | ||
34 | kJSONScannerOptions_MutableLeaves = 0x2, | ||
35 | }; | ||
36 | typedef NSUInteger EJSONScannerOptions; | ||
37 | |||
38 | /// CDataScanner subclass that understands JSON syntax natively. You should generally use CJSONDeserializer instead of this class. (TODO - this could have been a category?) | ||
39 | @interface CJSONScanner : CDataScanner { | ||
40 | BOOL strictEscapeCodes; | ||
41 | id nullObject; | ||
42 | NSStringEncoding allowedEncoding; | ||
43 | EJSONScannerOptions options; | ||
44 | } | ||
45 | |||
46 | @property (readwrite, nonatomic, assign) BOOL strictEscapeCodes; | ||
47 | @property (readwrite, nonatomic, retain) id nullObject; | ||
48 | @property (readwrite, nonatomic, assign) NSStringEncoding allowedEncoding; | ||
49 | @property (readwrite, nonatomic, assign) EJSONScannerOptions options; | ||
50 | |||
51 | - (BOOL)setData:(NSData *)inData error:(NSError **)outError; | ||
52 | |||
53 | - (BOOL)scanJSONObject:(id *)outObject error:(NSError **)outError; | ||
54 | - (BOOL)scanJSONDictionary:(NSDictionary **)outDictionary error:(NSError **)outError; | ||
55 | - (BOOL)scanJSONArray:(NSArray **)outArray error:(NSError **)outError; | ||
56 | - (BOOL)scanJSONStringConstant:(NSString **)outStringConstant error:(NSError **)outError; | ||
57 | - (BOOL)scanJSONNumberConstant:(NSNumber **)outNumberConstant error:(NSError **)outError; | ||
58 | |||
59 | @end | ||
60 | |||
61 | extern NSString *const kJSONScannerErrorDomain /* = @"kJSONScannerErrorDomain" */; | ||
62 | |||
63 | typedef enum { | ||
64 | |||
65 | // Fundamental scanning errors | ||
66 | kJSONScannerErrorCode_NothingToScan = -11, | ||
67 | kJSONScannerErrorCode_CouldNotDecodeData = -12, | ||
68 | kJSONScannerErrorCode_CouldNotSerializeData = -13, | ||
69 | kJSONScannerErrorCode_CouldNotSerializeObject = -14, | ||
70 | kJSONScannerErrorCode_CouldNotScanObject = -15, | ||
71 | |||
72 | // Dictionary scanning | ||
73 | kJSONScannerErrorCode_DictionaryStartCharacterMissing = -101, | ||
74 | kJSONScannerErrorCode_DictionaryKeyScanFailed = -102, | ||
75 | kJSONScannerErrorCode_DictionaryKeyNotTerminated = -103, | ||
76 | kJSONScannerErrorCode_DictionaryValueScanFailed = -104, | ||
77 | kJSONScannerErrorCode_DictionaryKeyValuePairNoDelimiter = -105, | ||
78 | kJSONScannerErrorCode_DictionaryNotTerminated = -106, | ||
79 | |||
80 | // Array scanning | ||
81 | kJSONScannerErrorCode_ArrayStartCharacterMissing = -201, | ||
82 | kJSONScannerErrorCode_ArrayValueScanFailed = -202, | ||
83 | kJSONScannerErrorCode_ArrayValueIsNull = -203, | ||
84 | kJSONScannerErrorCode_ArrayNotTerminated = -204, | ||
85 | |||
86 | // String scanning | ||
87 | kJSONScannerErrorCode_StringNotStartedWithBackslash = -301, | ||
88 | kJSONScannerErrorCode_StringUnicodeNotDecoded = -302, | ||
89 | kJSONScannerErrorCode_StringUnknownEscapeCode = -303, | ||
90 | kJSONScannerErrorCode_StringNotTerminated = -304, | ||
91 | |||
92 | // Number scanning | ||
93 | kJSONScannerErrorCode_NumberNotScannable = -401 | ||
94 | |||
95 | } EJSONScannerErrorCode; | ||
diff --git a/libs/TouchJSON/JSON/CJSONScanner.m b/libs/TouchJSON/JSON/CJSONScanner.m new file mode 100755 index 0000000..c5ffeb4 --- /dev/null +++ b/libs/TouchJSON/JSON/CJSONScanner.m | |||
@@ -0,0 +1,676 @@ | |||
1 | // | ||
2 | // CJSONScanner.m | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 12/07/2005. | ||
6 | // Copyright 2005 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import "CJSONScanner.h" | ||
31 | |||
32 | #import "CDataScanner_Extensions.h" | ||
33 | |||
34 | #if !defined(TREAT_COMMENTS_AS_WHITESPACE) | ||
35 | #define TREAT_COMMENTS_AS_WHITESPACE 0 | ||
36 | #endif // !defined(TREAT_COMMENTS_AS_WHITESPACE) | ||
37 | |||
38 | NSString *const kJSONScannerErrorDomain = @"kJSONScannerErrorDomain"; | ||
39 | |||
40 | inline static int HexToInt(char inCharacter) | ||
41 | { | ||
42 | int theValues[] = { 0x0 /* 48 '0' */, 0x1 /* 49 '1' */, 0x2 /* 50 '2' */, 0x3 /* 51 '3' */, 0x4 /* 52 '4' */, 0x5 /* 53 '5' */, 0x6 /* 54 '6' */, 0x7 /* 55 '7' */, 0x8 /* 56 '8' */, 0x9 /* 57 '9' */, -1 /* 58 ':' */, -1 /* 59 ';' */, -1 /* 60 '<' */, -1 /* 61 '=' */, -1 /* 62 '>' */, -1 /* 63 '?' */, -1 /* 64 '@' */, 0xa /* 65 'A' */, 0xb /* 66 'B' */, 0xc /* 67 'C' */, 0xd /* 68 'D' */, 0xe /* 69 'E' */, 0xf /* 70 'F' */, -1 /* 71 'G' */, -1 /* 72 'H' */, -1 /* 73 'I' */, -1 /* 74 'J' */, -1 /* 75 'K' */, -1 /* 76 'L' */, -1 /* 77 'M' */, -1 /* 78 'N' */, -1 /* 79 'O' */, -1 /* 80 'P' */, -1 /* 81 'Q' */, -1 /* 82 'R' */, -1 /* 83 'S' */, -1 /* 84 'T' */, -1 /* 85 'U' */, -1 /* 86 'V' */, -1 /* 87 'W' */, -1 /* 88 'X' */, -1 /* 89 'Y' */, -1 /* 90 'Z' */, -1 /* 91 '[' */, -1 /* 92 '\' */, -1 /* 93 ']' */, -1 /* 94 '^' */, -1 /* 95 '_' */, -1 /* 96 '`' */, 0xa /* 97 'a' */, 0xb /* 98 'b' */, 0xc /* 99 'c' */, 0xd /* 100 'd' */, 0xe /* 101 'e' */, 0xf /* 102 'f' */, }; | ||
43 | if (inCharacter >= '0' && inCharacter <= 'f') | ||
44 | return(theValues[inCharacter - '0']); | ||
45 | else | ||
46 | return(-1); | ||
47 | } | ||
48 | |||
49 | @interface CJSONScanner () | ||
50 | - (BOOL)scanNotQuoteCharactersIntoString:(NSString **)outValue; | ||
51 | @end | ||
52 | |||
53 | #pragma mark - | ||
54 | |||
55 | @implementation CJSONScanner | ||
56 | |||
57 | @synthesize strictEscapeCodes; | ||
58 | @synthesize nullObject; | ||
59 | @synthesize allowedEncoding; | ||
60 | @synthesize options; | ||
61 | |||
62 | - (id)init | ||
63 | { | ||
64 | if ((self = [super init]) != NULL) | ||
65 | { | ||
66 | strictEscapeCodes = NO; | ||
67 | nullObject = [[NSNull null] retain]; | ||
68 | } | ||
69 | return(self); | ||
70 | } | ||
71 | |||
72 | - (void)dealloc | ||
73 | { | ||
74 | [nullObject release]; | ||
75 | nullObject = NULL; | ||
76 | // | ||
77 | [super dealloc]; | ||
78 | } | ||
79 | |||
80 | #pragma mark - | ||
81 | |||
82 | - (BOOL)setData:(NSData *)inData error:(NSError **)outError; | ||
83 | { | ||
84 | NSData *theData = inData; | ||
85 | if (theData && theData.length >= 4) | ||
86 | { | ||
87 | // This code is lame, but it works. Because the first character of any JSON string will always be a (ascii) control character we can work out the Unicode encoding by the bit pattern. See section 3 of http://www.ietf.org/rfc/rfc4627.txt | ||
88 | const char *theChars = theData.bytes; | ||
89 | NSStringEncoding theEncoding = NSUTF8StringEncoding; | ||
90 | if (theChars[0] != 0 && theChars[1] == 0) | ||
91 | { | ||
92 | if (theChars[2] != 0 && theChars[3] == 0) | ||
93 | theEncoding = NSUTF16LittleEndianStringEncoding; | ||
94 | else if (theChars[2] == 0 && theChars[3] == 0) | ||
95 | theEncoding = NSUTF32LittleEndianStringEncoding; | ||
96 | } | ||
97 | else if (theChars[0] == 0 && theChars[2] == 0 && theChars[3] != 0) | ||
98 | { | ||
99 | if (theChars[1] == 0) | ||
100 | theEncoding = NSUTF32BigEndianStringEncoding; | ||
101 | else if (theChars[1] != 0) | ||
102 | theEncoding = NSUTF16BigEndianStringEncoding; | ||
103 | } | ||
104 | |||
105 | NSString *theString = [[NSString alloc] initWithData:theData encoding:theEncoding]; | ||
106 | if (theString == NULL && self.allowedEncoding != 0) | ||
107 | { | ||
108 | theString = [[NSString alloc] initWithData:theData encoding:self.allowedEncoding]; | ||
109 | } | ||
110 | theData = [theString dataUsingEncoding:NSUTF8StringEncoding]; | ||
111 | [theString release]; | ||
112 | } | ||
113 | |||
114 | if (theData) | ||
115 | { | ||
116 | [super setData:theData]; | ||
117 | return(YES); | ||
118 | } | ||
119 | else | ||
120 | { | ||
121 | if (outError) | ||
122 | { | ||
123 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
124 | @"Could not scan data. Data wasn't encoded properly?", NSLocalizedDescriptionKey, | ||
125 | NULL]; | ||
126 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
127 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_CouldNotDecodeData userInfo:theUserInfo]; | ||
128 | } | ||
129 | return(NO); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | - (void)setData:(NSData *)inData | ||
134 | { | ||
135 | [self setData:inData error:NULL]; | ||
136 | } | ||
137 | |||
138 | #pragma mark - | ||
139 | |||
140 | - (BOOL)scanJSONObject:(id *)outObject error:(NSError **)outError | ||
141 | { | ||
142 | BOOL theResult = YES; | ||
143 | |||
144 | [self skipWhitespace]; | ||
145 | |||
146 | id theObject = NULL; | ||
147 | |||
148 | const unichar C = [self currentCharacter]; | ||
149 | switch (C) | ||
150 | { | ||
151 | case 't': | ||
152 | if ([self scanUTF8String:"true" intoString:NULL]) | ||
153 | { | ||
154 | theObject = [NSNumber numberWithBool:YES]; | ||
155 | } | ||
156 | break; | ||
157 | case 'f': | ||
158 | if ([self scanUTF8String:"false" intoString:NULL]) | ||
159 | { | ||
160 | theObject = [NSNumber numberWithBool:NO]; | ||
161 | } | ||
162 | break; | ||
163 | case 'n': | ||
164 | if ([self scanUTF8String:"null" intoString:NULL]) | ||
165 | { | ||
166 | theObject = self.nullObject; | ||
167 | } | ||
168 | break; | ||
169 | case '\"': | ||
170 | case '\'': | ||
171 | theResult = [self scanJSONStringConstant:&theObject error:outError]; | ||
172 | break; | ||
173 | case '0': | ||
174 | case '1': | ||
175 | case '2': | ||
176 | case '3': | ||
177 | case '4': | ||
178 | case '5': | ||
179 | case '6': | ||
180 | case '7': | ||
181 | case '8': | ||
182 | case '9': | ||
183 | case '-': | ||
184 | theResult = [self scanJSONNumberConstant:&theObject error:outError]; | ||
185 | break; | ||
186 | case '{': | ||
187 | theResult = [self scanJSONDictionary:&theObject error:outError]; | ||
188 | break; | ||
189 | case '[': | ||
190 | theResult = [self scanJSONArray:&theObject error:outError]; | ||
191 | break; | ||
192 | default: | ||
193 | theResult = NO; | ||
194 | if (outError) | ||
195 | { | ||
196 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
197 | @"Could not scan object. Character not a valid JSON character.", NSLocalizedDescriptionKey, | ||
198 | NULL]; | ||
199 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
200 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_CouldNotScanObject userInfo:theUserInfo]; | ||
201 | } | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | if (outObject != NULL) | ||
206 | *outObject = theObject; | ||
207 | |||
208 | return(theResult); | ||
209 | } | ||
210 | |||
211 | - (BOOL)scanJSONDictionary:(NSDictionary **)outDictionary error:(NSError **)outError | ||
212 | { | ||
213 | NSUInteger theScanLocation = [self scanLocation]; | ||
214 | |||
215 | [self skipWhitespace]; | ||
216 | |||
217 | if ([self scanCharacter:'{'] == NO) | ||
218 | { | ||
219 | if (outError) | ||
220 | { | ||
221 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
222 | @"Could not scan dictionary. Dictionary that does not start with '{' character.", NSLocalizedDescriptionKey, | ||
223 | NULL]; | ||
224 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
225 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryStartCharacterMissing userInfo:theUserInfo]; | ||
226 | } | ||
227 | return(NO); | ||
228 | } | ||
229 | |||
230 | NSMutableDictionary *theDictionary = [[NSMutableDictionary alloc] init]; | ||
231 | |||
232 | while ([self currentCharacter] != '}') | ||
233 | { | ||
234 | [self skipWhitespace]; | ||
235 | |||
236 | if ([self currentCharacter] == '}') | ||
237 | break; | ||
238 | |||
239 | NSString *theKey = NULL; | ||
240 | if ([self scanJSONStringConstant:&theKey error:outError] == NO) | ||
241 | { | ||
242 | [self setScanLocation:theScanLocation]; | ||
243 | if (outError) | ||
244 | { | ||
245 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
246 | @"Could not scan dictionary. Failed to scan a key.", NSLocalizedDescriptionKey, | ||
247 | NULL]; | ||
248 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
249 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryKeyScanFailed userInfo:theUserInfo]; | ||
250 | } | ||
251 | [theDictionary release]; | ||
252 | return(NO); | ||
253 | } | ||
254 | |||
255 | [self skipWhitespace]; | ||
256 | |||
257 | if ([self scanCharacter:':'] == NO) | ||
258 | { | ||
259 | [self setScanLocation:theScanLocation]; | ||
260 | if (outError) | ||
261 | { | ||
262 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
263 | @"Could not scan dictionary. Key was not terminated with a ':' character.", NSLocalizedDescriptionKey, | ||
264 | NULL]; | ||
265 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
266 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryKeyNotTerminated userInfo:theUserInfo]; | ||
267 | } | ||
268 | [theDictionary release]; | ||
269 | return(NO); | ||
270 | } | ||
271 | |||
272 | id theValue = NULL; | ||
273 | if ([self scanJSONObject:&theValue error:outError] == NO) | ||
274 | { | ||
275 | [self setScanLocation:theScanLocation]; | ||
276 | if (outError) | ||
277 | { | ||
278 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
279 | @"Could not scan dictionary. Failed to scan a value.", NSLocalizedDescriptionKey, | ||
280 | NULL]; | ||
281 | |||
282 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
283 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryValueScanFailed userInfo:theUserInfo]; | ||
284 | } | ||
285 | [theDictionary release]; | ||
286 | return(NO); | ||
287 | } | ||
288 | |||
289 | if (theValue == NULL && self.nullObject == NULL) | ||
290 | { | ||
291 | // If the value is a null and nullObject is also null then we're skipping this key/value pair. | ||
292 | } | ||
293 | else | ||
294 | { | ||
295 | [theDictionary setValue:theValue forKey:theKey]; | ||
296 | } | ||
297 | |||
298 | [self skipWhitespace]; | ||
299 | if ([self scanCharacter:','] == NO) | ||
300 | { | ||
301 | if ([self currentCharacter] != '}') | ||
302 | { | ||
303 | [self setScanLocation:theScanLocation]; | ||
304 | if (outError) | ||
305 | { | ||
306 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
307 | @"Could not scan dictionary. Key value pairs not delimited with a ',' character.", NSLocalizedDescriptionKey, | ||
308 | NULL]; | ||
309 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
310 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryKeyValuePairNoDelimiter userInfo:theUserInfo]; | ||
311 | } | ||
312 | [theDictionary release]; | ||
313 | return(NO); | ||
314 | } | ||
315 | break; | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | [self skipWhitespace]; | ||
320 | if ([self currentCharacter] == '}') | ||
321 | break; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | if ([self scanCharacter:'}'] == NO) | ||
326 | { | ||
327 | [self setScanLocation:theScanLocation]; | ||
328 | if (outError) | ||
329 | { | ||
330 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
331 | @"Could not scan dictionary. Dictionary not terminated by a '}' character.", NSLocalizedDescriptionKey, | ||
332 | NULL]; | ||
333 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
334 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_DictionaryNotTerminated userInfo:theUserInfo]; | ||
335 | } | ||
336 | [theDictionary release]; | ||
337 | return(NO); | ||
338 | } | ||
339 | |||
340 | if (outDictionary != NULL) | ||
341 | { | ||
342 | if (self.options & kJSONScannerOptions_MutableContainers) | ||
343 | { | ||
344 | *outDictionary = [theDictionary autorelease]; | ||
345 | } | ||
346 | else | ||
347 | { | ||
348 | *outDictionary = [[theDictionary copy] autorelease]; | ||
349 | [theDictionary release]; | ||
350 | } | ||
351 | } | ||
352 | else | ||
353 | { | ||
354 | [theDictionary release]; | ||
355 | } | ||
356 | |||
357 | return(YES); | ||
358 | } | ||
359 | |||
360 | - (BOOL)scanJSONArray:(NSArray **)outArray error:(NSError **)outError | ||
361 | { | ||
362 | NSUInteger theScanLocation = [self scanLocation]; | ||
363 | |||
364 | [self skipWhitespace]; | ||
365 | |||
366 | if ([self scanCharacter:'['] == NO) | ||
367 | { | ||
368 | if (outError) | ||
369 | { | ||
370 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
371 | @"Could not scan array. Array not started by a '[' character.", NSLocalizedDescriptionKey, | ||
372 | NULL]; | ||
373 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
374 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_ArrayStartCharacterMissing userInfo:theUserInfo]; | ||
375 | } | ||
376 | return(NO); | ||
377 | } | ||
378 | |||
379 | NSMutableArray *theArray = [[NSMutableArray alloc] init]; | ||
380 | |||
381 | [self skipWhitespace]; | ||
382 | while ([self currentCharacter] != ']') | ||
383 | { | ||
384 | NSString *theValue = NULL; | ||
385 | if ([self scanJSONObject:&theValue error:outError] == NO) | ||
386 | { | ||
387 | [self setScanLocation:theScanLocation]; | ||
388 | if (outError) | ||
389 | { | ||
390 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
391 | @"Could not scan array. Could not scan a value.", NSLocalizedDescriptionKey, | ||
392 | NULL]; | ||
393 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
394 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_ArrayValueScanFailed userInfo:theUserInfo]; | ||
395 | } | ||
396 | [theArray release]; | ||
397 | return(NO); | ||
398 | } | ||
399 | |||
400 | if (theValue == NULL) | ||
401 | { | ||
402 | if (self.nullObject != NULL) | ||
403 | { | ||
404 | if (outError) | ||
405 | { | ||
406 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
407 | @"Could not scan array. Value is NULL.", NSLocalizedDescriptionKey, | ||
408 | NULL]; | ||
409 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
410 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_ArrayValueIsNull userInfo:theUserInfo]; | ||
411 | } | ||
412 | [theArray release]; | ||
413 | return(NO); | ||
414 | } | ||
415 | } | ||
416 | else | ||
417 | { | ||
418 | [theArray addObject:theValue]; | ||
419 | } | ||
420 | |||
421 | [self skipWhitespace]; | ||
422 | if ([self scanCharacter:','] == NO) | ||
423 | { | ||
424 | [self skipWhitespace]; | ||
425 | if ([self currentCharacter] != ']') | ||
426 | { | ||
427 | [self setScanLocation:theScanLocation]; | ||
428 | if (outError) | ||
429 | { | ||
430 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
431 | @"Could not scan array. Array not terminated by a ']' character.", NSLocalizedDescriptionKey, | ||
432 | NULL]; | ||
433 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
434 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_ArrayNotTerminated userInfo:theUserInfo]; | ||
435 | } | ||
436 | [theArray release]; | ||
437 | return(NO); | ||
438 | } | ||
439 | |||
440 | break; | ||
441 | } | ||
442 | [self skipWhitespace]; | ||
443 | } | ||
444 | |||
445 | [self skipWhitespace]; | ||
446 | |||
447 | if ([self scanCharacter:']'] == NO) | ||
448 | { | ||
449 | [self setScanLocation:theScanLocation]; | ||
450 | if (outError) | ||
451 | { | ||
452 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
453 | @"Could not scan array. Array not terminated by a ']' character.", NSLocalizedDescriptionKey, | ||
454 | NULL]; | ||
455 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
456 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_ArrayNotTerminated userInfo:theUserInfo]; | ||
457 | } | ||
458 | [theArray release]; | ||
459 | return(NO); | ||
460 | } | ||
461 | |||
462 | if (outArray != NULL) | ||
463 | { | ||
464 | if (self.options & kJSONScannerOptions_MutableContainers) | ||
465 | { | ||
466 | *outArray = [theArray autorelease]; | ||
467 | } | ||
468 | else | ||
469 | { | ||
470 | *outArray = [[theArray copy] autorelease]; | ||
471 | [theArray release]; | ||
472 | } | ||
473 | } | ||
474 | else | ||
475 | { | ||
476 | [theArray release]; | ||
477 | } | ||
478 | return(YES); | ||
479 | } | ||
480 | |||
481 | - (BOOL)scanJSONStringConstant:(NSString **)outStringConstant error:(NSError **)outError | ||
482 | { | ||
483 | NSUInteger theScanLocation = [self scanLocation]; | ||
484 | |||
485 | [self skipWhitespace]; | ||
486 | |||
487 | NSMutableString *theString = [[NSMutableString alloc] init]; | ||
488 | |||
489 | if ([self scanCharacter:'"'] == NO) | ||
490 | { | ||
491 | [self setScanLocation:theScanLocation]; | ||
492 | if (outError) | ||
493 | { | ||
494 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
495 | @"Could not scan string constant. String not started by a '\"' character.", NSLocalizedDescriptionKey, | ||
496 | NULL]; | ||
497 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
498 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_StringNotStartedWithBackslash userInfo:theUserInfo]; | ||
499 | } | ||
500 | [theString release]; | ||
501 | return(NO); | ||
502 | } | ||
503 | |||
504 | while ([self scanCharacter:'"'] == NO) | ||
505 | { | ||
506 | NSString *theStringChunk = NULL; | ||
507 | if ([self scanNotQuoteCharactersIntoString:&theStringChunk]) | ||
508 | { | ||
509 | CFStringAppend((CFMutableStringRef)theString, (CFStringRef)theStringChunk); | ||
510 | } | ||
511 | else if ([self scanCharacter:'\\'] == YES) | ||
512 | { | ||
513 | unichar theCharacter = [self scanCharacter]; | ||
514 | switch (theCharacter) | ||
515 | { | ||
516 | case '"': | ||
517 | case '\\': | ||
518 | case '/': | ||
519 | break; | ||
520 | case 'b': | ||
521 | theCharacter = '\b'; | ||
522 | break; | ||
523 | case 'f': | ||
524 | theCharacter = '\f'; | ||
525 | break; | ||
526 | case 'n': | ||
527 | theCharacter = '\n'; | ||
528 | break; | ||
529 | case 'r': | ||
530 | theCharacter = '\r'; | ||
531 | break; | ||
532 | case 't': | ||
533 | theCharacter = '\t'; | ||
534 | break; | ||
535 | case 'u': | ||
536 | { | ||
537 | theCharacter = 0; | ||
538 | |||
539 | int theShift; | ||
540 | for (theShift = 12; theShift >= 0; theShift -= 4) | ||
541 | { | ||
542 | const int theDigit = HexToInt([self scanCharacter]); | ||
543 | if (theDigit == -1) | ||
544 | { | ||
545 | [self setScanLocation:theScanLocation]; | ||
546 | if (outError) | ||
547 | { | ||
548 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
549 | @"Could not scan string constant. Unicode character could not be decoded.", NSLocalizedDescriptionKey, | ||
550 | NULL]; | ||
551 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
552 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_StringUnicodeNotDecoded userInfo:theUserInfo]; | ||
553 | } | ||
554 | [theString release]; | ||
555 | return(NO); | ||
556 | } | ||
557 | theCharacter |= (theDigit << theShift); | ||
558 | } | ||
559 | } | ||
560 | break; | ||
561 | default: | ||
562 | { | ||
563 | if (strictEscapeCodes == YES) | ||
564 | { | ||
565 | [self setScanLocation:theScanLocation]; | ||
566 | if (outError) | ||
567 | { | ||
568 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
569 | @"Could not scan string constant. Unknown escape code.", NSLocalizedDescriptionKey, | ||
570 | NULL]; | ||
571 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
572 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_StringUnknownEscapeCode userInfo:theUserInfo]; | ||
573 | } | ||
574 | [theString release]; | ||
575 | return(NO); | ||
576 | } | ||
577 | } | ||
578 | break; | ||
579 | } | ||
580 | CFStringAppendCharacters((CFMutableStringRef)theString, &theCharacter, 1); | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | if (outError) | ||
585 | { | ||
586 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
587 | @"Could not scan string constant. No terminating double quote character.", NSLocalizedDescriptionKey, | ||
588 | NULL]; | ||
589 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
590 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_StringNotTerminated userInfo:theUserInfo]; | ||
591 | } | ||
592 | [theString release]; | ||
593 | return(NO); | ||
594 | } | ||
595 | } | ||
596 | |||
597 | if (outStringConstant != NULL) | ||
598 | { | ||
599 | if (self.options & kJSONScannerOptions_MutableLeaves) | ||
600 | { | ||
601 | *outStringConstant = [theString autorelease]; | ||
602 | } | ||
603 | else | ||
604 | { | ||
605 | *outStringConstant = [[theString copy] autorelease]; | ||
606 | [theString release]; | ||
607 | } | ||
608 | } | ||
609 | else | ||
610 | { | ||
611 | [theString release]; | ||
612 | } | ||
613 | |||
614 | return(YES); | ||
615 | } | ||
616 | |||
617 | - (BOOL)scanJSONNumberConstant:(NSNumber **)outNumberConstant error:(NSError **)outError | ||
618 | { | ||
619 | NSNumber *theNumber = NULL; | ||
620 | |||
621 | [self skipWhitespace]; | ||
622 | |||
623 | if ([self scanNumber:&theNumber] == YES) | ||
624 | { | ||
625 | if (outNumberConstant != NULL) | ||
626 | *outNumberConstant = theNumber; | ||
627 | return(YES); | ||
628 | } | ||
629 | else | ||
630 | { | ||
631 | if (outError) | ||
632 | { | ||
633 | NSMutableDictionary *theUserInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: | ||
634 | @"Could not scan number constant.", NSLocalizedDescriptionKey, | ||
635 | NULL]; | ||
636 | [theUserInfo addEntriesFromDictionary:self.userInfoForScanLocation]; | ||
637 | *outError = [NSError errorWithDomain:kJSONScannerErrorDomain code:kJSONScannerErrorCode_NumberNotScannable userInfo:theUserInfo]; | ||
638 | } | ||
639 | return(NO); | ||
640 | } | ||
641 | } | ||
642 | |||
643 | #if TREAT_COMMENTS_AS_WHITESPACE | ||
644 | - (void)skipWhitespace | ||
645 | { | ||
646 | [super skipWhitespace]; | ||
647 | [self scanCStyleComment:NULL]; | ||
648 | [self scanCPlusPlusStyleComment:NULL]; | ||
649 | [super skipWhitespace]; | ||
650 | } | ||
651 | #endif // TREAT_COMMENTS_AS_WHITESPACE | ||
652 | |||
653 | #pragma mark - | ||
654 | |||
655 | - (BOOL)scanNotQuoteCharactersIntoString:(NSString **)outValue | ||
656 | { | ||
657 | u_int8_t *P; | ||
658 | for (P = current; P < end && *P != '\"' && *P != '\\'; ++P) | ||
659 | ; | ||
660 | |||
661 | if (P == current) | ||
662 | { | ||
663 | return(NO); | ||
664 | } | ||
665 | |||
666 | if (outValue) | ||
667 | { | ||
668 | *outValue = [[[NSString alloc] initWithBytes:current length:P - current encoding:NSUTF8StringEncoding] autorelease]; | ||
669 | } | ||
670 | |||
671 | current = P; | ||
672 | |||
673 | return(YES); | ||
674 | } | ||
675 | |||
676 | @end | ||
diff --git a/libs/TouchJSON/JSON/CJSONSerializer.h b/libs/TouchJSON/JSON/CJSONSerializer.h new file mode 100755 index 0000000..748a85c --- /dev/null +++ b/libs/TouchJSON/JSON/CJSONSerializer.h | |||
@@ -0,0 +1,53 @@ | |||
1 | // | ||
2 | // CJSONSerializer.h | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 12/07/2005. | ||
6 | // Copyright 2005 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import <Foundation/Foundation.h> | ||
31 | |||
32 | @interface CJSONSerializer : NSObject { | ||
33 | } | ||
34 | |||
35 | + (id)serializer; | ||
36 | |||
37 | - (BOOL)isValidJSONObject:(id)inObject; | ||
38 | |||
39 | /// Take any JSON compatible object (generally NSNull, NSNumber, NSString, NSArray and NSDictionary) and produce an NSData containing the serialized JSON. | ||
40 | - (NSData *)serializeObject:(id)inObject error:(NSError **)outError; | ||
41 | |||
42 | - (NSData *)serializeNull:(NSNull *)inNull error:(NSError **)outError; | ||
43 | - (NSData *)serializeNumber:(NSNumber *)inNumber error:(NSError **)outError; | ||
44 | - (NSData *)serializeString:(NSString *)inString error:(NSError **)outError; | ||
45 | - (NSData *)serializeArray:(NSArray *)inArray error:(NSError **)outError; | ||
46 | - (NSData *)serializeDictionary:(NSDictionary *)inDictionary error:(NSError **)outError; | ||
47 | |||
48 | @end | ||
49 | |||
50 | typedef enum { | ||
51 | CJSONSerializerErrorCouldNotSerializeDataType = -1, | ||
52 | CJSONSerializerErrorCouldNotSerializeObject = -1 | ||
53 | } CJSONSerializerError; | ||
diff --git a/libs/TouchJSON/JSON/CJSONSerializer.m b/libs/TouchJSON/JSON/CJSONSerializer.m new file mode 100755 index 0000000..952b3c2 --- /dev/null +++ b/libs/TouchJSON/JSON/CJSONSerializer.m | |||
@@ -0,0 +1,342 @@ | |||
1 | // | ||
2 | // CJSONSerializer.m | ||
3 | // TouchCode | ||
4 | // | ||
5 | // Created by Jonathan Wight on 12/07/2005. | ||
6 | // Copyright 2005 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | // Permission is hereby granted, free of charge, to any person | ||
9 | // obtaining a copy of this software and associated documentation | ||
10 | // files (the "Software"), to deal in the Software without | ||
11 | // restriction, including without limitation the rights to use, | ||
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the | ||
14 | // Software is furnished to do so, subject to the following | ||
15 | // conditions: | ||
16 | // | ||
17 | // The above copyright notice and this permission notice shall be | ||
18 | // included in all copies or substantial portions of the Software. | ||
19 | // | ||
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
27 | // OTHER DEALINGS IN THE SOFTWARE. | ||
28 | // | ||
29 | |||
30 | #import "CJSONSerializer.h" | ||
31 | |||
32 | #import "JSONRepresentation.h" | ||
33 | |||
34 | static NSData *kNULL = NULL; | ||
35 | static NSData *kFalse = NULL; | ||
36 | static NSData *kTrue = NULL; | ||
37 | |||
38 | @implementation CJSONSerializer | ||
39 | |||
40 | + (void)initialize | ||
41 | { | ||
42 | NSAutoreleasePool *thePool = [[NSAutoreleasePool alloc] init]; | ||
43 | |||
44 | if (self == [CJSONSerializer class]) | ||
45 | { | ||
46 | if (kNULL == NULL) | ||
47 | kNULL = [[NSData alloc] initWithBytesNoCopy:(void *)"null" length:4 freeWhenDone:NO]; | ||
48 | if (kFalse == NULL) | ||
49 | kFalse = [[NSData alloc] initWithBytesNoCopy:(void *)"false" length:5 freeWhenDone:NO]; | ||
50 | if (kTrue == NULL) | ||
51 | kTrue = [[NSData alloc] initWithBytesNoCopy:(void *)"true" length:4 freeWhenDone:NO]; | ||
52 | |||
53 | [thePool release]; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | + (id)serializer | ||
58 | { | ||
59 | return([[[self alloc] init] autorelease]); | ||
60 | } | ||
61 | |||
62 | - (BOOL)isValidJSONObject:(id)inObject | ||
63 | { | ||
64 | if ([inObject isKindOfClass:[NSNull class]]) | ||
65 | { | ||
66 | return(YES); | ||
67 | } | ||
68 | else if ([inObject isKindOfClass:[NSNumber class]]) | ||
69 | { | ||
70 | return(YES); | ||
71 | } | ||
72 | else if ([inObject isKindOfClass:[NSString class]]) | ||
73 | { | ||
74 | return(YES); | ||
75 | } | ||
76 | else if ([inObject isKindOfClass:[NSArray class]]) | ||
77 | { | ||
78 | return(YES); | ||
79 | } | ||
80 | else if ([inObject isKindOfClass:[NSDictionary class]]) | ||
81 | { | ||
82 | return(YES); | ||
83 | } | ||
84 | else if ([inObject isKindOfClass:[NSData class]]) | ||
85 | { | ||
86 | return(YES); | ||
87 | } | ||
88 | else if ([inObject respondsToSelector:@selector(JSONDataRepresentation)]) | ||
89 | { | ||
90 | return(YES); | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | return(NO); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | - (NSData *)serializeObject:(id)inObject error:(NSError **)outError | ||
99 | { | ||
100 | NSData *theResult = NULL; | ||
101 | |||
102 | if ([inObject isKindOfClass:[NSNull class]]) | ||
103 | { | ||
104 | theResult = [self serializeNull:inObject error:outError]; | ||
105 | } | ||
106 | else if ([inObject isKindOfClass:[NSNumber class]]) | ||
107 | { | ||
108 | theResult = [self serializeNumber:inObject error:outError]; | ||
109 | } | ||
110 | else if ([inObject isKindOfClass:[NSString class]]) | ||
111 | { | ||
112 | theResult = [self serializeString:inObject error:outError]; | ||
113 | } | ||
114 | else if ([inObject isKindOfClass:[NSArray class]]) | ||
115 | { | ||
116 | theResult = [self serializeArray:inObject error:outError]; | ||
117 | } | ||
118 | else if ([inObject isKindOfClass:[NSDictionary class]]) | ||
119 | { | ||
120 | theResult = [self serializeDictionary:inObject error:outError]; | ||
121 | } | ||
122 | else if ([inObject isKindOfClass:[NSData class]]) | ||
123 | { | ||
124 | NSString *theString = [[[NSString alloc] initWithData:inObject encoding:NSUTF8StringEncoding] autorelease]; | ||
125 | theResult = [self serializeString:theString error:outError]; | ||
126 | } | ||
127 | else if ([inObject respondsToSelector:@selector(JSONDataRepresentation)]) | ||
128 | { | ||
129 | theResult = [inObject JSONDataRepresentation]; | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | if (outError) | ||
134 | { | ||
135 | NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: | ||
136 | [NSString stringWithFormat:@"Cannot serialize data of type '%@'", NSStringFromClass([inObject class])], NSLocalizedDescriptionKey, | ||
137 | NULL]; | ||
138 | *outError = [NSError errorWithDomain:@"TODO_DOMAIN" code:CJSONSerializerErrorCouldNotSerializeDataType userInfo:theUserInfo]; | ||
139 | } | ||
140 | return(NULL); | ||
141 | } | ||
142 | if (theResult == NULL) | ||
143 | { | ||
144 | if (outError) | ||
145 | { | ||
146 | NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: | ||
147 | [NSString stringWithFormat:@"Could not serialize object '%@'", inObject], NSLocalizedDescriptionKey, | ||
148 | NULL]; | ||
149 | *outError = [NSError errorWithDomain:@"TODO_DOMAIN" code:CJSONSerializerErrorCouldNotSerializeObject userInfo:theUserInfo]; | ||
150 | } | ||
151 | return(NULL); | ||
152 | } | ||
153 | return(theResult); | ||
154 | } | ||
155 | |||
156 | - (NSData *)serializeNull:(NSNull *)inNull error:(NSError **)outError | ||
157 | { | ||
158 | #pragma unused (inNull, outError) | ||
159 | return(kNULL); | ||
160 | } | ||
161 | |||
162 | - (NSData *)serializeNumber:(NSNumber *)inNumber error:(NSError **)outError | ||
163 | { | ||
164 | #pragma unused (outError) | ||
165 | NSData *theResult = NULL; | ||
166 | switch (CFNumberGetType((CFNumberRef)inNumber)) | ||
167 | { | ||
168 | case kCFNumberCharType: | ||
169 | { | ||
170 | int theValue = [inNumber intValue]; | ||
171 | if (theValue == 0) | ||
172 | theResult = kFalse; | ||
173 | else if (theValue == 1) | ||
174 | theResult = kTrue; | ||
175 | else | ||
176 | theResult = [[inNumber stringValue] dataUsingEncoding:NSASCIIStringEncoding]; | ||
177 | } | ||
178 | break; | ||
179 | case kCFNumberFloat32Type: | ||
180 | case kCFNumberFloat64Type: | ||
181 | case kCFNumberFloatType: | ||
182 | case kCFNumberDoubleType: | ||
183 | case kCFNumberSInt8Type: | ||
184 | case kCFNumberSInt16Type: | ||
185 | case kCFNumberSInt32Type: | ||
186 | case kCFNumberSInt64Type: | ||
187 | case kCFNumberShortType: | ||
188 | case kCFNumberIntType: | ||
189 | case kCFNumberLongType: | ||
190 | case kCFNumberLongLongType: | ||
191 | case kCFNumberCFIndexType: | ||
192 | default: | ||
193 | theResult = [[inNumber stringValue] dataUsingEncoding:NSASCIIStringEncoding]; | ||
194 | break; | ||
195 | } | ||
196 | return(theResult); | ||
197 | } | ||
198 | |||
199 | - (NSData *)serializeString:(NSString *)inString error:(NSError **)outError | ||
200 | { | ||
201 | #pragma unused (outError) | ||
202 | |||
203 | const char *theUTF8String = [inString UTF8String]; | ||
204 | |||
205 | NSMutableData *theData = [NSMutableData dataWithLength:strlen(theUTF8String) * 2 + 2]; | ||
206 | |||
207 | char *theOutputStart = [theData mutableBytes]; | ||
208 | char *OUT = theOutputStart; | ||
209 | |||
210 | *OUT++ = '"'; | ||
211 | |||
212 | for (const char *IN = theUTF8String; IN && *IN != '\0'; ++IN) | ||
213 | { | ||
214 | switch (*IN) | ||
215 | { | ||
216 | case '\\': | ||
217 | { | ||
218 | *OUT++ = '\\'; | ||
219 | *OUT++ = '\\'; | ||
220 | } | ||
221 | break; | ||
222 | case '\"': | ||
223 | { | ||
224 | *OUT++ = '\\'; | ||
225 | *OUT++ = '\"'; | ||
226 | } | ||
227 | break; | ||
228 | case '/': | ||
229 | { | ||
230 | *OUT++ = '\\'; | ||
231 | *OUT++ = '/'; | ||
232 | } | ||
233 | break; | ||
234 | case '\b': | ||
235 | { | ||
236 | *OUT++ = '\\'; | ||
237 | *OUT++ = 'b'; | ||
238 | } | ||
239 | break; | ||
240 | case '\f': | ||
241 | { | ||
242 | *OUT++ = '\\'; | ||
243 | *OUT++ = 'f'; | ||
244 | } | ||
245 | break; | ||
246 | case '\n': | ||
247 | { | ||
248 | *OUT++ = '\\'; | ||
249 | *OUT++ = 'n'; | ||
250 | } | ||
251 | break; | ||
252 | case '\r': | ||
253 | { | ||
254 | *OUT++ = '\\'; | ||
255 | *OUT++ = 'r'; | ||
256 | } | ||
257 | break; | ||
258 | case '\t': | ||
259 | { | ||
260 | *OUT++ = '\\'; | ||
261 | *OUT++ = 't'; | ||
262 | } | ||
263 | break; | ||
264 | default: | ||
265 | { | ||
266 | *OUT++ = *IN; | ||
267 | } | ||
268 | break; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | *OUT++ = '"'; | ||
273 | |||
274 | theData.length = OUT - theOutputStart; | ||
275 | return(theData); | ||
276 | } | ||
277 | |||
278 | - (NSData *)serializeArray:(NSArray *)inArray error:(NSError **)outError | ||
279 | { | ||
280 | NSMutableData *theData = [NSMutableData data]; | ||
281 | |||
282 | [theData appendBytes:"[" length:1]; | ||
283 | |||
284 | NSEnumerator *theEnumerator = [inArray objectEnumerator]; | ||
285 | id theValue = NULL; | ||
286 | NSUInteger i = 0; | ||
287 | while ((theValue = [theEnumerator nextObject]) != NULL) | ||
288 | { | ||
289 | NSData *theValueData = [self serializeObject:theValue error:outError]; | ||
290 | if (theValueData == NULL) | ||
291 | { | ||
292 | return(NULL); | ||
293 | } | ||
294 | [theData appendData:theValueData]; | ||
295 | if (++i < [inArray count]) | ||
296 | [theData appendBytes:"," length:1]; | ||
297 | } | ||
298 | |||
299 | [theData appendBytes:"]" length:1]; | ||
300 | |||
301 | return(theData); | ||
302 | } | ||
303 | |||
304 | - (NSData *)serializeDictionary:(NSDictionary *)inDictionary error:(NSError **)outError | ||
305 | { | ||
306 | NSMutableData *theData = [NSMutableData data]; | ||
307 | |||
308 | [theData appendBytes:"{" length:1]; | ||
309 | |||
310 | NSArray *theKeys = [inDictionary allKeys]; | ||
311 | NSEnumerator *theEnumerator = [theKeys objectEnumerator]; | ||
312 | NSString *theKey = NULL; | ||
313 | while ((theKey = [theEnumerator nextObject]) != NULL) | ||
314 | { | ||
315 | id theValue = [inDictionary objectForKey:theKey]; | ||
316 | |||
317 | NSData *theKeyData = [self serializeString:theKey error:outError]; | ||
318 | if (theKeyData == NULL) | ||
319 | { | ||
320 | return(NULL); | ||
321 | } | ||
322 | NSData *theValueData = [self serializeObject:theValue error:outError]; | ||
323 | if (theValueData == NULL) | ||
324 | { | ||
325 | return(NULL); | ||
326 | } | ||
327 | |||
328 | |||
329 | [theData appendData:theKeyData]; | ||
330 | [theData appendBytes:":" length:1]; | ||
331 | [theData appendData:theValueData]; | ||
332 | |||
333 | if (theKey != [theKeys lastObject]) | ||
334 | [theData appendData:[@"," dataUsingEncoding:NSASCIIStringEncoding]]; | ||
335 | } | ||
336 | |||
337 | [theData appendBytes:"}" length:1]; | ||
338 | |||
339 | return(theData); | ||
340 | } | ||
341 | |||
342 | @end | ||
diff --git a/libs/TouchJSON/JSON/JSONRepresentation.h b/libs/TouchJSON/JSON/JSONRepresentation.h new file mode 100755 index 0000000..a83d76f --- /dev/null +++ b/libs/TouchJSON/JSON/JSONRepresentation.h | |||
@@ -0,0 +1,18 @@ | |||
1 | // | ||
2 | // JSONRepresentation.h | ||
3 | // TouchJSON | ||
4 | // | ||
5 | // Created by Jonathan Wight on 10/15/10. | ||
6 | // Copyright 2010 toxicsoftware.com. All rights reserved. | ||
7 | // | ||
8 | |||
9 | #import <Foundation/Foundation.h> | ||
10 | |||
11 | @protocol JSONRepresentation | ||
12 | |||
13 | @optional | ||
14 | - (id)initWithJSONDataRepresentation:(NSData *)inJSONData; | ||
15 | |||
16 | - (NSData *)JSONDataRepresentation; | ||
17 | |||
18 | @end | ||
diff --git a/libs/cocos2d/CCAction.h b/libs/cocos2d/CCAction.h new file mode 100755 index 0000000..51bad8e --- /dev/null +++ b/libs/cocos2d/CCAction.h | |||
@@ -0,0 +1,195 @@ | |||
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 | #include <sys/time.h> | ||
29 | #import <Foundation/Foundation.h> | ||
30 | |||
31 | #import "ccTypes.h" | ||
32 | |||
33 | enum { | ||
34 | //! Default tag | ||
35 | kCCActionTagInvalid = -1, | ||
36 | }; | ||
37 | |||
38 | /** Base class for CCAction objects. | ||
39 | */ | ||
40 | @interface CCAction : NSObject <NSCopying> | ||
41 | { | ||
42 | id originalTarget_; | ||
43 | id target_; | ||
44 | NSInteger tag_; | ||
45 | } | ||
46 | |||
47 | /** The "target". The action will modify the target properties. | ||
48 | The target will be set with the 'startWithTarget' method. | ||
49 | When the 'stop' method is called, target will be set to nil. | ||
50 | The target is 'assigned', it is not 'retained'. | ||
51 | */ | ||
52 | @property (nonatomic,readonly,assign) id target; | ||
53 | |||
54 | /** The original target, since target can be nil. | ||
55 | Is the target that were used to run the action. Unless you are doing something complex, like CCActionManager, you should NOT call this method. | ||
56 | @since v0.8.2 | ||
57 | */ | ||
58 | @property (nonatomic,readonly,assign) id originalTarget; | ||
59 | |||
60 | |||
61 | /** The action tag. An identifier of the action */ | ||
62 | @property (nonatomic,readwrite,assign) NSInteger tag; | ||
63 | |||
64 | /** Allocates and initializes the action */ | ||
65 | +(id) action; | ||
66 | |||
67 | /** Initializes the action */ | ||
68 | -(id) init; | ||
69 | |||
70 | -(id) copyWithZone: (NSZone*) zone; | ||
71 | |||
72 | //! return YES if the action has finished | ||
73 | -(BOOL) isDone; | ||
74 | //! called before the action start. It will also set the target. | ||
75 | -(void) startWithTarget:(id)target; | ||
76 | //! called after the action has finished. It will set the 'target' to nil. | ||
77 | //! IMPORTANT: You should never call "[action stop]" manually. Instead, use: "[target stopAction:action];" | ||
78 | -(void) stop; | ||
79 | //! called every frame with it's delta time. DON'T override unless you know what you are doing. | ||
80 | -(void) step: (ccTime) dt; | ||
81 | //! called once per frame. time a value between 0 and 1 | ||
82 | //! For example: | ||
83 | //! * 0 means that the action just started | ||
84 | //! * 0.5 means that the action is in the middle | ||
85 | //! * 1 means that the action is over | ||
86 | -(void) update: (ccTime) time; | ||
87 | |||
88 | @end | ||
89 | |||
90 | /** Base class actions that do have a finite time duration. | ||
91 | Possible actions: | ||
92 | - An action with a duration of 0 seconds | ||
93 | - An action with a duration of 35.5 seconds | ||
94 | Infitite time actions are valid | ||
95 | */ | ||
96 | @interface CCFiniteTimeAction : CCAction <NSCopying> | ||
97 | { | ||
98 | //! duration in seconds | ||
99 | ccTime duration_; | ||
100 | } | ||
101 | //! duration in seconds of the action | ||
102 | @property (nonatomic,readwrite) ccTime duration; | ||
103 | |||
104 | /** returns a reversed action */ | ||
105 | - (CCFiniteTimeAction*) reverse; | ||
106 | @end | ||
107 | |||
108 | |||
109 | @class CCActionInterval; | ||
110 | /** Repeats an action for ever. | ||
111 | To repeat the an action for a limited number of times use the Repeat action. | ||
112 | @warning This action can't be Sequenceable because it is not an IntervalAction | ||
113 | */ | ||
114 | @interface CCRepeatForever : CCAction <NSCopying> | ||
115 | { | ||
116 | CCActionInterval *innerAction_; | ||
117 | } | ||
118 | /** Inner action */ | ||
119 | @property (nonatomic, readwrite, retain) CCActionInterval *innerAction; | ||
120 | |||
121 | /** creates the action */ | ||
122 | +(id) actionWithAction: (CCActionInterval*) action; | ||
123 | /** initializes the action */ | ||
124 | -(id) initWithAction: (CCActionInterval*) action; | ||
125 | @end | ||
126 | |||
127 | /** Changes the speed of an action, making it take longer (speed>1) | ||
128 | or less (speed<1) time. | ||
129 | Useful to simulate 'slow motion' or 'fast forward' effect. | ||
130 | @warning This action can't be Sequenceable because it is not an CCIntervalAction | ||
131 | */ | ||
132 | @interface CCSpeed : CCAction <NSCopying> | ||
133 | { | ||
134 | CCActionInterval *innerAction_; | ||
135 | float speed_; | ||
136 | } | ||
137 | /** alter the speed of the inner function in runtime */ | ||
138 | @property (nonatomic,readwrite) float speed; | ||
139 | /** Inner action of CCSpeed */ | ||
140 | @property (nonatomic, readwrite, retain) CCActionInterval *innerAction; | ||
141 | |||
142 | /** creates the action */ | ||
143 | +(id) actionWithAction: (CCActionInterval*) action speed:(float)rate; | ||
144 | /** initializes the action */ | ||
145 | -(id) initWithAction: (CCActionInterval*) action speed:(float)rate; | ||
146 | @end | ||
147 | |||
148 | @class CCNode; | ||
149 | /** CCFollow is an action that "follows" a node. | ||
150 | |||
151 | Eg: | ||
152 | [layer runAction: [CCFollow actionWithTarget:hero]]; | ||
153 | |||
154 | Instead of using CCCamera as a "follower", use this action instead. | ||
155 | @since v0.99.2 | ||
156 | */ | ||
157 | @interface CCFollow : CCAction <NSCopying> | ||
158 | { | ||
159 | /* node to follow */ | ||
160 | CCNode *followedNode_; | ||
161 | |||
162 | /* whether camera should be limited to certain area */ | ||
163 | BOOL boundarySet; | ||
164 | |||
165 | /* if screensize is bigger than the boundary - update not needed */ | ||
166 | BOOL boundaryFullyCovered; | ||
167 | |||
168 | /* fast access to the screen dimensions */ | ||
169 | CGPoint halfScreenSize; | ||
170 | CGPoint fullScreenSize; | ||
171 | |||
172 | /* world boundaries */ | ||
173 | float leftBoundary; | ||
174 | float rightBoundary; | ||
175 | float topBoundary; | ||
176 | float bottomBoundary; | ||
177 | } | ||
178 | |||
179 | /** alter behavior - turn on/off boundary */ | ||
180 | @property (nonatomic,readwrite) BOOL boundarySet; | ||
181 | |||
182 | /** creates the action with no boundary set */ | ||
183 | +(id) actionWithTarget:(CCNode *)followedNode; | ||
184 | |||
185 | /** creates the action with a set boundary */ | ||
186 | +(id) actionWithTarget:(CCNode *)followedNode worldBoundary:(CGRect)rect; | ||
187 | |||
188 | /** initializes the action */ | ||
189 | -(id) initWithTarget:(CCNode *)followedNode; | ||
190 | |||
191 | /** initializes the action with a set boundary */ | ||
192 | -(id) initWithTarget:(CCNode *)followedNode worldBoundary:(CGRect)rect; | ||
193 | |||
194 | @end | ||
195 | |||
diff --git a/libs/cocos2d/CCAction.m b/libs/cocos2d/CCAction.m new file mode 100755 index 0000000..27db20b --- /dev/null +++ b/libs/cocos2d/CCAction.m | |||
@@ -0,0 +1,360 @@ | |||
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 | |||
29 | #import <Availability.h> | ||
30 | #import "CCDirector.h" | ||
31 | #import "ccMacros.h" | ||
32 | #import "CCAction.h" | ||
33 | #import "CCActionInterval.h" | ||
34 | #import "Support/CGPointExtension.h" | ||
35 | |||
36 | // | ||
37 | // Action Base Class | ||
38 | // | ||
39 | #pragma mark - | ||
40 | #pragma mark Action | ||
41 | @implementation CCAction | ||
42 | |||
43 | @synthesize tag = tag_, target = target_, originalTarget = originalTarget_; | ||
44 | |||
45 | +(id) action | ||
46 | { | ||
47 | return [[[self alloc] init] autorelease]; | ||
48 | } | ||
49 | |||
50 | -(id) init | ||
51 | { | ||
52 | if( (self=[super init]) ) { | ||
53 | originalTarget_ = target_ = nil; | ||
54 | tag_ = kCCActionTagInvalid; | ||
55 | } | ||
56 | return self; | ||
57 | } | ||
58 | |||
59 | -(void) dealloc | ||
60 | { | ||
61 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
62 | [super dealloc]; | ||
63 | } | ||
64 | |||
65 | -(NSString*) description | ||
66 | { | ||
67 | return [NSString stringWithFormat:@"<%@ = %08X | Tag = %i>", [self class], self, tag_]; | ||
68 | } | ||
69 | |||
70 | -(id) copyWithZone: (NSZone*) zone | ||
71 | { | ||
72 | CCAction *copy = [[[self class] allocWithZone: zone] init]; | ||
73 | copy.tag = tag_; | ||
74 | return copy; | ||
75 | } | ||
76 | |||
77 | -(void) startWithTarget:(id)aTarget | ||
78 | { | ||
79 | originalTarget_ = target_ = aTarget; | ||
80 | } | ||
81 | |||
82 | -(void) stop | ||
83 | { | ||
84 | target_ = nil; | ||
85 | } | ||
86 | |||
87 | -(BOOL) isDone | ||
88 | { | ||
89 | return YES; | ||
90 | } | ||
91 | |||
92 | -(void) step: (ccTime) dt | ||
93 | { | ||
94 | NSLog(@"[Action step]. override me"); | ||
95 | } | ||
96 | |||
97 | -(void) update: (ccTime) time | ||
98 | { | ||
99 | NSLog(@"[Action update]. override me"); | ||
100 | } | ||
101 | @end | ||
102 | |||
103 | // | ||
104 | // FiniteTimeAction | ||
105 | // | ||
106 | #pragma mark - | ||
107 | #pragma mark FiniteTimeAction | ||
108 | @implementation CCFiniteTimeAction | ||
109 | @synthesize duration = duration_; | ||
110 | |||
111 | - (CCFiniteTimeAction*) reverse | ||
112 | { | ||
113 | CCLOG(@"cocos2d: FiniteTimeAction#reverse: Implement me"); | ||
114 | return nil; | ||
115 | } | ||
116 | @end | ||
117 | |||
118 | |||
119 | // | ||
120 | // RepeatForever | ||
121 | // | ||
122 | #pragma mark - | ||
123 | #pragma mark RepeatForever | ||
124 | @implementation CCRepeatForever | ||
125 | @synthesize innerAction=innerAction_; | ||
126 | +(id) actionWithAction: (CCActionInterval*) action | ||
127 | { | ||
128 | return [[[self alloc] initWithAction: action] autorelease]; | ||
129 | } | ||
130 | |||
131 | -(id) initWithAction: (CCActionInterval*) action | ||
132 | { | ||
133 | if( (self=[super init]) ) | ||
134 | self.innerAction = action; | ||
135 | |||
136 | return self; | ||
137 | } | ||
138 | |||
139 | -(id) copyWithZone: (NSZone*) zone | ||
140 | { | ||
141 | CCAction *copy = [[[self class] allocWithZone: zone] initWithAction:[[innerAction_ copy] autorelease] ]; | ||
142 | return copy; | ||
143 | } | ||
144 | |||
145 | -(void) dealloc | ||
146 | { | ||
147 | [innerAction_ release]; | ||
148 | [super dealloc]; | ||
149 | } | ||
150 | |||
151 | -(void) startWithTarget:(id)aTarget | ||
152 | { | ||
153 | [super startWithTarget:aTarget]; | ||
154 | [innerAction_ startWithTarget:target_]; | ||
155 | } | ||
156 | |||
157 | -(void) step:(ccTime) dt | ||
158 | { | ||
159 | [innerAction_ step: dt]; | ||
160 | if( [innerAction_ isDone] ) { | ||
161 | ccTime diff = dt + innerAction_.duration - innerAction_.elapsed; | ||
162 | [innerAction_ startWithTarget:target_]; | ||
163 | |||
164 | // to prevent jerk. issue #390 | ||
165 | [innerAction_ step: diff]; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | |||
170 | -(BOOL) isDone | ||
171 | { | ||
172 | return NO; | ||
173 | } | ||
174 | |||
175 | - (CCActionInterval *) reverse | ||
176 | { | ||
177 | return [CCRepeatForever actionWithAction:[innerAction_ reverse]]; | ||
178 | } | ||
179 | @end | ||
180 | |||
181 | // | ||
182 | // Speed | ||
183 | // | ||
184 | #pragma mark - | ||
185 | #pragma mark Speed | ||
186 | @implementation CCSpeed | ||
187 | @synthesize speed=speed_; | ||
188 | @synthesize innerAction=innerAction_; | ||
189 | |||
190 | +(id) actionWithAction: (CCActionInterval*) action speed:(float)r | ||
191 | { | ||
192 | return [[[self alloc] initWithAction: action speed:r] autorelease]; | ||
193 | } | ||
194 | |||
195 | -(id) initWithAction: (CCActionInterval*) action speed:(float)r | ||
196 | { | ||
197 | if( (self=[super init]) ) { | ||
198 | self.innerAction = action; | ||
199 | speed_ = r; | ||
200 | } | ||
201 | return self; | ||
202 | } | ||
203 | |||
204 | -(id) copyWithZone: (NSZone*) zone | ||
205 | { | ||
206 | CCAction *copy = [[[self class] allocWithZone: zone] initWithAction:[[innerAction_ copy] autorelease] speed:speed_]; | ||
207 | return copy; | ||
208 | } | ||
209 | |||
210 | -(void) dealloc | ||
211 | { | ||
212 | [innerAction_ release]; | ||
213 | [super dealloc]; | ||
214 | } | ||
215 | |||
216 | -(void) startWithTarget:(id)aTarget | ||
217 | { | ||
218 | [super startWithTarget:aTarget]; | ||
219 | [innerAction_ startWithTarget:target_]; | ||
220 | } | ||
221 | |||
222 | -(void) stop | ||
223 | { | ||
224 | [innerAction_ stop]; | ||
225 | [super stop]; | ||
226 | } | ||
227 | |||
228 | -(void) step:(ccTime) dt | ||
229 | { | ||
230 | [innerAction_ step: dt * speed_]; | ||
231 | } | ||
232 | |||
233 | -(BOOL) isDone | ||
234 | { | ||
235 | return [innerAction_ isDone]; | ||
236 | } | ||
237 | |||
238 | - (CCActionInterval *) reverse | ||
239 | { | ||
240 | return [CCSpeed actionWithAction:[innerAction_ reverse] speed:speed_]; | ||
241 | } | ||
242 | @end | ||
243 | |||
244 | // | ||
245 | // Follow | ||
246 | // | ||
247 | #pragma mark - | ||
248 | #pragma mark Follow | ||
249 | @implementation CCFollow | ||
250 | |||
251 | @synthesize boundarySet; | ||
252 | |||
253 | +(id) actionWithTarget:(CCNode *) fNode | ||
254 | { | ||
255 | return [[[self alloc] initWithTarget:fNode] autorelease]; | ||
256 | } | ||
257 | |||
258 | +(id) actionWithTarget:(CCNode *) fNode worldBoundary:(CGRect)rect | ||
259 | { | ||
260 | return [[[self alloc] initWithTarget:fNode worldBoundary:rect] autorelease]; | ||
261 | } | ||
262 | |||
263 | -(id) initWithTarget:(CCNode *)fNode | ||
264 | { | ||
265 | if( (self=[super init]) ) { | ||
266 | |||
267 | followedNode_ = [fNode retain]; | ||
268 | boundarySet = FALSE; | ||
269 | boundaryFullyCovered = FALSE; | ||
270 | |||
271 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
272 | fullScreenSize = CGPointMake(s.width, s.height); | ||
273 | halfScreenSize = ccpMult(fullScreenSize, .5f); | ||
274 | } | ||
275 | |||
276 | return self; | ||
277 | } | ||
278 | |||
279 | -(id) initWithTarget:(CCNode *)fNode worldBoundary:(CGRect)rect | ||
280 | { | ||
281 | if( (self=[super init]) ) { | ||
282 | |||
283 | followedNode_ = [fNode retain]; | ||
284 | boundarySet = TRUE; | ||
285 | boundaryFullyCovered = FALSE; | ||
286 | |||
287 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
288 | fullScreenSize = CGPointMake(winSize.width, winSize.height); | ||
289 | halfScreenSize = ccpMult(fullScreenSize, .5f); | ||
290 | |||
291 | leftBoundary = -((rect.origin.x+rect.size.width) - fullScreenSize.x); | ||
292 | rightBoundary = -rect.origin.x ; | ||
293 | topBoundary = -rect.origin.y; | ||
294 | bottomBoundary = -((rect.origin.y+rect.size.height) - fullScreenSize.y); | ||
295 | |||
296 | if(rightBoundary < leftBoundary) | ||
297 | { | ||
298 | // screen width is larger than world's boundary width | ||
299 | //set both in the middle of the world | ||
300 | rightBoundary = leftBoundary = (leftBoundary + rightBoundary) / 2; | ||
301 | } | ||
302 | if(topBoundary < bottomBoundary) | ||
303 | { | ||
304 | // screen width is larger than world's boundary width | ||
305 | //set both in the middle of the world | ||
306 | topBoundary = bottomBoundary = (topBoundary + bottomBoundary) / 2; | ||
307 | } | ||
308 | |||
309 | if( (topBoundary == bottomBoundary) && (leftBoundary == rightBoundary) ) | ||
310 | boundaryFullyCovered = TRUE; | ||
311 | } | ||
312 | |||
313 | return self; | ||
314 | } | ||
315 | |||
316 | -(id) copyWithZone: (NSZone*) zone | ||
317 | { | ||
318 | CCAction *copy = [[[self class] allocWithZone: zone] init]; | ||
319 | copy.tag = tag_; | ||
320 | return copy; | ||
321 | } | ||
322 | |||
323 | -(void) step:(ccTime) dt | ||
324 | { | ||
325 | if(boundarySet) | ||
326 | { | ||
327 | // whole map fits inside a single screen, no need to modify the position - unless map boundaries are increased | ||
328 | if(boundaryFullyCovered) | ||
329 | return; | ||
330 | |||
331 | CGPoint tempPos = ccpSub( halfScreenSize, followedNode_.position); | ||
332 | [target_ setPosition:ccp(clampf(tempPos.x,leftBoundary,rightBoundary), clampf(tempPos.y,bottomBoundary,topBoundary))]; | ||
333 | } | ||
334 | else | ||
335 | [target_ setPosition:ccpSub( halfScreenSize, followedNode_.position )]; | ||
336 | |||
337 | #undef CLAMP | ||
338 | } | ||
339 | |||
340 | |||
341 | -(BOOL) isDone | ||
342 | { | ||
343 | return !followedNode_.isRunning; | ||
344 | } | ||
345 | |||
346 | -(void) stop | ||
347 | { | ||
348 | target_ = nil; | ||
349 | [super stop]; | ||
350 | } | ||
351 | |||
352 | -(void) dealloc | ||
353 | { | ||
354 | [followedNode_ release]; | ||
355 | [super dealloc]; | ||
356 | } | ||
357 | |||
358 | @end | ||
359 | |||
360 | |||
diff --git a/libs/cocos2d/CCActionCamera.h b/libs/cocos2d/CCActionCamera.h new file mode 100755 index 0000000..1ea83a7 --- /dev/null +++ b/libs/cocos2d/CCActionCamera.h | |||
@@ -0,0 +1,73 @@ | |||
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 | #import "CCActionInterval.h" | ||
28 | |||
29 | @class CCCamera; | ||
30 | |||
31 | /** Base class for CCCamera actions | ||
32 | */ | ||
33 | @interface CCActionCamera : CCActionInterval <NSCopying> | ||
34 | { | ||
35 | float centerXOrig_; | ||
36 | float centerYOrig_; | ||
37 | float centerZOrig_; | ||
38 | |||
39 | float eyeXOrig_; | ||
40 | float eyeYOrig_; | ||
41 | float eyeZOrig_; | ||
42 | |||
43 | float upXOrig_; | ||
44 | float upYOrig_; | ||
45 | float upZOrig_; | ||
46 | } | ||
47 | @end | ||
48 | |||
49 | /** CCOrbitCamera action | ||
50 | Orbits the camera around the center of the screen using spherical coordinates | ||
51 | */ | ||
52 | @interface CCOrbitCamera : CCActionCamera <NSCopying> | ||
53 | { | ||
54 | float radius_; | ||
55 | float deltaRadius_; | ||
56 | float angleZ_; | ||
57 | float deltaAngleZ_; | ||
58 | float angleX_; | ||
59 | float deltaAngleX_; | ||
60 | |||
61 | float radZ_; | ||
62 | float radDeltaZ_; | ||
63 | float radX_; | ||
64 | float radDeltaX_; | ||
65 | |||
66 | } | ||
67 | /** creates a CCOrbitCamera action with radius, delta-radius, z, deltaZ, x, deltaX */ | ||
68 | +(id) actionWithDuration:(float) t radius:(float)r deltaRadius:(float) dr angleZ:(float)z deltaAngleZ:(float)dz angleX:(float)x deltaAngleX:(float)dx; | ||
69 | /** initializes a CCOrbitCamera action with radius, delta-radius, z, deltaZ, x, deltaX */ | ||
70 | -(id) initWithDuration:(float) t radius:(float)r deltaRadius:(float) dr angleZ:(float)z deltaAngleZ:(float)dz angleX:(float)x deltaAngleX:(float)dx; | ||
71 | /** positions the camera according to spherical coordinates */ | ||
72 | -(void) sphericalRadius:(float*) r zenith:(float*) zenith azimuth:(float*) azimuth; | ||
73 | @end | ||
diff --git a/libs/cocos2d/CCActionCamera.m b/libs/cocos2d/CCActionCamera.m new file mode 100755 index 0000000..4dafc4e --- /dev/null +++ b/libs/cocos2d/CCActionCamera.m | |||
@@ -0,0 +1,147 @@ | |||
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 | |||
29 | #import "CCActionCamera.h" | ||
30 | #import "CCNode.h" | ||
31 | #import "CCCamera.h" | ||
32 | #import "ccMacros.h" | ||
33 | |||
34 | // | ||
35 | // CameraAction | ||
36 | // | ||
37 | @implementation CCActionCamera | ||
38 | -(void) startWithTarget:(id)aTarget | ||
39 | { | ||
40 | [super startWithTarget:aTarget]; | ||
41 | CCCamera *camera = [target_ camera]; | ||
42 | [camera centerX:¢erXOrig_ centerY:¢erYOrig_ centerZ:¢erZOrig_]; | ||
43 | [camera eyeX:&eyeXOrig_ eyeY:&eyeYOrig_ eyeZ:&eyeZOrig_]; | ||
44 | [camera upX:&upXOrig_ upY:&upYOrig_ upZ: &upZOrig_]; | ||
45 | } | ||
46 | |||
47 | -(id) reverse | ||
48 | { | ||
49 | return [CCReverseTime actionWithAction:self]; | ||
50 | } | ||
51 | @end | ||
52 | |||
53 | @implementation CCOrbitCamera | ||
54 | +(id) actionWithDuration:(float)t radius:(float)r deltaRadius:(float) dr angleZ:(float)z deltaAngleZ:(float)dz angleX:(float)x deltaAngleX:(float)dx | ||
55 | { | ||
56 | return [[[self alloc] initWithDuration:t radius:r deltaRadius:dr angleZ:z deltaAngleZ:dz angleX:x deltaAngleX:dx] autorelease]; | ||
57 | } | ||
58 | |||
59 | -(id) copyWithZone: (NSZone*) zone | ||
60 | { | ||
61 | return [[[self class] allocWithZone: zone] initWithDuration:duration_ radius:radius_ deltaRadius:deltaRadius_ angleZ:angleZ_ deltaAngleZ:deltaAngleZ_ angleX:angleX_ deltaAngleX:deltaAngleX_]; | ||
62 | } | ||
63 | |||
64 | |||
65 | -(id) initWithDuration:(float)t radius:(float)r deltaRadius:(float) dr angleZ:(float)z deltaAngleZ:(float)dz angleX:(float)x deltaAngleX:(float)dx | ||
66 | { | ||
67 | if((self=[super initWithDuration:t]) ) { | ||
68 | |||
69 | radius_ = r; | ||
70 | deltaRadius_ = dr; | ||
71 | angleZ_ = z; | ||
72 | deltaAngleZ_ = dz; | ||
73 | angleX_ = x; | ||
74 | deltaAngleX_ = dx; | ||
75 | |||
76 | radDeltaZ_ = (CGFloat)CC_DEGREES_TO_RADIANS(dz); | ||
77 | radDeltaX_ = (CGFloat)CC_DEGREES_TO_RADIANS(dx); | ||
78 | } | ||
79 | |||
80 | return self; | ||
81 | } | ||
82 | |||
83 | -(void) startWithTarget:(id)aTarget | ||
84 | { | ||
85 | [super startWithTarget:aTarget]; | ||
86 | float r, zenith, azimuth; | ||
87 | |||
88 | [self sphericalRadius: &r zenith:&zenith azimuth:&azimuth]; | ||
89 | |||
90 | #if 0 // isnan() is not supported on the simulator, and isnan() always returns false. | ||
91 | if( isnan(radius_) ) | ||
92 | radius_ = r; | ||
93 | |||
94 | if( isnan( angleZ_) ) | ||
95 | angleZ_ = (CGFloat)CC_RADIANS_TO_DEGREES(zenith); | ||
96 | |||
97 | if( isnan( angleX_ ) ) | ||
98 | angleX_ = (CGFloat)CC_RADIANS_TO_DEGREES(azimuth); | ||
99 | #endif | ||
100 | |||
101 | radZ_ = (CGFloat)CC_DEGREES_TO_RADIANS(angleZ_); | ||
102 | radX_ = (CGFloat)CC_DEGREES_TO_RADIANS(angleX_); | ||
103 | } | ||
104 | |||
105 | -(void) update: (ccTime) dt | ||
106 | { | ||
107 | float r = (radius_ + deltaRadius_ * dt) *[CCCamera getZEye]; | ||
108 | float za = radZ_ + radDeltaZ_ * dt; | ||
109 | float xa = radX_ + radDeltaX_ * dt; | ||
110 | |||
111 | float i = sinf(za) * cosf(xa) * r + centerXOrig_; | ||
112 | float j = sinf(za) * sinf(xa) * r + centerYOrig_; | ||
113 | float k = cosf(za) * r + centerZOrig_; | ||
114 | |||
115 | [[target_ camera] setEyeX:i eyeY:j eyeZ:k]; | ||
116 | } | ||
117 | |||
118 | -(void) sphericalRadius:(float*) newRadius zenith:(float*) zenith azimuth:(float*) azimuth | ||
119 | { | ||
120 | float ex, ey, ez, cx, cy, cz, x, y, z; | ||
121 | float r; // radius | ||
122 | float s; | ||
123 | |||
124 | CCCamera *camera = [target_ camera]; | ||
125 | [camera eyeX:&ex eyeY:&ey eyeZ:&ez]; | ||
126 | [camera centerX:&cx centerY:&cy centerZ:&cz]; | ||
127 | |||
128 | x = ex-cx; | ||
129 | y = ey-cy; | ||
130 | z = ez-cz; | ||
131 | |||
132 | r = sqrtf( x*x + y*y + z*z); | ||
133 | s = sqrtf( x*x + y*y); | ||
134 | if(s==0.0f) | ||
135 | s = FLT_EPSILON; | ||
136 | if(r==0.0f) | ||
137 | r = FLT_EPSILON; | ||
138 | |||
139 | *zenith = acosf( z/r); | ||
140 | if( x < 0 ) | ||
141 | *azimuth = (float)M_PI - asinf(y/s); | ||
142 | else | ||
143 | *azimuth = asinf(y/s); | ||
144 | |||
145 | *newRadius = r / [CCCamera getZEye]; | ||
146 | } | ||
147 | @end | ||
diff --git a/libs/cocos2d/CCActionEase.h b/libs/cocos2d/CCActionEase.h new file mode 100755 index 0000000..fced701 --- /dev/null +++ b/libs/cocos2d/CCActionEase.h | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2009 Jason Booth | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCActionInterval.h" | ||
28 | |||
29 | /** Base class for Easing actions | ||
30 | */ | ||
31 | @interface CCActionEase : CCActionInterval <NSCopying> | ||
32 | { | ||
33 | CCActionInterval * other; | ||
34 | } | ||
35 | /** creates the action */ | ||
36 | +(id) actionWithAction: (CCActionInterval*) action; | ||
37 | /** initializes the action */ | ||
38 | -(id) initWithAction: (CCActionInterval*) action; | ||
39 | @end | ||
40 | |||
41 | /** Base class for Easing actions with rate parameters | ||
42 | */ | ||
43 | @interface CCEaseRateAction : CCActionEase <NSCopying> | ||
44 | { | ||
45 | float rate; | ||
46 | } | ||
47 | /** rate value for the actions */ | ||
48 | @property (nonatomic,readwrite,assign) float rate; | ||
49 | /** Creates the action with the inner action and the rate parameter */ | ||
50 | +(id) actionWithAction: (CCActionInterval*) action rate:(float)rate; | ||
51 | /** Initializes the action with the inner action and the rate parameter */ | ||
52 | -(id) initWithAction: (CCActionInterval*) action rate:(float)rate; | ||
53 | @end | ||
54 | |||
55 | /** CCEaseIn action with a rate | ||
56 | */ | ||
57 | @interface CCEaseIn : CCEaseRateAction <NSCopying> {} @end | ||
58 | |||
59 | /** CCEaseOut action with a rate | ||
60 | */ | ||
61 | @interface CCEaseOut : CCEaseRateAction <NSCopying> {} @end | ||
62 | |||
63 | /** CCEaseInOut action with a rate | ||
64 | */ | ||
65 | @interface CCEaseInOut : CCEaseRateAction <NSCopying> {} @end | ||
66 | |||
67 | /** CCEase Exponential In | ||
68 | */ | ||
69 | @interface CCEaseExponentialIn : CCActionEase <NSCopying> {} @end | ||
70 | /** Ease Exponential Out | ||
71 | */ | ||
72 | @interface CCEaseExponentialOut : CCActionEase <NSCopying> {} @end | ||
73 | /** Ease Exponential InOut | ||
74 | */ | ||
75 | @interface CCEaseExponentialInOut : CCActionEase <NSCopying> {} @end | ||
76 | /** Ease Sine In | ||
77 | */ | ||
78 | @interface CCEaseSineIn : CCActionEase <NSCopying> {} @end | ||
79 | /** Ease Sine Out | ||
80 | */ | ||
81 | @interface CCEaseSineOut : CCActionEase <NSCopying> {} @end | ||
82 | /** Ease Sine InOut | ||
83 | */ | ||
84 | @interface CCEaseSineInOut : CCActionEase <NSCopying> {} @end | ||
85 | |||
86 | /** Ease Elastic abstract class | ||
87 | @since v0.8.2 | ||
88 | */ | ||
89 | @interface CCEaseElastic : CCActionEase <NSCopying> | ||
90 | { | ||
91 | float period_; | ||
92 | } | ||
93 | |||
94 | /** period of the wave in radians. default is 0.3 */ | ||
95 | @property (nonatomic,readwrite) float period; | ||
96 | |||
97 | /** Creates the action with the inner action and the period in radians (default is 0.3) */ | ||
98 | +(id) actionWithAction: (CCActionInterval*) action period:(float)period; | ||
99 | /** Initializes the action with the inner action and the period in radians (default is 0.3) */ | ||
100 | -(id) initWithAction: (CCActionInterval*) action period:(float)period; | ||
101 | @end | ||
102 | |||
103 | /** Ease Elastic In action. | ||
104 | @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. | ||
105 | @since v0.8.2 | ||
106 | */ | ||
107 | @interface CCEaseElasticIn : CCEaseElastic <NSCopying> {} @end | ||
108 | /** Ease Elastic Out action. | ||
109 | @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. | ||
110 | @since v0.8.2 | ||
111 | */ | ||
112 | @interface CCEaseElasticOut : CCEaseElastic <NSCopying> {} @end | ||
113 | /** Ease Elastic InOut action. | ||
114 | @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. | ||
115 | @since v0.8.2 | ||
116 | */ | ||
117 | @interface CCEaseElasticInOut : CCEaseElastic <NSCopying> {} @end | ||
118 | |||
119 | /** CCEaseBounce abstract class. | ||
120 | @since v0.8.2 | ||
121 | */ | ||
122 | @interface CCEaseBounce : CCActionEase <NSCopying> {} @end | ||
123 | |||
124 | /** CCEaseBounceIn action. | ||
125 | @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. | ||
126 | @since v0.8.2 | ||
127 | */ | ||
128 | @interface CCEaseBounceIn : CCEaseBounce <NSCopying> {} @end | ||
129 | |||
130 | /** EaseBounceOut action. | ||
131 | @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. | ||
132 | @since v0.8.2 | ||
133 | */ | ||
134 | @interface CCEaseBounceOut : CCEaseBounce <NSCopying> {} @end | ||
135 | |||
136 | /** CCEaseBounceInOut action. | ||
137 | @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. | ||
138 | @since v0.8.2 | ||
139 | */ | ||
140 | @interface CCEaseBounceInOut : CCEaseBounce <NSCopying> {} @end | ||
141 | |||
142 | /** CCEaseBackIn action. | ||
143 | @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. | ||
144 | @since v0.8.2 | ||
145 | */ | ||
146 | @interface CCEaseBackIn : CCActionEase <NSCopying> {} @end | ||
147 | |||
148 | /** CCEaseBackOut action. | ||
149 | @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. | ||
150 | @since v0.8.2 | ||
151 | */ | ||
152 | @interface CCEaseBackOut : CCActionEase <NSCopying> {} @end | ||
153 | |||
154 | /** CCEaseBackInOut action. | ||
155 | @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. | ||
156 | @since v0.8.2 | ||
157 | */ | ||
158 | @interface CCEaseBackInOut : CCActionEase <NSCopying> {} @end | ||
159 | |||
diff --git a/libs/cocos2d/CCActionEase.m b/libs/cocos2d/CCActionEase.m new file mode 100755 index 0000000..f28be11 --- /dev/null +++ b/libs/cocos2d/CCActionEase.m | |||
@@ -0,0 +1,534 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2009 Jason Booth | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | /* | ||
28 | * Elastic, Back and Bounce actions based on code from: | ||
29 | * http://github.com/NikhilK/silverlightfx/ | ||
30 | * | ||
31 | * by http://github.com/NikhilK | ||
32 | */ | ||
33 | |||
34 | #import "CCActionEase.h" | ||
35 | |||
36 | #ifndef M_PI_X_2 | ||
37 | #define M_PI_X_2 (float)M_PI * 2.0f | ||
38 | #endif | ||
39 | |||
40 | #pragma mark EaseAction | ||
41 | |||
42 | // | ||
43 | // EaseAction | ||
44 | // | ||
45 | @implementation CCActionEase | ||
46 | |||
47 | +(id) actionWithAction: (CCActionInterval*) action | ||
48 | { | ||
49 | return [[[self alloc] initWithAction: action] autorelease ]; | ||
50 | } | ||
51 | |||
52 | -(id) initWithAction: (CCActionInterval*) action | ||
53 | { | ||
54 | NSAssert( action!=nil, @"Ease: arguments must be non-nil"); | ||
55 | |||
56 | if( (self=[super initWithDuration: action.duration]) ) | ||
57 | other = [action retain]; | ||
58 | |||
59 | return self; | ||
60 | } | ||
61 | |||
62 | -(id) copyWithZone: (NSZone*) zone | ||
63 | { | ||
64 | CCAction *copy = [[[self class] allocWithZone:zone] initWithAction:[[other copy] autorelease]]; | ||
65 | return copy; | ||
66 | } | ||
67 | |||
68 | -(void) dealloc | ||
69 | { | ||
70 | [other release]; | ||
71 | [super dealloc]; | ||
72 | } | ||
73 | |||
74 | -(void) startWithTarget:(id)aTarget | ||
75 | { | ||
76 | [super startWithTarget:aTarget]; | ||
77 | [other startWithTarget:target_]; | ||
78 | } | ||
79 | |||
80 | -(void) stop | ||
81 | { | ||
82 | [other stop]; | ||
83 | [super stop]; | ||
84 | } | ||
85 | |||
86 | -(void) update: (ccTime) t | ||
87 | { | ||
88 | [other update: t]; | ||
89 | } | ||
90 | |||
91 | -(CCActionInterval*) reverse | ||
92 | { | ||
93 | return [[self class] actionWithAction: [other reverse]]; | ||
94 | } | ||
95 | @end | ||
96 | |||
97 | |||
98 | #pragma mark - | ||
99 | #pragma mark EaseRate | ||
100 | |||
101 | // | ||
102 | // EaseRateAction | ||
103 | // | ||
104 | @implementation CCEaseRateAction | ||
105 | @synthesize rate; | ||
106 | +(id) actionWithAction: (CCActionInterval*) action rate:(float)aRate | ||
107 | { | ||
108 | return [[[self alloc] initWithAction: action rate:aRate] autorelease ]; | ||
109 | } | ||
110 | |||
111 | -(id) initWithAction: (CCActionInterval*) action rate:(float)aRate | ||
112 | { | ||
113 | if( (self=[super initWithAction:action ]) ) | ||
114 | self.rate = aRate; | ||
115 | |||
116 | return self; | ||
117 | } | ||
118 | |||
119 | -(id) copyWithZone: (NSZone*) zone | ||
120 | { | ||
121 | CCAction *copy = [[[self class] allocWithZone:zone] initWithAction:[[other copy] autorelease] rate:rate]; | ||
122 | return copy; | ||
123 | } | ||
124 | |||
125 | -(void) dealloc | ||
126 | { | ||
127 | [super dealloc]; | ||
128 | } | ||
129 | |||
130 | -(CCActionInterval*) reverse | ||
131 | { | ||
132 | return [[self class] actionWithAction: [other reverse] rate:1/rate]; | ||
133 | } | ||
134 | @end | ||
135 | |||
136 | // | ||
137 | // EeseIn | ||
138 | // | ||
139 | @implementation CCEaseIn | ||
140 | -(void) update: (ccTime) t | ||
141 | { | ||
142 | [other update: powf(t,rate)]; | ||
143 | } | ||
144 | @end | ||
145 | |||
146 | // | ||
147 | // EaseOut | ||
148 | // | ||
149 | @implementation CCEaseOut | ||
150 | -(void) update: (ccTime) t | ||
151 | { | ||
152 | [other update: powf(t,1/rate)]; | ||
153 | } | ||
154 | @end | ||
155 | |||
156 | // | ||
157 | // EaseInOut | ||
158 | // | ||
159 | @implementation CCEaseInOut | ||
160 | -(void) update: (ccTime) t | ||
161 | { | ||
162 | int sign =1; | ||
163 | int r = (int) rate; | ||
164 | if (r % 2 == 0) | ||
165 | sign = -1; | ||
166 | t *= 2; | ||
167 | if (t < 1) | ||
168 | [other update: 0.5f * powf (t, rate)]; | ||
169 | else | ||
170 | [other update: sign*0.5f * (powf (t-2, rate) + sign*2)]; | ||
171 | } | ||
172 | |||
173 | // InOut and OutIn are symmetrical | ||
174 | -(CCActionInterval*) reverse | ||
175 | { | ||
176 | return [[self class] actionWithAction: [other reverse] rate:rate]; | ||
177 | } | ||
178 | |||
179 | @end | ||
180 | |||
181 | #pragma mark - | ||
182 | #pragma mark EaseExponential | ||
183 | |||
184 | // | ||
185 | // EaseExponentialIn | ||
186 | // | ||
187 | @implementation CCEaseExponentialIn | ||
188 | -(void) update: (ccTime) t | ||
189 | { | ||
190 | [other update: (t==0) ? 0 : powf(2, 10 * (t/1 - 1)) - 1 * 0.001f]; | ||
191 | } | ||
192 | |||
193 | - (CCActionInterval*) reverse | ||
194 | { | ||
195 | return [CCEaseExponentialOut actionWithAction: [other reverse]]; | ||
196 | } | ||
197 | @end | ||
198 | |||
199 | // | ||
200 | // EaseExponentialOut | ||
201 | // | ||
202 | @implementation CCEaseExponentialOut | ||
203 | -(void) update: (ccTime) t | ||
204 | { | ||
205 | [other update: (t==1) ? 1 : (-powf(2, -10 * t/1) + 1)]; | ||
206 | } | ||
207 | |||
208 | - (CCActionInterval*) reverse | ||
209 | { | ||
210 | return [CCEaseExponentialIn actionWithAction: [other reverse]]; | ||
211 | } | ||
212 | @end | ||
213 | |||
214 | // | ||
215 | // EaseExponentialInOut | ||
216 | // | ||
217 | @implementation CCEaseExponentialInOut | ||
218 | -(void) update: (ccTime) t | ||
219 | { | ||
220 | t /= 0.5f; | ||
221 | if (t < 1) | ||
222 | t = 0.5f * powf(2, 10 * (t - 1)); | ||
223 | else | ||
224 | t = 0.5f * (-powf(2, -10 * (t -1) ) + 2); | ||
225 | |||
226 | [other update:t]; | ||
227 | } | ||
228 | @end | ||
229 | |||
230 | |||
231 | #pragma mark - | ||
232 | #pragma mark EaseSin actions | ||
233 | |||
234 | // | ||
235 | // EaseSineIn | ||
236 | // | ||
237 | @implementation CCEaseSineIn | ||
238 | -(void) update: (ccTime) t | ||
239 | { | ||
240 | [other update:-1*cosf(t * (float)M_PI_2) +1]; | ||
241 | } | ||
242 | |||
243 | - (CCActionInterval*) reverse | ||
244 | { | ||
245 | return [CCEaseSineOut actionWithAction: [other reverse]]; | ||
246 | } | ||
247 | @end | ||
248 | |||
249 | // | ||
250 | // EaseSineOut | ||
251 | // | ||
252 | @implementation CCEaseSineOut | ||
253 | -(void) update: (ccTime) t | ||
254 | { | ||
255 | [other update:sinf(t * (float)M_PI_2)]; | ||
256 | } | ||
257 | |||
258 | - (CCActionInterval*) reverse | ||
259 | { | ||
260 | return [CCEaseSineIn actionWithAction: [other reverse]]; | ||
261 | } | ||
262 | @end | ||
263 | |||
264 | // | ||
265 | // EaseSineInOut | ||
266 | // | ||
267 | @implementation CCEaseSineInOut | ||
268 | -(void) update: (ccTime) t | ||
269 | { | ||
270 | [other update:-0.5f*(cosf( (float)M_PI*t) - 1)]; | ||
271 | } | ||
272 | @end | ||
273 | |||
274 | #pragma mark - | ||
275 | #pragma mark EaseElastic actions | ||
276 | |||
277 | // | ||
278 | // EaseElastic | ||
279 | // | ||
280 | @implementation CCEaseElastic | ||
281 | |||
282 | @synthesize period = period_; | ||
283 | |||
284 | +(id) actionWithAction: (CCActionInterval*) action | ||
285 | { | ||
286 | return [[[self alloc] initWithAction:action period:0.3f] autorelease]; | ||
287 | } | ||
288 | |||
289 | +(id) actionWithAction: (CCActionInterval*) action period:(float)period | ||
290 | { | ||
291 | return [[[self alloc] initWithAction:action period:period] autorelease]; | ||
292 | } | ||
293 | |||
294 | -(id) initWithAction: (CCActionInterval*) action | ||
295 | { | ||
296 | return [self initWithAction:action period:0.3f]; | ||
297 | } | ||
298 | |||
299 | -(id) initWithAction: (CCActionInterval*) action period:(float)period | ||
300 | { | ||
301 | if( (self=[super initWithAction:action]) ) | ||
302 | period_ = period; | ||
303 | |||
304 | return self; | ||
305 | } | ||
306 | |||
307 | -(id) copyWithZone: (NSZone*) zone | ||
308 | { | ||
309 | CCAction *copy = [[[self class] allocWithZone:zone] initWithAction:[[other copy] autorelease] period:period_]; | ||
310 | return copy; | ||
311 | } | ||
312 | |||
313 | -(CCActionInterval*) reverse | ||
314 | { | ||
315 | NSAssert(NO,@"Override me"); | ||
316 | return nil; | ||
317 | } | ||
318 | |||
319 | @end | ||
320 | |||
321 | // | ||
322 | // EaseElasticIn | ||
323 | // | ||
324 | |||
325 | @implementation CCEaseElasticIn | ||
326 | -(void) update: (ccTime) t | ||
327 | { | ||
328 | ccTime newT = 0; | ||
329 | if (t == 0 || t == 1) | ||
330 | newT = t; | ||
331 | |||
332 | else { | ||
333 | float s = period_ / 4; | ||
334 | t = t - 1; | ||
335 | newT = -powf(2, 10 * t) * sinf( (t-s) *M_PI_X_2 / period_); | ||
336 | } | ||
337 | [other update:newT]; | ||
338 | } | ||
339 | |||
340 | - (CCActionInterval*) reverse | ||
341 | { | ||
342 | return [CCEaseElasticOut actionWithAction: [other reverse] period:period_]; | ||
343 | } | ||
344 | |||
345 | @end | ||
346 | |||
347 | // | ||
348 | // EaseElasticOut | ||
349 | // | ||
350 | @implementation CCEaseElasticOut | ||
351 | |||
352 | -(void) update: (ccTime) t | ||
353 | { | ||
354 | ccTime newT = 0; | ||
355 | if (t == 0 || t == 1) { | ||
356 | newT = t; | ||
357 | |||
358 | } else { | ||
359 | float s = period_ / 4; | ||
360 | newT = powf(2, -10 * t) * sinf( (t-s) *M_PI_X_2 / period_) + 1; | ||
361 | } | ||
362 | [other update:newT]; | ||
363 | } | ||
364 | |||
365 | - (CCActionInterval*) reverse | ||
366 | { | ||
367 | return [CCEaseElasticIn actionWithAction: [other reverse] period:period_]; | ||
368 | } | ||
369 | |||
370 | @end | ||
371 | |||
372 | // | ||
373 | // EaseElasticInOut | ||
374 | // | ||
375 | @implementation CCEaseElasticInOut | ||
376 | -(void) update: (ccTime) t | ||
377 | { | ||
378 | ccTime newT = 0; | ||
379 | |||
380 | if( t == 0 || t == 1 ) | ||
381 | newT = t; | ||
382 | else { | ||
383 | t = t * 2; | ||
384 | if(! period_ ) | ||
385 | period_ = 0.3f * 1.5f; | ||
386 | ccTime s = period_ / 4; | ||
387 | |||
388 | t = t -1; | ||
389 | if( t < 0 ) | ||
390 | newT = -0.5f * powf(2, 10 * t) * sinf((t - s) * M_PI_X_2 / period_); | ||
391 | else | ||
392 | newT = powf(2, -10 * t) * sinf((t - s) * M_PI_X_2 / period_) * 0.5f + 1; | ||
393 | } | ||
394 | [other update:newT]; | ||
395 | } | ||
396 | |||
397 | - (CCActionInterval*) reverse | ||
398 | { | ||
399 | return [CCEaseElasticInOut actionWithAction: [other reverse] period:period_]; | ||
400 | } | ||
401 | |||
402 | @end | ||
403 | |||
404 | #pragma mark - | ||
405 | #pragma mark EaseBounce actions | ||
406 | |||
407 | // | ||
408 | // EaseBounce | ||
409 | // | ||
410 | @implementation CCEaseBounce | ||
411 | -(ccTime) bounceTime:(ccTime) t | ||
412 | { | ||
413 | if (t < 1 / 2.75) { | ||
414 | return 7.5625f * t * t; | ||
415 | } | ||
416 | else if (t < 2 / 2.75) { | ||
417 | t -= 1.5f / 2.75f; | ||
418 | return 7.5625f * t * t + 0.75f; | ||
419 | } | ||
420 | else if (t < 2.5 / 2.75) { | ||
421 | t -= 2.25f / 2.75f; | ||
422 | return 7.5625f * t * t + 0.9375f; | ||
423 | } | ||
424 | |||
425 | t -= 2.625f / 2.75f; | ||
426 | return 7.5625f * t * t + 0.984375f; | ||
427 | } | ||
428 | @end | ||
429 | |||
430 | // | ||
431 | // EaseBounceIn | ||
432 | // | ||
433 | |||
434 | @implementation CCEaseBounceIn | ||
435 | |||
436 | -(void) update: (ccTime) t | ||
437 | { | ||
438 | ccTime newT = 1 - [self bounceTime:1-t]; | ||
439 | [other update:newT]; | ||
440 | } | ||
441 | |||
442 | - (CCActionInterval*) reverse | ||
443 | { | ||
444 | return [CCEaseBounceOut actionWithAction: [other reverse]]; | ||
445 | } | ||
446 | |||
447 | @end | ||
448 | |||
449 | @implementation CCEaseBounceOut | ||
450 | |||
451 | -(void) update: (ccTime) t | ||
452 | { | ||
453 | ccTime newT = [self bounceTime:t]; | ||
454 | [other update:newT]; | ||
455 | } | ||
456 | |||
457 | - (CCActionInterval*) reverse | ||
458 | { | ||
459 | return [CCEaseBounceIn actionWithAction: [other reverse]]; | ||
460 | } | ||
461 | |||
462 | @end | ||
463 | |||
464 | @implementation CCEaseBounceInOut | ||
465 | |||
466 | -(void) update: (ccTime) t | ||
467 | { | ||
468 | ccTime newT = 0; | ||
469 | if (t < 0.5) { | ||
470 | t = t * 2; | ||
471 | newT = (1 - [self bounceTime:1-t] ) * 0.5f; | ||
472 | } else | ||
473 | newT = [self bounceTime:t * 2 - 1] * 0.5f + 0.5f; | ||
474 | |||
475 | [other update:newT]; | ||
476 | } | ||
477 | @end | ||
478 | |||
479 | #pragma mark - | ||
480 | #pragma mark Ease Back actions | ||
481 | |||
482 | // | ||
483 | // EaseBackIn | ||
484 | // | ||
485 | @implementation CCEaseBackIn | ||
486 | |||
487 | -(void) update: (ccTime) t | ||
488 | { | ||
489 | ccTime overshoot = 1.70158f; | ||
490 | [other update: t * t * ((overshoot + 1) * t - overshoot)]; | ||
491 | } | ||
492 | |||
493 | - (CCActionInterval*) reverse | ||
494 | { | ||
495 | return [CCEaseBackOut actionWithAction: [other reverse]]; | ||
496 | } | ||
497 | @end | ||
498 | |||
499 | // | ||
500 | // EaseBackOut | ||
501 | // | ||
502 | @implementation CCEaseBackOut | ||
503 | -(void) update: (ccTime) t | ||
504 | { | ||
505 | ccTime overshoot = 1.70158f; | ||
506 | |||
507 | t = t - 1; | ||
508 | [other update: t * t * ((overshoot + 1) * t + overshoot) + 1]; | ||
509 | } | ||
510 | |||
511 | - (CCActionInterval*) reverse | ||
512 | { | ||
513 | return [CCEaseBackIn actionWithAction: [other reverse]]; | ||
514 | } | ||
515 | @end | ||
516 | |||
517 | // | ||
518 | // EaseBackInOut | ||
519 | // | ||
520 | @implementation CCEaseBackInOut | ||
521 | |||
522 | -(void) update: (ccTime) t | ||
523 | { | ||
524 | ccTime overshoot = 1.70158f * 1.525f; | ||
525 | |||
526 | t = t * 2; | ||
527 | if (t < 1) | ||
528 | [other update: (t * t * ((overshoot + 1) * t - overshoot)) / 2]; | ||
529 | else { | ||
530 | t = t - 2; | ||
531 | [other update: (t * t * ((overshoot + 1) * t + overshoot)) / 2 + 1]; | ||
532 | } | ||
533 | } | ||
534 | @end | ||
diff --git a/libs/cocos2d/CCActionGrid.h b/libs/cocos2d/CCActionGrid.h new file mode 100755 index 0000000..6b31179 --- /dev/null +++ b/libs/cocos2d/CCActionGrid.h | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 On-Core | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCActionInterval.h" | ||
28 | #import "CCActionInstant.h" | ||
29 | #import "CCGrid.h" | ||
30 | |||
31 | @class CCGridBase; | ||
32 | |||
33 | /** Base class for Grid actions */ | ||
34 | @interface CCGridAction : CCActionInterval | ||
35 | { | ||
36 | ccGridSize gridSize_; | ||
37 | } | ||
38 | |||
39 | /** size of the grid */ | ||
40 | @property (nonatomic,readwrite) ccGridSize gridSize; | ||
41 | |||
42 | /** creates the action with size and duration */ | ||
43 | +(id) actionWithSize:(ccGridSize)size duration:(ccTime)d; | ||
44 | /** initializes the action with size and duration */ | ||
45 | -(id) initWithSize:(ccGridSize)gridSize duration:(ccTime)d; | ||
46 | /** returns the grid */ | ||
47 | -(CCGridBase *)grid; | ||
48 | |||
49 | @end | ||
50 | |||
51 | //////////////////////////////////////////////////////////// | ||
52 | |||
53 | /** Base class for CCGrid3D actions. | ||
54 | Grid3D actions can modify a non-tiled grid. | ||
55 | */ | ||
56 | @interface CCGrid3DAction : CCGridAction | ||
57 | { | ||
58 | } | ||
59 | |||
60 | /** returns the vertex than belongs to certain position in the grid */ | ||
61 | -(ccVertex3F)vertex:(ccGridSize)pos; | ||
62 | /** returns the non-transformed vertex than belongs to certain position in the grid */ | ||
63 | -(ccVertex3F)originalVertex:(ccGridSize)pos; | ||
64 | /** sets a new vertex to a certain position of the grid */ | ||
65 | -(void)setVertex:(ccGridSize)pos vertex:(ccVertex3F)vertex; | ||
66 | |||
67 | @end | ||
68 | |||
69 | //////////////////////////////////////////////////////////// | ||
70 | |||
71 | /** Base class for CCTiledGrid3D actions */ | ||
72 | @interface CCTiledGrid3DAction : CCGridAction | ||
73 | { | ||
74 | } | ||
75 | |||
76 | /** returns the tile that belongs to a certain position of the grid */ | ||
77 | -(ccQuad3)tile:(ccGridSize)pos; | ||
78 | /** returns the non-transformed tile that belongs to a certain position of the grid */ | ||
79 | -(ccQuad3)originalTile:(ccGridSize)pos; | ||
80 | /** sets a new tile to a certain position of the grid */ | ||
81 | -(void)setTile:(ccGridSize)pos coords:(ccQuad3)coords; | ||
82 | |||
83 | @end | ||
84 | |||
85 | //////////////////////////////////////////////////////////// | ||
86 | |||
87 | /** CCAccelDeccelAmplitude action */ | ||
88 | @interface CCAccelDeccelAmplitude : CCActionInterval | ||
89 | { | ||
90 | float rate_; | ||
91 | CCActionInterval *other_; | ||
92 | } | ||
93 | |||
94 | /** amplitude rate */ | ||
95 | @property (nonatomic,readwrite) float rate; | ||
96 | |||
97 | /** creates the action with an inner action that has the amplitude property, and a duration time */ | ||
98 | +(id)actionWithAction:(CCAction*)action duration:(ccTime)d; | ||
99 | /** initializes the action with an inner action that has the amplitude property, and a duration time */ | ||
100 | -(id)initWithAction:(CCAction*)action duration:(ccTime)d; | ||
101 | |||
102 | @end | ||
103 | |||
104 | //////////////////////////////////////////////////////////// | ||
105 | |||
106 | /** CCAccelAmplitude action */ | ||
107 | @interface CCAccelAmplitude : CCActionInterval | ||
108 | { | ||
109 | float rate_; | ||
110 | CCActionInterval *other_; | ||
111 | } | ||
112 | |||
113 | /** amplitude rate */ | ||
114 | @property (nonatomic,readwrite) float rate; | ||
115 | |||
116 | /** creates the action with an inner action that has the amplitude property, and a duration time */ | ||
117 | +(id)actionWithAction:(CCAction*)action duration:(ccTime)d; | ||
118 | /** initializes the action with an inner action that has the amplitude property, and a duration time */ | ||
119 | -(id)initWithAction:(CCAction*)action duration:(ccTime)d; | ||
120 | |||
121 | @end | ||
122 | |||
123 | //////////////////////////////////////////////////////////// | ||
124 | |||
125 | /** CCDeccelAmplitude action */ | ||
126 | @interface CCDeccelAmplitude : CCActionInterval | ||
127 | { | ||
128 | float rate_; | ||
129 | CCActionInterval *other_; | ||
130 | } | ||
131 | |||
132 | /** amplitude rate */ | ||
133 | @property (nonatomic,readwrite) float rate; | ||
134 | |||
135 | /** creates the action with an inner action that has the amplitude property, and a duration time */ | ||
136 | +(id)actionWithAction:(CCAction*)action duration:(ccTime)d; | ||
137 | /** initializes the action with an inner action that has the amplitude property, and a duration time */ | ||
138 | -(id)initWithAction:(CCAction*)action duration:(ccTime)d; | ||
139 | |||
140 | @end | ||
141 | |||
142 | //////////////////////////////////////////////////////////// | ||
143 | |||
144 | /** CCStopGrid action. | ||
145 | Don't call this action if another grid action is active. | ||
146 | Call if you want to remove the the grid effect. Example: | ||
147 | [Sequence actions:[Lens ...], [StopGrid action], nil]; | ||
148 | */ | ||
149 | @interface CCStopGrid : CCActionInstant | ||
150 | { | ||
151 | } | ||
152 | @end | ||
153 | |||
154 | //////////////////////////////////////////////////////////// | ||
155 | |||
156 | /** CCReuseGrid action */ | ||
157 | @interface CCReuseGrid : CCActionInstant | ||
158 | { | ||
159 | int t_; | ||
160 | } | ||
161 | /** creates an action with the number of times that the current grid will be reused */ | ||
162 | +(id) actionWithTimes: (int) times; | ||
163 | /** initializes an action with the number of times that the current grid will be reused */ | ||
164 | -(id) initWithTimes: (int) times; | ||
165 | @end | ||
diff --git a/libs/cocos2d/CCActionGrid.m b/libs/cocos2d/CCActionGrid.m new file mode 100755 index 0000000..638e27d --- /dev/null +++ b/libs/cocos2d/CCActionGrid.m | |||
@@ -0,0 +1,386 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 On-Core | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCActionGrid.h" | ||
28 | #import "CCDirector.h" | ||
29 | |||
30 | #pragma mark - | ||
31 | #pragma mark GridAction | ||
32 | |||
33 | @implementation CCGridAction | ||
34 | |||
35 | @synthesize gridSize = gridSize_; | ||
36 | |||
37 | +(id) actionWithSize:(ccGridSize)size duration:(ccTime)d | ||
38 | { | ||
39 | return [[[self alloc] initWithSize:size duration:d ] autorelease]; | ||
40 | } | ||
41 | |||
42 | -(id) initWithSize:(ccGridSize)gSize duration:(ccTime)d | ||
43 | { | ||
44 | if ( (self = [super initWithDuration:d]) ) | ||
45 | { | ||
46 | gridSize_ = gSize; | ||
47 | } | ||
48 | |||
49 | return self; | ||
50 | } | ||
51 | |||
52 | -(void)startWithTarget:(id)aTarget | ||
53 | { | ||
54 | [super startWithTarget:aTarget]; | ||
55 | |||
56 | CCGridBase *newgrid = [self grid]; | ||
57 | |||
58 | CCNode *t = (CCNode*) target_; | ||
59 | CCGridBase *targetGrid = [t grid]; | ||
60 | |||
61 | if ( targetGrid && targetGrid.reuseGrid > 0 ) | ||
62 | { | ||
63 | if ( targetGrid.active && targetGrid.gridSize.x == gridSize_.x && targetGrid.gridSize.y == gridSize_.y && [targetGrid isKindOfClass:[newgrid class]] ) | ||
64 | [targetGrid reuse]; | ||
65 | else | ||
66 | [NSException raise:@"GridBase" format:@"Cannot reuse grid"]; | ||
67 | } | ||
68 | else | ||
69 | { | ||
70 | if ( targetGrid && targetGrid.active ) | ||
71 | targetGrid.active = NO; | ||
72 | |||
73 | t.grid = newgrid; | ||
74 | t.grid.active = YES; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | -(CCGridBase *)grid | ||
79 | { | ||
80 | [NSException raise:@"GridBase" format:@"Abstract class needs implementation"]; | ||
81 | return nil; | ||
82 | } | ||
83 | |||
84 | - (CCActionInterval*) reverse | ||
85 | { | ||
86 | return [CCReverseTime actionWithAction:self]; | ||
87 | } | ||
88 | |||
89 | -(id) copyWithZone: (NSZone*) zone | ||
90 | { | ||
91 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithSize:gridSize_ duration:duration_]; | ||
92 | return copy; | ||
93 | } | ||
94 | @end | ||
95 | |||
96 | //////////////////////////////////////////////////////////// | ||
97 | |||
98 | #pragma mark - | ||
99 | #pragma mark Grid3DAction | ||
100 | |||
101 | @implementation CCGrid3DAction | ||
102 | |||
103 | -(CCGridBase *)grid | ||
104 | { | ||
105 | return [CCGrid3D gridWithSize:gridSize_]; | ||
106 | } | ||
107 | |||
108 | -(ccVertex3F)vertex:(ccGridSize)pos | ||
109 | { | ||
110 | CCGrid3D *g = (CCGrid3D *)[target_ grid]; | ||
111 | return [g vertex:pos]; | ||
112 | } | ||
113 | |||
114 | -(ccVertex3F)originalVertex:(ccGridSize)pos | ||
115 | { | ||
116 | CCGrid3D *g = (CCGrid3D *)[target_ grid]; | ||
117 | return [g originalVertex:pos]; | ||
118 | } | ||
119 | |||
120 | -(void)setVertex:(ccGridSize)pos vertex:(ccVertex3F)vertex | ||
121 | { | ||
122 | CCGrid3D *g = (CCGrid3D *)[target_ grid]; | ||
123 | [g setVertex:pos vertex:vertex]; | ||
124 | } | ||
125 | @end | ||
126 | |||
127 | //////////////////////////////////////////////////////////// | ||
128 | |||
129 | #pragma mark - | ||
130 | #pragma mark TiledGrid3DAction | ||
131 | |||
132 | @implementation CCTiledGrid3DAction | ||
133 | |||
134 | -(CCGridBase *)grid | ||
135 | { | ||
136 | return [CCTiledGrid3D gridWithSize:gridSize_]; | ||
137 | } | ||
138 | |||
139 | -(ccQuad3)tile:(ccGridSize)pos | ||
140 | { | ||
141 | CCTiledGrid3D *g = (CCTiledGrid3D *)[target_ grid]; | ||
142 | return [g tile:pos]; | ||
143 | } | ||
144 | |||
145 | -(ccQuad3)originalTile:(ccGridSize)pos | ||
146 | { | ||
147 | CCTiledGrid3D *g = (CCTiledGrid3D *)[target_ grid]; | ||
148 | return [g originalTile:pos]; | ||
149 | } | ||
150 | |||
151 | -(void)setTile:(ccGridSize)pos coords:(ccQuad3)coords | ||
152 | { | ||
153 | CCTiledGrid3D *g = (CCTiledGrid3D *)[target_ grid]; | ||
154 | [g setTile:pos coords:coords]; | ||
155 | } | ||
156 | |||
157 | @end | ||
158 | |||
159 | //////////////////////////////////////////////////////////// | ||
160 | |||
161 | @interface CCActionInterval (Amplitude) | ||
162 | -(void)setAmplitudeRate:(CGFloat)amp; | ||
163 | -(CGFloat)getAmplitudeRate; | ||
164 | @end | ||
165 | |||
166 | @implementation CCActionInterval (Amplitude) | ||
167 | -(void)setAmplitudeRate:(CGFloat)amp | ||
168 | { | ||
169 | [NSException raise:@"IntervalAction (Amplitude)" format:@"Abstract class needs implementation"]; | ||
170 | } | ||
171 | |||
172 | -(CGFloat)getAmplitudeRate | ||
173 | { | ||
174 | [NSException raise:@"IntervalAction (Amplitude)" format:@"Abstract class needs implementation"]; | ||
175 | return 0; | ||
176 | } | ||
177 | @end | ||
178 | |||
179 | //////////////////////////////////////////////////////////// | ||
180 | |||
181 | #pragma mark - | ||
182 | #pragma mark AccelDeccelAmplitude | ||
183 | |||
184 | @implementation CCAccelDeccelAmplitude | ||
185 | |||
186 | @synthesize rate=rate_; | ||
187 | |||
188 | +(id)actionWithAction:(CCAction*)action duration:(ccTime)d | ||
189 | { | ||
190 | return [[[self alloc] initWithAction:action duration:d ] autorelease]; | ||
191 | } | ||
192 | |||
193 | -(id)initWithAction:(CCAction *)action duration:(ccTime)d | ||
194 | { | ||
195 | if ( (self = [super initWithDuration:d]) ) | ||
196 | { | ||
197 | rate_ = 1.0f; | ||
198 | other_ = (CCActionInterval*)[action retain]; | ||
199 | } | ||
200 | |||
201 | return self; | ||
202 | } | ||
203 | |||
204 | -(void)dealloc | ||
205 | { | ||
206 | [other_ release]; | ||
207 | [super dealloc]; | ||
208 | } | ||
209 | |||
210 | -(void)startWithTarget:(id)aTarget | ||
211 | { | ||
212 | [super startWithTarget:aTarget]; | ||
213 | [other_ startWithTarget:target_]; | ||
214 | } | ||
215 | |||
216 | -(void) update: (ccTime) time | ||
217 | { | ||
218 | float f = time*2; | ||
219 | |||
220 | if (f > 1) | ||
221 | { | ||
222 | f -= 1; | ||
223 | f = 1 - f; | ||
224 | } | ||
225 | |||
226 | [other_ setAmplitudeRate:powf(f, rate_)]; | ||
227 | [other_ update:time]; | ||
228 | } | ||
229 | |||
230 | - (CCActionInterval*) reverse | ||
231 | { | ||
232 | return [CCAccelDeccelAmplitude actionWithAction:[other_ reverse] duration:duration_]; | ||
233 | } | ||
234 | |||
235 | @end | ||
236 | |||
237 | //////////////////////////////////////////////////////////// | ||
238 | |||
239 | #pragma mark - | ||
240 | #pragma mark AccelAmplitude | ||
241 | |||
242 | @implementation CCAccelAmplitude | ||
243 | |||
244 | @synthesize rate=rate_; | ||
245 | |||
246 | +(id)actionWithAction:(CCAction*)action duration:(ccTime)d | ||
247 | { | ||
248 | return [[[self alloc] initWithAction:action duration:d ] autorelease]; | ||
249 | } | ||
250 | |||
251 | -(id)initWithAction:(CCAction *)action duration:(ccTime)d | ||
252 | { | ||
253 | if ( (self = [super initWithDuration:d]) ) | ||
254 | { | ||
255 | rate_ = 1.0f; | ||
256 | other_ = (CCActionInterval*)[action retain]; | ||
257 | } | ||
258 | |||
259 | return self; | ||
260 | } | ||
261 | |||
262 | -(void)dealloc | ||
263 | { | ||
264 | [other_ release]; | ||
265 | [super dealloc]; | ||
266 | } | ||
267 | |||
268 | -(void)startWithTarget:(id)aTarget | ||
269 | { | ||
270 | [super startWithTarget:aTarget]; | ||
271 | [other_ startWithTarget:target_]; | ||
272 | } | ||
273 | |||
274 | -(void) update: (ccTime) time | ||
275 | { | ||
276 | [other_ setAmplitudeRate:powf(time, rate_)]; | ||
277 | [other_ update:time]; | ||
278 | } | ||
279 | |||
280 | - (CCActionInterval*) reverse | ||
281 | { | ||
282 | return [CCAccelAmplitude actionWithAction:[other_ reverse] duration:self.duration]; | ||
283 | } | ||
284 | |||
285 | @end | ||
286 | |||
287 | //////////////////////////////////////////////////////////// | ||
288 | |||
289 | #pragma mark - | ||
290 | #pragma mark DeccelAmplitude | ||
291 | |||
292 | @implementation CCDeccelAmplitude | ||
293 | |||
294 | @synthesize rate=rate_; | ||
295 | |||
296 | +(id)actionWithAction:(CCAction*)action duration:(ccTime)d | ||
297 | { | ||
298 | return [[[self alloc] initWithAction:action duration:d ] autorelease]; | ||
299 | } | ||
300 | |||
301 | -(id)initWithAction:(CCAction *)action duration:(ccTime)d | ||
302 | { | ||
303 | if ( (self = [super initWithDuration:d]) ) | ||
304 | { | ||
305 | rate_ = 1.0f; | ||
306 | other_ = (CCActionInterval*)[action retain]; | ||
307 | } | ||
308 | |||
309 | return self; | ||
310 | } | ||
311 | |||
312 | -(void)dealloc | ||
313 | { | ||
314 | [other_ release]; | ||
315 | [super dealloc]; | ||
316 | } | ||
317 | |||
318 | -(void)startWithTarget:(id)aTarget | ||
319 | { | ||
320 | [super startWithTarget:aTarget]; | ||
321 | [other_ startWithTarget:target_]; | ||
322 | } | ||
323 | |||
324 | -(void) update: (ccTime) time | ||
325 | { | ||
326 | [other_ setAmplitudeRate:powf((1-time), rate_)]; | ||
327 | [other_ update:time]; | ||
328 | } | ||
329 | |||
330 | - (CCActionInterval*) reverse | ||
331 | { | ||
332 | return [CCDeccelAmplitude actionWithAction:[other_ reverse] duration:self.duration]; | ||
333 | } | ||
334 | |||
335 | @end | ||
336 | |||
337 | //////////////////////////////////////////////////////////// | ||
338 | |||
339 | #pragma mark - | ||
340 | #pragma mark StopGrid | ||
341 | |||
342 | @implementation CCStopGrid | ||
343 | |||
344 | -(void)startWithTarget:(id)aTarget | ||
345 | { | ||
346 | [super startWithTarget:aTarget]; | ||
347 | |||
348 | if ( [[self target] grid] && [[[self target] grid] active] ) { | ||
349 | [[[self target] grid] setActive: NO]; | ||
350 | |||
351 | // [[self target] setGrid: nil]; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | @end | ||
356 | |||
357 | //////////////////////////////////////////////////////////// | ||
358 | |||
359 | #pragma mark - | ||
360 | #pragma mark ReuseGrid | ||
361 | |||
362 | @implementation CCReuseGrid | ||
363 | |||
364 | +(id)actionWithTimes:(int)times | ||
365 | { | ||
366 | return [[[self alloc] initWithTimes:times ] autorelease]; | ||
367 | } | ||
368 | |||
369 | -(id)initWithTimes:(int)times | ||
370 | { | ||
371 | if ( (self = [super init]) ) | ||
372 | t_ = times; | ||
373 | |||
374 | return self; | ||
375 | } | ||
376 | |||
377 | -(void)startWithTarget:(id)aTarget | ||
378 | { | ||
379 | [super startWithTarget:aTarget]; | ||
380 | |||
381 | CCNode *myTarget = (CCNode*) [self target]; | ||
382 | if ( myTarget.grid && myTarget.grid.active ) | ||
383 | myTarget.grid.reuseGrid += t_; | ||
384 | } | ||
385 | |||
386 | @end | ||
diff --git a/libs/cocos2d/CCActionGrid3D.h b/libs/cocos2d/CCActionGrid3D.h new file mode 100755 index 0000000..a8003f4 --- /dev/null +++ b/libs/cocos2d/CCActionGrid3D.h | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 On-Core | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCActionGrid.h" | ||
28 | |||
29 | /** CCWaves3D action */ | ||
30 | @interface CCWaves3D : CCGrid3DAction | ||
31 | { | ||
32 | int waves; | ||
33 | float amplitude; | ||
34 | float amplitudeRate; | ||
35 | } | ||
36 | |||
37 | /** amplitude of the wave */ | ||
38 | @property (nonatomic,readwrite) float amplitude; | ||
39 | /** amplitude rate of the wave */ | ||
40 | @property (nonatomic,readwrite) float amplitudeRate; | ||
41 | |||
42 | +(id)actionWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
43 | -(id)initWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
44 | |||
45 | @end | ||
46 | |||
47 | //////////////////////////////////////////////////////////// | ||
48 | |||
49 | /** CCFlipX3D action */ | ||
50 | @interface CCFlipX3D : CCGrid3DAction | ||
51 | { | ||
52 | } | ||
53 | |||
54 | /** creates the action with duration */ | ||
55 | +(id) actionWithDuration:(ccTime)d; | ||
56 | /** initizlies the action with duration */ | ||
57 | -(id) initWithDuration:(ccTime)d; | ||
58 | |||
59 | @end | ||
60 | |||
61 | //////////////////////////////////////////////////////////// | ||
62 | |||
63 | /** CCFlipY3D action */ | ||
64 | @interface CCFlipY3D : CCFlipX3D | ||
65 | { | ||
66 | } | ||
67 | |||
68 | @end | ||
69 | |||
70 | //////////////////////////////////////////////////////////// | ||
71 | |||
72 | /** CCLens3D action */ | ||
73 | @interface CCLens3D : CCGrid3DAction | ||
74 | { | ||
75 | CGPoint position_; | ||
76 | CGPoint positionInPixels_; | ||
77 | float radius_; | ||
78 | float lensEffect_; | ||
79 | BOOL dirty_; | ||
80 | } | ||
81 | |||
82 | /** lens effect. Defaults to 0.7 - 0 means no effect, 1 is very strong effect */ | ||
83 | @property (nonatomic,readwrite) float lensEffect; | ||
84 | /** lens center position in Points */ | ||
85 | @property (nonatomic,readwrite) CGPoint position; | ||
86 | |||
87 | /** creates the action with center position in Points, radius, a grid size and duration */ | ||
88 | +(id)actionWithPosition:(CGPoint)pos radius:(float)r grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
89 | /** initializes the action with center position in Points, radius, a grid size and duration */ | ||
90 | -(id)initWithPosition:(CGPoint)pos radius:(float)r grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
91 | |||
92 | @end | ||
93 | |||
94 | //////////////////////////////////////////////////////////// | ||
95 | |||
96 | /** CCRipple3D action */ | ||
97 | @interface CCRipple3D : CCGrid3DAction | ||
98 | { | ||
99 | CGPoint position_; | ||
100 | CGPoint positionInPixels_; | ||
101 | float radius_; | ||
102 | int waves_; | ||
103 | float amplitude_; | ||
104 | float amplitudeRate_; | ||
105 | } | ||
106 | |||
107 | /** center position in Points */ | ||
108 | @property (nonatomic,readwrite) CGPoint position; | ||
109 | /** amplitude */ | ||
110 | @property (nonatomic,readwrite) float amplitude; | ||
111 | /** amplitude rate */ | ||
112 | @property (nonatomic,readwrite) float amplitudeRate; | ||
113 | |||
114 | /** creates the action with a position in points, radius, number of waves, amplitude, a grid size and duration */ | ||
115 | +(id)actionWithPosition:(CGPoint)pos radius:(float)r waves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
116 | /** initializes the action with a position in points, radius, number of waves, amplitude, a grid size and duration */ | ||
117 | -(id)initWithPosition:(CGPoint)pos radius:(float)r waves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
118 | |||
119 | @end | ||
120 | |||
121 | //////////////////////////////////////////////////////////// | ||
122 | |||
123 | /** CCShaky3D action */ | ||
124 | @interface CCShaky3D : CCGrid3DAction | ||
125 | { | ||
126 | int randrange; | ||
127 | BOOL shakeZ; | ||
128 | } | ||
129 | |||
130 | /** creates the action with a range, shake Z vertices, a grid and duration */ | ||
131 | +(id)actionWithRange:(int)range shakeZ:(BOOL)shakeZ grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
132 | /** initializes the action with a range, shake Z vertices, a grid and duration */ | ||
133 | -(id)initWithRange:(int)range shakeZ:(BOOL)shakeZ grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
134 | |||
135 | @end | ||
136 | |||
137 | //////////////////////////////////////////////////////////// | ||
138 | |||
139 | /** CCLiquid action */ | ||
140 | @interface CCLiquid : CCGrid3DAction | ||
141 | { | ||
142 | int waves; | ||
143 | float amplitude; | ||
144 | float amplitudeRate; | ||
145 | |||
146 | } | ||
147 | |||
148 | /** amplitude */ | ||
149 | @property (nonatomic,readwrite) float amplitude; | ||
150 | /** amplitude rate */ | ||
151 | @property (nonatomic,readwrite) float amplitudeRate; | ||
152 | |||
153 | /** creates the action with amplitude, a grid and duration */ | ||
154 | +(id)actionWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
155 | /** initializes the action with amplitude, a grid and duration */ | ||
156 | -(id)initWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
157 | |||
158 | @end | ||
159 | |||
160 | //////////////////////////////////////////////////////////// | ||
161 | |||
162 | /** CCWaves action */ | ||
163 | @interface CCWaves : CCGrid3DAction | ||
164 | { | ||
165 | int waves; | ||
166 | float amplitude; | ||
167 | float amplitudeRate; | ||
168 | BOOL vertical; | ||
169 | BOOL horizontal; | ||
170 | } | ||
171 | |||
172 | /** amplitude */ | ||
173 | @property (nonatomic,readwrite) float amplitude; | ||
174 | /** amplitude rate */ | ||
175 | @property (nonatomic,readwrite) float amplitudeRate; | ||
176 | |||
177 | /** initializes the action with amplitude, horizontal sin, vertical sin, a grid and duration */ | ||
178 | +(id)actionWithWaves:(int)wav amplitude:(float)amp horizontal:(BOOL)h vertical:(BOOL)v grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
179 | /** creates the action with amplitude, horizontal sin, vertical sin, a grid and duration */ | ||
180 | -(id)initWithWaves:(int)wav amplitude:(float)amp horizontal:(BOOL)h vertical:(BOOL)v grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
181 | |||
182 | @end | ||
183 | |||
184 | //////////////////////////////////////////////////////////// | ||
185 | |||
186 | /** CCTwirl action */ | ||
187 | @interface CCTwirl : CCGrid3DAction | ||
188 | { | ||
189 | CGPoint position_; | ||
190 | CGPoint positionInPixels_; | ||
191 | int twirls_; | ||
192 | float amplitude_; | ||
193 | float amplitudeRate_; | ||
194 | } | ||
195 | |||
196 | /** twirl center */ | ||
197 | @property (nonatomic,readwrite) CGPoint position; | ||
198 | /** amplitude */ | ||
199 | @property (nonatomic,readwrite) float amplitude; | ||
200 | /** amplitude rate */ | ||
201 | @property (nonatomic,readwrite) float amplitudeRate; | ||
202 | |||
203 | /** creates the action with center position, number of twirls, amplitude, a grid size and duration */ | ||
204 | +(id)actionWithPosition:(CGPoint)pos twirls:(int)t amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
205 | /** initializes the action with center position, number of twirls, amplitude, a grid size and duration */ | ||
206 | -(id)initWithPosition:(CGPoint)pos twirls:(int)t amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
207 | |||
208 | @end | ||
diff --git a/libs/cocos2d/CCActionGrid3D.m b/libs/cocos2d/CCActionGrid3D.m new file mode 100755 index 0000000..1d4a783 --- /dev/null +++ b/libs/cocos2d/CCActionGrid3D.m | |||
@@ -0,0 +1,659 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 On-Core | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCActionGrid3D.h" | ||
28 | #import "ccMacros.h" | ||
29 | #import "Support/CGPointExtension.h" | ||
30 | |||
31 | #pragma mark - | ||
32 | #pragma mark Waves3D | ||
33 | |||
34 | @implementation CCWaves3D | ||
35 | |||
36 | @synthesize amplitude; | ||
37 | @synthesize amplitudeRate; | ||
38 | |||
39 | +(id)actionWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d | ||
40 | { | ||
41 | return [[[self alloc] initWithWaves:wav amplitude:amp grid:gridSize duration:d] autorelease]; | ||
42 | } | ||
43 | |||
44 | -(id)initWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gSize duration:(ccTime)d | ||
45 | { | ||
46 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
47 | { | ||
48 | waves = wav; | ||
49 | amplitude = amp; | ||
50 | amplitudeRate = 1.0f; | ||
51 | } | ||
52 | |||
53 | return self; | ||
54 | } | ||
55 | |||
56 | -(id) copyWithZone: (NSZone*) zone | ||
57 | { | ||
58 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithWaves:waves amplitude:amplitude grid:gridSize_ duration:duration_]; | ||
59 | return copy; | ||
60 | } | ||
61 | |||
62 | |||
63 | -(void)update:(ccTime)time | ||
64 | { | ||
65 | int i, j; | ||
66 | |||
67 | for( i = 0; i < (gridSize_.x+1); i++ ) | ||
68 | { | ||
69 | for( j = 0; j < (gridSize_.y+1); j++ ) | ||
70 | { | ||
71 | ccVertex3F v = [self originalVertex:ccg(i,j)]; | ||
72 | v.z += (sinf((CGFloat)M_PI*time*waves*2 + (v.y+v.x) * .01f) * amplitude * amplitudeRate); | ||
73 | [self setVertex:ccg(i,j) vertex:v]; | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | @end | ||
78 | |||
79 | //////////////////////////////////////////////////////////// | ||
80 | |||
81 | #pragma mark - | ||
82 | #pragma mark FlipX3D | ||
83 | |||
84 | @implementation CCFlipX3D | ||
85 | |||
86 | +(id) actionWithDuration:(ccTime)d | ||
87 | { | ||
88 | return [[[self alloc] initWithSize:ccg(1,1) duration:d] autorelease]; | ||
89 | } | ||
90 | |||
91 | -(id) initWithDuration:(ccTime)d | ||
92 | { | ||
93 | return [super initWithSize:ccg(1,1) duration:d]; | ||
94 | } | ||
95 | |||
96 | -(id)initWithSize:(ccGridSize)gSize duration:(ccTime)d | ||
97 | { | ||
98 | if ( gSize.x != 1 || gSize.y != 1 ) | ||
99 | { | ||
100 | [NSException raise:@"FlipX3D" format:@"Grid size must be (1,1)"]; | ||
101 | } | ||
102 | |||
103 | return [super initWithSize:gSize duration:d]; | ||
104 | } | ||
105 | |||
106 | -(id) copyWithZone: (NSZone*) zone | ||
107 | { | ||
108 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithSize:gridSize_ duration:duration_]; | ||
109 | return copy; | ||
110 | } | ||
111 | |||
112 | |||
113 | -(void)update:(ccTime)time | ||
114 | { | ||
115 | CGFloat angle = (CGFloat)M_PI * time; // 180 degrees | ||
116 | CGFloat mz = sinf( angle ); | ||
117 | angle = angle / 2.0f; // x calculates degrees from 0 to 90 | ||
118 | CGFloat mx = cosf( angle ); | ||
119 | |||
120 | ccVertex3F v0, v1, v, diff; | ||
121 | |||
122 | v0 = [self originalVertex:ccg(1,1)]; | ||
123 | v1 = [self originalVertex:ccg(0,0)]; | ||
124 | |||
125 | CGFloat x0 = v0.x; | ||
126 | CGFloat x1 = v1.x; | ||
127 | CGFloat x; | ||
128 | ccGridSize a, b, c, d; | ||
129 | |||
130 | if ( x0 > x1 ) | ||
131 | { | ||
132 | // Normal Grid | ||
133 | a = ccg(0,0); | ||
134 | b = ccg(0,1); | ||
135 | c = ccg(1,0); | ||
136 | d = ccg(1,1); | ||
137 | x = x0; | ||
138 | } | ||
139 | else | ||
140 | { | ||
141 | // Reversed Grid | ||
142 | c = ccg(0,0); | ||
143 | d = ccg(0,1); | ||
144 | a = ccg(1,0); | ||
145 | b = ccg(1,1); | ||
146 | x = x1; | ||
147 | } | ||
148 | |||
149 | diff.x = ( x - x * mx ); | ||
150 | diff.z = fabsf( floorf( (x * mz) / 4.0f ) ); | ||
151 | |||
152 | // bottom-left | ||
153 | v = [self originalVertex:a]; | ||
154 | v.x = diff.x; | ||
155 | v.z += diff.z; | ||
156 | [self setVertex:a vertex:v]; | ||
157 | |||
158 | // upper-left | ||
159 | v = [self originalVertex:b]; | ||
160 | v.x = diff.x; | ||
161 | v.z += diff.z; | ||
162 | [self setVertex:b vertex:v]; | ||
163 | |||
164 | // bottom-right | ||
165 | v = [self originalVertex:c]; | ||
166 | v.x -= diff.x; | ||
167 | v.z -= diff.z; | ||
168 | [self setVertex:c vertex:v]; | ||
169 | |||
170 | // upper-right | ||
171 | v = [self originalVertex:d]; | ||
172 | v.x -= diff.x; | ||
173 | v.z -= diff.z; | ||
174 | [self setVertex:d vertex:v]; | ||
175 | } | ||
176 | |||
177 | @end | ||
178 | |||
179 | //////////////////////////////////////////////////////////// | ||
180 | |||
181 | #pragma mark - | ||
182 | #pragma mark FlipY3D | ||
183 | |||
184 | @implementation CCFlipY3D | ||
185 | |||
186 | -(void)update:(ccTime)time | ||
187 | { | ||
188 | CGFloat angle = (CGFloat)M_PI * time; // 180 degrees | ||
189 | CGFloat mz = sinf( angle ); | ||
190 | angle = angle / 2.0f; // x calculates degrees from 0 to 90 | ||
191 | CGFloat my = cosf( angle ); | ||
192 | |||
193 | ccVertex3F v0, v1, v, diff; | ||
194 | |||
195 | v0 = [self originalVertex:ccg(1,1)]; | ||
196 | v1 = [self originalVertex:ccg(0,0)]; | ||
197 | |||
198 | CGFloat y0 = v0.y; | ||
199 | CGFloat y1 = v1.y; | ||
200 | CGFloat y; | ||
201 | ccGridSize a, b, c, d; | ||
202 | |||
203 | if ( y0 > y1 ) | ||
204 | { | ||
205 | // Normal Grid | ||
206 | a = ccg(0,0); | ||
207 | b = ccg(0,1); | ||
208 | c = ccg(1,0); | ||
209 | d = ccg(1,1); | ||
210 | y = y0; | ||
211 | } | ||
212 | else | ||
213 | { | ||
214 | // Reversed Grid | ||
215 | b = ccg(0,0); | ||
216 | a = ccg(0,1); | ||
217 | d = ccg(1,0); | ||
218 | c = ccg(1,1); | ||
219 | y = y1; | ||
220 | } | ||
221 | |||
222 | diff.y = y - y * my; | ||
223 | diff.z = fabsf( floorf( (y * mz) / 4.0f ) ); | ||
224 | |||
225 | // bottom-left | ||
226 | v = [self originalVertex:a]; | ||
227 | v.y = diff.y; | ||
228 | v.z += diff.z; | ||
229 | [self setVertex:a vertex:v]; | ||
230 | |||
231 | // upper-left | ||
232 | v = [self originalVertex:b]; | ||
233 | v.y -= diff.y; | ||
234 | v.z -= diff.z; | ||
235 | [self setVertex:b vertex:v]; | ||
236 | |||
237 | // bottom-right | ||
238 | v = [self originalVertex:c]; | ||
239 | v.y = diff.y; | ||
240 | v.z += diff.z; | ||
241 | [self setVertex:c vertex:v]; | ||
242 | |||
243 | // upper-right | ||
244 | v = [self originalVertex:d]; | ||
245 | v.y -= diff.y; | ||
246 | v.z -= diff.z; | ||
247 | [self setVertex:d vertex:v]; | ||
248 | } | ||
249 | |||
250 | @end | ||
251 | |||
252 | //////////////////////////////////////////////////////////// | ||
253 | |||
254 | #pragma mark - | ||
255 | #pragma mark Lens3D | ||
256 | |||
257 | @implementation CCLens3D | ||
258 | |||
259 | @synthesize lensEffect=lensEffect_; | ||
260 | |||
261 | +(id)actionWithPosition:(CGPoint)pos radius:(float)r grid:(ccGridSize)gridSize duration:(ccTime)d | ||
262 | { | ||
263 | return [[[self alloc] initWithPosition:pos radius:r grid:gridSize duration:d] autorelease]; | ||
264 | } | ||
265 | |||
266 | -(id)initWithPosition:(CGPoint)pos radius:(float)r grid:(ccGridSize)gSize duration:(ccTime)d | ||
267 | { | ||
268 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
269 | { | ||
270 | position_ = ccp(-1,-1); | ||
271 | self.position = pos; | ||
272 | radius_ = r; | ||
273 | lensEffect_ = 0.7f; | ||
274 | dirty_ = YES; | ||
275 | } | ||
276 | |||
277 | return self; | ||
278 | } | ||
279 | |||
280 | -(id) copyWithZone: (NSZone*) zone | ||
281 | { | ||
282 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithPosition:position_ radius:radius_ grid:gridSize_ duration:duration_]; | ||
283 | return copy; | ||
284 | } | ||
285 | |||
286 | -(void) setPosition:(CGPoint)pos | ||
287 | { | ||
288 | if( ! CGPointEqualToPoint(pos, position_) ) { | ||
289 | position_ = pos; | ||
290 | positionInPixels_.x = pos.x * CC_CONTENT_SCALE_FACTOR(); | ||
291 | positionInPixels_.y = pos.y * CC_CONTENT_SCALE_FACTOR(); | ||
292 | |||
293 | dirty_ = YES; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | -(CGPoint) position | ||
298 | { | ||
299 | return position_; | ||
300 | } | ||
301 | |||
302 | -(void)update:(ccTime)time | ||
303 | { | ||
304 | if ( dirty_ ) | ||
305 | { | ||
306 | int i, j; | ||
307 | |||
308 | for( i = 0; i < gridSize_.x+1; i++ ) | ||
309 | { | ||
310 | for( j = 0; j < gridSize_.y+1; j++ ) | ||
311 | { | ||
312 | ccVertex3F v = [self originalVertex:ccg(i,j)]; | ||
313 | CGPoint vect = ccpSub(positionInPixels_, ccp(v.x,v.y)); | ||
314 | CGFloat r = ccpLength(vect); | ||
315 | |||
316 | if ( r < radius_ ) | ||
317 | { | ||
318 | r = radius_ - r; | ||
319 | CGFloat pre_log = r / radius_; | ||
320 | if ( pre_log == 0 ) pre_log = 0.001f; | ||
321 | float l = logf(pre_log) * lensEffect_; | ||
322 | float new_r = expf( l ) * radius_; | ||
323 | |||
324 | if ( ccpLength(vect) > 0 ) | ||
325 | { | ||
326 | vect = ccpNormalize(vect); | ||
327 | CGPoint new_vect = ccpMult(vect, new_r); | ||
328 | v.z += ccpLength(new_vect) * lensEffect_; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | [self setVertex:ccg(i,j) vertex:v]; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | dirty_ = NO; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | @end | ||
341 | |||
342 | //////////////////////////////////////////////////////////// | ||
343 | |||
344 | #pragma mark - | ||
345 | #pragma mark Ripple3D | ||
346 | |||
347 | @implementation CCRipple3D | ||
348 | |||
349 | @synthesize amplitude = amplitude_; | ||
350 | @synthesize amplitudeRate = amplitudeRate_; | ||
351 | |||
352 | +(id)actionWithPosition:(CGPoint)pos radius:(float)r waves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d | ||
353 | { | ||
354 | return [[[self alloc] initWithPosition:pos radius:r waves:wav amplitude:amp grid:gridSize duration:d] autorelease]; | ||
355 | } | ||
356 | |||
357 | -(id)initWithPosition:(CGPoint)pos radius:(float)r waves:(int)wav amplitude:(float)amp grid:(ccGridSize)gSize duration:(ccTime)d | ||
358 | { | ||
359 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
360 | { | ||
361 | self.position = pos; | ||
362 | radius_ = r; | ||
363 | waves_ = wav; | ||
364 | amplitude_ = amp; | ||
365 | amplitudeRate_ = 1.0f; | ||
366 | } | ||
367 | |||
368 | return self; | ||
369 | } | ||
370 | |||
371 | -(CGPoint) position | ||
372 | { | ||
373 | return position_; | ||
374 | } | ||
375 | |||
376 | -(void) setPosition:(CGPoint)pos | ||
377 | { | ||
378 | position_ = pos; | ||
379 | positionInPixels_.x = pos.x * CC_CONTENT_SCALE_FACTOR(); | ||
380 | positionInPixels_.y = pos.y * CC_CONTENT_SCALE_FACTOR(); | ||
381 | } | ||
382 | |||
383 | -(id) copyWithZone: (NSZone*) zone | ||
384 | { | ||
385 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithPosition:position_ radius:radius_ waves:waves_ amplitude:amplitude_ grid:gridSize_ duration:duration_]; | ||
386 | return copy; | ||
387 | } | ||
388 | |||
389 | |||
390 | -(void)update:(ccTime)time | ||
391 | { | ||
392 | int i, j; | ||
393 | |||
394 | for( i = 0; i < (gridSize_.x+1); i++ ) | ||
395 | { | ||
396 | for( j = 0; j < (gridSize_.y+1); j++ ) | ||
397 | { | ||
398 | ccVertex3F v = [self originalVertex:ccg(i,j)]; | ||
399 | CGPoint vect = ccpSub(positionInPixels_, ccp(v.x,v.y)); | ||
400 | CGFloat r = ccpLength(vect); | ||
401 | |||
402 | if ( r < radius_ ) | ||
403 | { | ||
404 | r = radius_ - r; | ||
405 | CGFloat rate = powf( r / radius_, 2); | ||
406 | v.z += (sinf( time*(CGFloat)M_PI*waves_*2 + r * 0.1f) * amplitude_ * amplitudeRate_ * rate ); | ||
407 | } | ||
408 | |||
409 | [self setVertex:ccg(i,j) vertex:v]; | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | @end | ||
415 | |||
416 | //////////////////////////////////////////////////////////// | ||
417 | |||
418 | #pragma mark - | ||
419 | #pragma mark Shaky3D | ||
420 | |||
421 | @implementation CCShaky3D | ||
422 | |||
423 | +(id)actionWithRange:(int)range shakeZ:(BOOL)sz grid:(ccGridSize)gridSize duration:(ccTime)d | ||
424 | { | ||
425 | return [[[self alloc] initWithRange:range shakeZ:sz grid:gridSize duration:d] autorelease]; | ||
426 | } | ||
427 | |||
428 | -(id)initWithRange:(int)range shakeZ:(BOOL)sz grid:(ccGridSize)gSize duration:(ccTime)d | ||
429 | { | ||
430 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
431 | { | ||
432 | randrange = range; | ||
433 | shakeZ = sz; | ||
434 | } | ||
435 | |||
436 | return self; | ||
437 | } | ||
438 | |||
439 | -(id) copyWithZone: (NSZone*) zone | ||
440 | { | ||
441 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithRange:randrange shakeZ:shakeZ grid:gridSize_ duration:duration_]; | ||
442 | return copy; | ||
443 | } | ||
444 | |||
445 | -(void)update:(ccTime)time | ||
446 | { | ||
447 | int i, j; | ||
448 | |||
449 | for( i = 0; i < (gridSize_.x+1); i++ ) | ||
450 | { | ||
451 | for( j = 0; j < (gridSize_.y+1); j++ ) | ||
452 | { | ||
453 | ccVertex3F v = [self originalVertex:ccg(i,j)]; | ||
454 | v.x += ( rand() % (randrange*2) ) - randrange; | ||
455 | v.y += ( rand() % (randrange*2) ) - randrange; | ||
456 | if( shakeZ ) | ||
457 | v.z += ( rand() % (randrange*2) ) - randrange; | ||
458 | |||
459 | [self setVertex:ccg(i,j) vertex:v]; | ||
460 | } | ||
461 | } | ||
462 | } | ||
463 | |||
464 | @end | ||
465 | |||
466 | //////////////////////////////////////////////////////////// | ||
467 | |||
468 | #pragma mark - | ||
469 | #pragma mark Liquid | ||
470 | |||
471 | @implementation CCLiquid | ||
472 | |||
473 | @synthesize amplitude; | ||
474 | @synthesize amplitudeRate; | ||
475 | |||
476 | +(id)actionWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d | ||
477 | { | ||
478 | return [[[self alloc] initWithWaves:wav amplitude:amp grid:gridSize duration:d] autorelease]; | ||
479 | } | ||
480 | |||
481 | -(id)initWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gSize duration:(ccTime)d | ||
482 | { | ||
483 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
484 | { | ||
485 | waves = wav; | ||
486 | amplitude = amp; | ||
487 | amplitudeRate = 1.0f; | ||
488 | } | ||
489 | |||
490 | return self; | ||
491 | } | ||
492 | |||
493 | -(void)update:(ccTime)time | ||
494 | { | ||
495 | int i, j; | ||
496 | |||
497 | for( i = 1; i < gridSize_.x; i++ ) | ||
498 | { | ||
499 | for( j = 1; j < gridSize_.y; j++ ) | ||
500 | { | ||
501 | ccVertex3F v = [self originalVertex:ccg(i,j)]; | ||
502 | v.x = (v.x + (sinf(time*(CGFloat)M_PI*waves*2 + v.x * .01f) * amplitude * amplitudeRate)); | ||
503 | v.y = (v.y + (sinf(time*(CGFloat)M_PI*waves*2 + v.y * .01f) * amplitude * amplitudeRate)); | ||
504 | [self setVertex:ccg(i,j) vertex:v]; | ||
505 | } | ||
506 | } | ||
507 | } | ||
508 | |||
509 | -(id) copyWithZone: (NSZone*) zone | ||
510 | { | ||
511 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithWaves:waves amplitude:amplitude grid:gridSize_ duration:duration_]; | ||
512 | return copy; | ||
513 | } | ||
514 | |||
515 | @end | ||
516 | |||
517 | //////////////////////////////////////////////////////////// | ||
518 | |||
519 | #pragma mark - | ||
520 | #pragma mark Waves | ||
521 | |||
522 | @implementation CCWaves | ||
523 | |||
524 | @synthesize amplitude; | ||
525 | @synthesize amplitudeRate; | ||
526 | |||
527 | +(id)actionWithWaves:(int)wav amplitude:(float)amp horizontal:(BOOL)h vertical:(BOOL)v grid:(ccGridSize)gridSize duration:(ccTime)d | ||
528 | { | ||
529 | return [[[self alloc] initWithWaves:wav amplitude:amp horizontal:h vertical:v grid:gridSize duration:d] autorelease]; | ||
530 | } | ||
531 | |||
532 | -(id)initWithWaves:(int)wav amplitude:(float)amp horizontal:(BOOL)h vertical:(BOOL)v grid:(ccGridSize)gSize duration:(ccTime)d | ||
533 | { | ||
534 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
535 | { | ||
536 | waves = wav; | ||
537 | amplitude = amp; | ||
538 | amplitudeRate = 1.0f; | ||
539 | horizontal = h; | ||
540 | vertical = v; | ||
541 | } | ||
542 | |||
543 | return self; | ||
544 | } | ||
545 | |||
546 | -(void)update:(ccTime)time | ||
547 | { | ||
548 | int i, j; | ||
549 | |||
550 | for( i = 0; i < (gridSize_.x+1); i++ ) | ||
551 | { | ||
552 | for( j = 0; j < (gridSize_.y+1); j++ ) | ||
553 | { | ||
554 | ccVertex3F v = [self originalVertex:ccg(i,j)]; | ||
555 | |||
556 | if ( vertical ) | ||
557 | v.x = (v.x + (sinf(time*(CGFloat)M_PI*waves*2 + v.y * .01f) * amplitude * amplitudeRate)); | ||
558 | |||
559 | if ( horizontal ) | ||
560 | v.y = (v.y + (sinf(time*(CGFloat)M_PI*waves*2 + v.x * .01f) * amplitude * amplitudeRate)); | ||
561 | |||
562 | [self setVertex:ccg(i,j) vertex:v]; | ||
563 | } | ||
564 | } | ||
565 | } | ||
566 | |||
567 | -(id) copyWithZone: (NSZone*) zone | ||
568 | { | ||
569 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithWaves:waves amplitude:amplitude horizontal:horizontal vertical:vertical grid:gridSize_ duration:duration_]; | ||
570 | return copy; | ||
571 | } | ||
572 | |||
573 | @end | ||
574 | |||
575 | //////////////////////////////////////////////////////////// | ||
576 | |||
577 | #pragma mark - | ||
578 | #pragma mark Twirl | ||
579 | |||
580 | @implementation CCTwirl | ||
581 | |||
582 | @synthesize amplitude = amplitude_; | ||
583 | @synthesize amplitudeRate = amplitudeRate_; | ||
584 | |||
585 | +(id)actionWithPosition:(CGPoint)pos twirls:(int)t amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d | ||
586 | { | ||
587 | return [[[self alloc] initWithPosition:pos twirls:t amplitude:amp grid:gridSize duration:d] autorelease]; | ||
588 | } | ||
589 | |||
590 | -(id)initWithPosition:(CGPoint)pos twirls:(int)t amplitude:(float)amp grid:(ccGridSize)gSize duration:(ccTime)d | ||
591 | { | ||
592 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
593 | { | ||
594 | self.position = pos; | ||
595 | twirls_ = t; | ||
596 | amplitude_ = amp; | ||
597 | amplitudeRate_ = 1.0f; | ||
598 | } | ||
599 | |||
600 | return self; | ||
601 | } | ||
602 | |||
603 | -(void) setPosition:(CGPoint)pos | ||
604 | { | ||
605 | position_ = pos; | ||
606 | positionInPixels_.x = pos.x * CC_CONTENT_SCALE_FACTOR(); | ||
607 | positionInPixels_.y = pos.y * CC_CONTENT_SCALE_FACTOR(); | ||
608 | } | ||
609 | |||
610 | -(CGPoint) position | ||
611 | { | ||
612 | return position_; | ||
613 | } | ||
614 | |||
615 | -(void)update:(ccTime)time | ||
616 | { | ||
617 | int i, j; | ||
618 | CGPoint c = positionInPixels_; | ||
619 | |||
620 | for( i = 0; i < (gridSize_.x+1); i++ ) | ||
621 | { | ||
622 | for( j = 0; j < (gridSize_.y+1); j++ ) | ||
623 | { | ||
624 | ccVertex3F v = [self originalVertex:ccg(i,j)]; | ||
625 | |||
626 | CGPoint avg = ccp(i-(gridSize_.x/2.0f), j-(gridSize_.y/2.0f)); | ||
627 | CGFloat r = ccpLength( avg ); | ||
628 | |||
629 | CGFloat amp = 0.1f * amplitude_ * amplitudeRate_; | ||
630 | CGFloat a = r * cosf( (CGFloat)M_PI/2.0f + time * (CGFloat)M_PI * twirls_ * 2 ) * amp; | ||
631 | |||
632 | float cosA = cosf(a); | ||
633 | float sinA = sinf(a); | ||
634 | |||
635 | CGPoint d = { | ||
636 | sinA * (v.y-c.y) + cosA * (v.x-c.x), | ||
637 | cosA * (v.y-c.y) - sinA * (v.x-c.x) | ||
638 | }; | ||
639 | |||
640 | v.x = c.x + d.x; | ||
641 | v.y = c.y + d.y; | ||
642 | |||
643 | [self setVertex:ccg(i,j) vertex:v]; | ||
644 | } | ||
645 | } | ||
646 | } | ||
647 | |||
648 | -(id) copyWithZone: (NSZone*) zone | ||
649 | { | ||
650 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithPosition:position_ | ||
651 | twirls:twirls_ | ||
652 | amplitude:amplitude_ | ||
653 | grid:gridSize_ | ||
654 | duration:duration_]; | ||
655 | return copy; | ||
656 | } | ||
657 | |||
658 | |||
659 | @end | ||
diff --git a/libs/cocos2d/CCActionInstant.h b/libs/cocos2d/CCActionInstant.h new file mode 100755 index 0000000..5a1bc2d --- /dev/null +++ b/libs/cocos2d/CCActionInstant.h | |||
@@ -0,0 +1,205 @@ | |||
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 | #import "CCAction.h" | ||
29 | |||
30 | /** Instant actions are immediate actions. They don't have a duration like | ||
31 | the CCIntervalAction actions. | ||
32 | */ | ||
33 | @interface CCActionInstant : CCFiniteTimeAction <NSCopying> | ||
34 | { | ||
35 | } | ||
36 | @end | ||
37 | |||
38 | /** Show the node | ||
39 | */ | ||
40 | @interface CCShow : CCActionInstant | ||
41 | { | ||
42 | } | ||
43 | @end | ||
44 | |||
45 | /** Hide the node | ||
46 | */ | ||
47 | @interface CCHide : CCActionInstant | ||
48 | { | ||
49 | } | ||
50 | @end | ||
51 | |||
52 | /** Toggles the visibility of a node | ||
53 | */ | ||
54 | @interface CCToggleVisibility : CCActionInstant | ||
55 | { | ||
56 | } | ||
57 | @end | ||
58 | |||
59 | /** Flips the sprite horizontally | ||
60 | @since v0.99.0 | ||
61 | */ | ||
62 | @interface CCFlipX : CCActionInstant | ||
63 | { | ||
64 | BOOL flipX; | ||
65 | } | ||
66 | +(id) actionWithFlipX:(BOOL)x; | ||
67 | -(id) initWithFlipX:(BOOL)x; | ||
68 | @end | ||
69 | |||
70 | /** Flips the sprite vertically | ||
71 | @since v0.99.0 | ||
72 | */ | ||
73 | @interface CCFlipY : CCActionInstant | ||
74 | { | ||
75 | BOOL flipY; | ||
76 | } | ||
77 | +(id) actionWithFlipY:(BOOL)y; | ||
78 | -(id) initWithFlipY:(BOOL)y; | ||
79 | @end | ||
80 | |||
81 | /** Places the node in a certain position | ||
82 | */ | ||
83 | @interface CCPlace : CCActionInstant <NSCopying> | ||
84 | { | ||
85 | CGPoint position; | ||
86 | } | ||
87 | /** creates a Place action with a position */ | ||
88 | +(id) actionWithPosition: (CGPoint) pos; | ||
89 | /** Initializes a Place action with a position */ | ||
90 | -(id) initWithPosition: (CGPoint) pos; | ||
91 | @end | ||
92 | |||
93 | /** Calls a 'callback' | ||
94 | */ | ||
95 | @interface CCCallFunc : CCActionInstant <NSCopying> | ||
96 | { | ||
97 | id targetCallback_; | ||
98 | SEL selector_; | ||
99 | } | ||
100 | |||
101 | /** Target that will be called */ | ||
102 | @property (nonatomic, readwrite, retain) id targetCallback; | ||
103 | |||
104 | /** creates the action with the callback */ | ||
105 | +(id) actionWithTarget: (id) t selector:(SEL) s; | ||
106 | /** initializes the action with the callback */ | ||
107 | -(id) initWithTarget: (id) t selector:(SEL) s; | ||
108 | /** exeuctes the callback */ | ||
109 | -(void) execute; | ||
110 | @end | ||
111 | |||
112 | /** Calls a 'callback' with the node as the first argument. | ||
113 | N means Node | ||
114 | */ | ||
115 | @interface CCCallFuncN : CCCallFunc | ||
116 | { | ||
117 | } | ||
118 | @end | ||
119 | |||
120 | typedef void (*CC_CALLBACK_ND)(id, SEL, id, void *); | ||
121 | /** Calls a 'callback' with the node as the first argument and the 2nd argument is data. | ||
122 | * ND means: Node and Data. Data is void *, so it could be anything. | ||
123 | */ | ||
124 | @interface CCCallFuncND : CCCallFuncN | ||
125 | { | ||
126 | void *data_; | ||
127 | CC_CALLBACK_ND callbackMethod_; | ||
128 | } | ||
129 | |||
130 | /** Invocation object that has the target#selector and the parameters */ | ||
131 | @property (nonatomic,readwrite) CC_CALLBACK_ND callbackMethod; | ||
132 | |||
133 | /** creates the action with the callback and the data to pass as an argument */ | ||
134 | +(id) actionWithTarget: (id) t selector:(SEL) s data:(void*)d; | ||
135 | /** initializes the action with the callback and the data to pass as an argument */ | ||
136 | -(id) initWithTarget:(id) t selector:(SEL) s data:(void*) d; | ||
137 | @end | ||
138 | |||
139 | /** Calls a 'callback' with an object as the first argument. | ||
140 | O means Object. | ||
141 | @since v0.99.5 | ||
142 | */ | ||
143 | @interface CCCallFuncO : CCCallFunc | ||
144 | { | ||
145 | id object_; | ||
146 | } | ||
147 | /** object to be passed as argument */ | ||
148 | @property (nonatomic, readwrite, retain) id object; | ||
149 | |||
150 | /** creates the action with the callback and the object to pass as an argument */ | ||
151 | +(id) actionWithTarget: (id) t selector:(SEL) s object:(id)object; | ||
152 | /** initializes the action with the callback and the object to pass as an argument */ | ||
153 | -(id) initWithTarget:(id) t selector:(SEL) s object:(id)object; | ||
154 | |||
155 | @end | ||
156 | |||
157 | #pragma mark Blocks Support | ||
158 | |||
159 | #if NS_BLOCKS_AVAILABLE | ||
160 | |||
161 | /** Executes a callback using a block. | ||
162 | */ | ||
163 | @interface CCCallBlock : CCActionInstant<NSCopying> | ||
164 | { | ||
165 | void (^block_)(); | ||
166 | } | ||
167 | |||
168 | /** creates the action with the specified block, to be used as a callback. | ||
169 | The block will be "copied". | ||
170 | */ | ||
171 | +(id) actionWithBlock:(void(^)())block; | ||
172 | |||
173 | /** initialized the action with the specified block, to be used as a callback. | ||
174 | The block will be "copied". | ||
175 | */ | ||
176 | -(id) initWithBlock:(void(^)())block; | ||
177 | |||
178 | /** executes the callback */ | ||
179 | -(void) execute; | ||
180 | @end | ||
181 | |||
182 | @class CCNode; | ||
183 | |||
184 | /** Executes a callback using a block with a single CCNode parameter. | ||
185 | */ | ||
186 | @interface CCCallBlockN : CCActionInstant<NSCopying> | ||
187 | { | ||
188 | void (^block_)(CCNode *); | ||
189 | } | ||
190 | |||
191 | /** creates the action with the specified block, to be used as a callback. | ||
192 | The block will be "copied". | ||
193 | */ | ||
194 | +(id) actionWithBlock:(void(^)(CCNode *node))block; | ||
195 | |||
196 | /** initialized the action with the specified block, to be used as a callback. | ||
197 | The block will be "copied". | ||
198 | */ | ||
199 | -(id) initWithBlock:(void(^)(CCNode *node))block; | ||
200 | |||
201 | /** executes the callback */ | ||
202 | -(void) execute; | ||
203 | @end | ||
204 | |||
205 | #endif | ||
diff --git a/libs/cocos2d/CCActionInstant.m b/libs/cocos2d/CCActionInstant.m new file mode 100755 index 0000000..e7f6fad --- /dev/null +++ b/libs/cocos2d/CCActionInstant.m | |||
@@ -0,0 +1,477 @@ | |||
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 | #import "CCBlockSupport.h" | ||
29 | #import "CCActionInstant.h" | ||
30 | #import "CCNode.h" | ||
31 | #import "CCSprite.h" | ||
32 | |||
33 | |||
34 | // | ||
35 | // InstantAction | ||
36 | // | ||
37 | #pragma mark CCActionInstant | ||
38 | |||
39 | @implementation CCActionInstant | ||
40 | |||
41 | -(id) init | ||
42 | { | ||
43 | if( (self=[super init]) ) | ||
44 | duration_ = 0; | ||
45 | |||
46 | return self; | ||
47 | } | ||
48 | |||
49 | -(id) copyWithZone: (NSZone*) zone | ||
50 | { | ||
51 | CCActionInstant *copy = [[[self class] allocWithZone: zone] init]; | ||
52 | return copy; | ||
53 | } | ||
54 | |||
55 | - (BOOL) isDone | ||
56 | { | ||
57 | return YES; | ||
58 | } | ||
59 | |||
60 | -(void) step: (ccTime) dt | ||
61 | { | ||
62 | [self update: 1]; | ||
63 | } | ||
64 | |||
65 | -(void) update: (ccTime) t | ||
66 | { | ||
67 | // ignore | ||
68 | } | ||
69 | |||
70 | -(CCFiniteTimeAction*) reverse | ||
71 | { | ||
72 | return [[self copy] autorelease]; | ||
73 | } | ||
74 | @end | ||
75 | |||
76 | // | ||
77 | // Show | ||
78 | // | ||
79 | #pragma mark CCShow | ||
80 | |||
81 | @implementation CCShow | ||
82 | -(void) startWithTarget:(id)aTarget | ||
83 | { | ||
84 | [super startWithTarget:aTarget]; | ||
85 | ((CCNode *)target_).visible = YES; | ||
86 | } | ||
87 | |||
88 | -(CCFiniteTimeAction*) reverse | ||
89 | { | ||
90 | return [CCHide action]; | ||
91 | } | ||
92 | @end | ||
93 | |||
94 | // | ||
95 | // Hide | ||
96 | // | ||
97 | #pragma mark CCHide | ||
98 | |||
99 | @implementation CCHide | ||
100 | -(void) startWithTarget:(id)aTarget | ||
101 | { | ||
102 | [super startWithTarget:aTarget]; | ||
103 | ((CCNode *)target_).visible = NO; | ||
104 | } | ||
105 | |||
106 | -(CCFiniteTimeAction*) reverse | ||
107 | { | ||
108 | return [CCShow action]; | ||
109 | } | ||
110 | @end | ||
111 | |||
112 | // | ||
113 | // ToggleVisibility | ||
114 | // | ||
115 | #pragma mark CCToggleVisibility | ||
116 | |||
117 | @implementation CCToggleVisibility | ||
118 | -(void) startWithTarget:(id)aTarget | ||
119 | { | ||
120 | [super startWithTarget:aTarget]; | ||
121 | ((CCNode *)target_).visible = !((CCNode *)target_).visible; | ||
122 | } | ||
123 | @end | ||
124 | |||
125 | // | ||
126 | // FlipX | ||
127 | // | ||
128 | #pragma mark CCFlipX | ||
129 | |||
130 | @implementation CCFlipX | ||
131 | +(id) actionWithFlipX:(BOOL)x | ||
132 | { | ||
133 | return [[[self alloc] initWithFlipX:x] autorelease]; | ||
134 | } | ||
135 | |||
136 | -(id) initWithFlipX:(BOOL)x | ||
137 | { | ||
138 | if(( self=[super init])) | ||
139 | flipX = x; | ||
140 | |||
141 | return self; | ||
142 | } | ||
143 | |||
144 | -(void) startWithTarget:(id)aTarget | ||
145 | { | ||
146 | [super startWithTarget:aTarget]; | ||
147 | [(CCSprite*)aTarget setFlipX:flipX]; | ||
148 | } | ||
149 | |||
150 | -(CCFiniteTimeAction*) reverse | ||
151 | { | ||
152 | return [CCFlipX actionWithFlipX:!flipX]; | ||
153 | } | ||
154 | |||
155 | -(id) copyWithZone: (NSZone*) zone | ||
156 | { | ||
157 | CCActionInstant *copy = [[[self class] allocWithZone: zone] initWithFlipX:flipX]; | ||
158 | return copy; | ||
159 | } | ||
160 | @end | ||
161 | |||
162 | // | ||
163 | // FlipY | ||
164 | // | ||
165 | #pragma mark CCFlipY | ||
166 | |||
167 | @implementation CCFlipY | ||
168 | +(id) actionWithFlipY:(BOOL)y | ||
169 | { | ||
170 | return [[[self alloc] initWithFlipY:y] autorelease]; | ||
171 | } | ||
172 | |||
173 | -(id) initWithFlipY:(BOOL)y | ||
174 | { | ||
175 | if(( self=[super init])) | ||
176 | flipY = y; | ||
177 | |||
178 | return self; | ||
179 | } | ||
180 | |||
181 | -(void) startWithTarget:(id)aTarget | ||
182 | { | ||
183 | [super startWithTarget:aTarget]; | ||
184 | [(CCSprite*)aTarget setFlipY:flipY]; | ||
185 | } | ||
186 | |||
187 | -(CCFiniteTimeAction*) reverse | ||
188 | { | ||
189 | return [CCFlipY actionWithFlipY:!flipY]; | ||
190 | } | ||
191 | |||
192 | -(id) copyWithZone: (NSZone*) zone | ||
193 | { | ||
194 | CCActionInstant *copy = [[[self class] allocWithZone: zone] initWithFlipY:flipY]; | ||
195 | return copy; | ||
196 | } | ||
197 | @end | ||
198 | |||
199 | |||
200 | // | ||
201 | // Place | ||
202 | // | ||
203 | #pragma mark CCPlace | ||
204 | |||
205 | @implementation CCPlace | ||
206 | +(id) actionWithPosition: (CGPoint) pos | ||
207 | { | ||
208 | return [[[self alloc]initWithPosition:pos]autorelease]; | ||
209 | } | ||
210 | |||
211 | -(id) initWithPosition: (CGPoint) pos | ||
212 | { | ||
213 | if( (self=[super init]) ) | ||
214 | position = pos; | ||
215 | |||
216 | return self; | ||
217 | } | ||
218 | |||
219 | -(id) copyWithZone: (NSZone*) zone | ||
220 | { | ||
221 | CCActionInstant *copy = [[[self class] allocWithZone: zone] initWithPosition: position]; | ||
222 | return copy; | ||
223 | } | ||
224 | |||
225 | -(void) startWithTarget:(id)aTarget | ||
226 | { | ||
227 | [super startWithTarget:aTarget]; | ||
228 | ((CCNode *)target_).position = position; | ||
229 | } | ||
230 | |||
231 | @end | ||
232 | |||
233 | // | ||
234 | // CallFunc | ||
235 | // | ||
236 | #pragma mark CCCallFunc | ||
237 | |||
238 | @implementation CCCallFunc | ||
239 | |||
240 | @synthesize targetCallback = targetCallback_; | ||
241 | |||
242 | +(id) actionWithTarget: (id) t selector:(SEL) s | ||
243 | { | ||
244 | return [[[self alloc] initWithTarget: t selector: s] autorelease]; | ||
245 | } | ||
246 | |||
247 | -(id) initWithTarget: (id) t selector:(SEL) s | ||
248 | { | ||
249 | if( (self=[super init]) ) { | ||
250 | self.targetCallback = t; | ||
251 | selector_ = s; | ||
252 | } | ||
253 | return self; | ||
254 | } | ||
255 | |||
256 | -(NSString*) description | ||
257 | { | ||
258 | return [NSString stringWithFormat:@"<%@ = %08X | Tag = %i | target = %@ | selector = %@>", | ||
259 | [self class], | ||
260 | self, | ||
261 | tag_, | ||
262 | [targetCallback_ class], | ||
263 | NSStringFromSelector(selector_) | ||
264 | ]; | ||
265 | } | ||
266 | |||
267 | -(void) dealloc | ||
268 | { | ||
269 | [targetCallback_ release]; | ||
270 | [super dealloc]; | ||
271 | } | ||
272 | |||
273 | -(id) copyWithZone: (NSZone*) zone | ||
274 | { | ||
275 | CCActionInstant *copy = [[[self class] allocWithZone: zone] initWithTarget:targetCallback_ selector:selector_]; | ||
276 | return copy; | ||
277 | } | ||
278 | |||
279 | -(void) startWithTarget:(id)aTarget | ||
280 | { | ||
281 | [super startWithTarget:aTarget]; | ||
282 | [self execute]; | ||
283 | } | ||
284 | |||
285 | -(void) execute | ||
286 | { | ||
287 | [targetCallback_ performSelector:selector_]; | ||
288 | } | ||
289 | @end | ||
290 | |||
291 | // | ||
292 | // CallFuncN | ||
293 | // | ||
294 | #pragma mark CCCallFuncN | ||
295 | |||
296 | @implementation CCCallFuncN | ||
297 | |||
298 | -(void) execute | ||
299 | { | ||
300 | [targetCallback_ performSelector:selector_ withObject:target_]; | ||
301 | } | ||
302 | @end | ||
303 | |||
304 | // | ||
305 | // CallFuncND | ||
306 | // | ||
307 | #pragma mark CCCallFuncND | ||
308 | |||
309 | @implementation CCCallFuncND | ||
310 | |||
311 | @synthesize callbackMethod = callbackMethod_; | ||
312 | |||
313 | +(id) actionWithTarget:(id)t selector:(SEL)s data:(void*)d | ||
314 | { | ||
315 | return [[[self alloc] initWithTarget:t selector:s data:d] autorelease]; | ||
316 | } | ||
317 | |||
318 | -(id) initWithTarget:(id)t selector:(SEL)s data:(void*)d | ||
319 | { | ||
320 | if( (self=[super initWithTarget:t selector:s]) ) { | ||
321 | data_ = d; | ||
322 | |||
323 | #if COCOS2D_DEBUG | ||
324 | NSMethodSignature * sig = [t methodSignatureForSelector:s]; // added | ||
325 | NSAssert(sig !=0 , @"Signature not found for selector - does it have the following form? -(void)name:(id)sender data:(void*)data"); | ||
326 | #endif | ||
327 | callbackMethod_ = (CC_CALLBACK_ND) [t methodForSelector:s]; | ||
328 | } | ||
329 | return self; | ||
330 | } | ||
331 | |||
332 | -(id) copyWithZone: (NSZone*) zone | ||
333 | { | ||
334 | CCActionInstant *copy = [[[self class] allocWithZone: zone] initWithTarget:targetCallback_ selector:selector_ data:data_]; | ||
335 | return copy; | ||
336 | } | ||
337 | |||
338 | -(void) dealloc | ||
339 | { | ||
340 | // nothing to dealloc really. Everything is dealloc on super (CCCallFuncN) | ||
341 | [super dealloc]; | ||
342 | } | ||
343 | |||
344 | -(void) execute | ||
345 | { | ||
346 | callbackMethod_(targetCallback_,selector_,target_, data_); | ||
347 | } | ||
348 | @end | ||
349 | |||
350 | @implementation CCCallFuncO | ||
351 | @synthesize object = object_; | ||
352 | |||
353 | +(id) actionWithTarget: (id) t selector:(SEL) s object:(id)object | ||
354 | { | ||
355 | return [[[self alloc] initWithTarget:t selector:s object:object] autorelease]; | ||
356 | } | ||
357 | |||
358 | -(id) initWithTarget:(id) t selector:(SEL) s object:(id)object | ||
359 | { | ||
360 | if( (self=[super initWithTarget:t selector:s] ) ) | ||
361 | self.object = object; | ||
362 | |||
363 | return self; | ||
364 | } | ||
365 | |||
366 | - (void) dealloc | ||
367 | { | ||
368 | [object_ release]; | ||
369 | [super dealloc]; | ||
370 | } | ||
371 | |||
372 | -(id) copyWithZone: (NSZone*) zone | ||
373 | { | ||
374 | CCActionInstant *copy = [[[self class] allocWithZone: zone] initWithTarget:targetCallback_ selector:selector_ object:object_]; | ||
375 | return copy; | ||
376 | } | ||
377 | |||
378 | |||
379 | -(void) execute | ||
380 | { | ||
381 | [targetCallback_ performSelector:selector_ withObject:object_]; | ||
382 | } | ||
383 | |||
384 | @end | ||
385 | |||
386 | |||
387 | #pragma mark - | ||
388 | #pragma mark Blocks | ||
389 | |||
390 | #if NS_BLOCKS_AVAILABLE | ||
391 | |||
392 | #pragma mark CCCallBlock | ||
393 | |||
394 | @implementation CCCallBlock | ||
395 | |||
396 | +(id) actionWithBlock:(void(^)())block | ||
397 | { | ||
398 | return [[[self alloc] initWithBlock:block] autorelease]; | ||
399 | } | ||
400 | |||
401 | -(id) initWithBlock:(void(^)())block | ||
402 | { | ||
403 | if ((self = [super init])) | ||
404 | block_ = [block copy]; | ||
405 | |||
406 | return self; | ||
407 | } | ||
408 | |||
409 | -(id) copyWithZone: (NSZone*) zone | ||
410 | { | ||
411 | CCActionInstant *copy = [[[self class] allocWithZone: zone] initWithBlock:block_]; | ||
412 | return copy; | ||
413 | } | ||
414 | |||
415 | -(void) startWithTarget:(id)aTarget | ||
416 | { | ||
417 | [super startWithTarget:aTarget]; | ||
418 | [self execute]; | ||
419 | } | ||
420 | |||
421 | -(void) execute | ||
422 | { | ||
423 | block_(); | ||
424 | } | ||
425 | |||
426 | -(void) dealloc | ||
427 | { | ||
428 | [block_ release]; | ||
429 | [super dealloc]; | ||
430 | } | ||
431 | |||
432 | @end | ||
433 | |||
434 | #pragma mark CCCallBlockN | ||
435 | |||
436 | @implementation CCCallBlockN | ||
437 | |||
438 | +(id) actionWithBlock:(void(^)(CCNode *node))block | ||
439 | { | ||
440 | return [[[self alloc] initWithBlock:block] autorelease]; | ||
441 | } | ||
442 | |||
443 | -(id) initWithBlock:(void(^)(CCNode *node))block | ||
444 | { | ||
445 | if ((self = [super init])) | ||
446 | block_ = [block copy]; | ||
447 | |||
448 | return self; | ||
449 | } | ||
450 | |||
451 | -(id) copyWithZone: (NSZone*) zone | ||
452 | { | ||
453 | CCActionInstant *copy = [[[self class] allocWithZone: zone] initWithBlock:block_]; | ||
454 | return copy; | ||
455 | } | ||
456 | |||
457 | -(void) startWithTarget:(id)aTarget | ||
458 | { | ||
459 | [super startWithTarget:aTarget]; | ||
460 | [self execute]; | ||
461 | } | ||
462 | |||
463 | -(void) execute | ||
464 | { | ||
465 | block_(target_); | ||
466 | } | ||
467 | |||
468 | -(void) dealloc | ||
469 | { | ||
470 | [block_ release]; | ||
471 | [super dealloc]; | ||
472 | } | ||
473 | |||
474 | @end | ||
475 | |||
476 | |||
477 | #endif // NS_BLOCKS_AVAILABLE | ||
diff --git a/libs/cocos2d/CCActionInterval.h b/libs/cocos2d/CCActionInterval.h new file mode 100755 index 0000000..c667963 --- /dev/null +++ b/libs/cocos2d/CCActionInterval.h | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2011 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 | #import "CCNode.h" | ||
29 | #import "CCAction.h" | ||
30 | #import "CCProtocols.h" | ||
31 | |||
32 | #include <sys/time.h> | ||
33 | |||
34 | /** An interval action is an action that takes place within a certain period of time. | ||
35 | It has an start time, and a finish time. The finish time is the parameter | ||
36 | duration plus the start time. | ||
37 | |||
38 | These CCActionInterval actions have some interesting properties, like: | ||
39 | - They can run normally (default) | ||
40 | - They can run reversed with the reverse method | ||
41 | - They can run with the time altered with the Accelerate, AccelDeccel and Speed actions. | ||
42 | |||
43 | For example, you can simulate a Ping Pong effect running the action normally and | ||
44 | then running it again in Reverse mode. | ||
45 | |||
46 | Example: | ||
47 | |||
48 | CCAction * pingPongAction = [CCSequence actions: action, [action reverse], nil]; | ||
49 | */ | ||
50 | @interface CCActionInterval: CCFiniteTimeAction <NSCopying> | ||
51 | { | ||
52 | ccTime elapsed_; | ||
53 | BOOL firstTick_; | ||
54 | } | ||
55 | |||
56 | /** how many seconds had elapsed since the actions started to run. */ | ||
57 | @property (nonatomic,readonly) ccTime elapsed; | ||
58 | |||
59 | /** creates the action */ | ||
60 | +(id) actionWithDuration: (ccTime) d; | ||
61 | /** initializes the action */ | ||
62 | -(id) initWithDuration: (ccTime) d; | ||
63 | /** returns YES if the action has finished */ | ||
64 | -(BOOL) isDone; | ||
65 | /** returns a reversed action */ | ||
66 | - (CCActionInterval*) reverse; | ||
67 | @end | ||
68 | |||
69 | /** Runs actions sequentially, one after another | ||
70 | */ | ||
71 | @interface CCSequence : CCActionInterval <NSCopying> | ||
72 | { | ||
73 | CCFiniteTimeAction *actions_[2]; | ||
74 | ccTime split_; | ||
75 | int last_; | ||
76 | } | ||
77 | /** helper contructor to create an array of sequenceable actions */ | ||
78 | +(id) actions: (CCFiniteTimeAction*) action1, ... NS_REQUIRES_NIL_TERMINATION; | ||
79 | /** helper contructor to create an array of sequenceable actions given an array */ | ||
80 | +(id) actionsWithArray: (NSArray*) actions; | ||
81 | /** creates the action */ | ||
82 | +(id) actionOne:(CCFiniteTimeAction*)actionOne two:(CCFiniteTimeAction*)actionTwo; | ||
83 | /** initializes the action */ | ||
84 | -(id) initOne:(CCFiniteTimeAction*)actionOne two:(CCFiniteTimeAction*)actionTwo; | ||
85 | @end | ||
86 | |||
87 | |||
88 | /** Repeats an action a number of times. | ||
89 | * To repeat an action forever use the CCRepeatForever action. | ||
90 | */ | ||
91 | @interface CCRepeat : CCActionInterval <NSCopying> | ||
92 | { | ||
93 | NSUInteger times_; | ||
94 | NSUInteger total_; | ||
95 | CCFiniteTimeAction *innerAction_; | ||
96 | } | ||
97 | |||
98 | /** Inner action */ | ||
99 | @property (nonatomic,readwrite,retain) CCFiniteTimeAction *innerAction; | ||
100 | |||
101 | /** creates a CCRepeat action. Times is an unsigned integer between 1 and MAX_UINT */ | ||
102 | +(id) actionWithAction:(CCFiniteTimeAction*)action times: (NSUInteger)times; | ||
103 | /** initializes a CCRepeat action. Times is an unsigned integer between 1 and MAX_UINT */ | ||
104 | -(id) initWithAction:(CCFiniteTimeAction*)action times: (NSUInteger)times; | ||
105 | @end | ||
106 | |||
107 | /** Spawn a new action immediately | ||
108 | */ | ||
109 | @interface CCSpawn : CCActionInterval <NSCopying> | ||
110 | { | ||
111 | CCFiniteTimeAction *one_; | ||
112 | CCFiniteTimeAction *two_; | ||
113 | } | ||
114 | /** helper constructor to create an array of spawned actions */ | ||
115 | +(id) actions: (CCFiniteTimeAction*) action1, ... NS_REQUIRES_NIL_TERMINATION; | ||
116 | /** helper contructor to create an array of spawned actions given an array */ | ||
117 | +(id) actionsWithArray: (NSArray*) actions; | ||
118 | /** creates the Spawn action */ | ||
119 | +(id) actionOne: (CCFiniteTimeAction*) one two:(CCFiniteTimeAction*) two; | ||
120 | /** initializes the Spawn action with the 2 actions to spawn */ | ||
121 | -(id) initOne: (CCFiniteTimeAction*) one two:(CCFiniteTimeAction*) two; | ||
122 | @end | ||
123 | |||
124 | /** Rotates a CCNode object to a certain angle by modifying it's | ||
125 | rotation attribute. | ||
126 | The direction will be decided by the shortest angle. | ||
127 | */ | ||
128 | @interface CCRotateTo : CCActionInterval <NSCopying> | ||
129 | { | ||
130 | float dstAngle_; | ||
131 | float startAngle_; | ||
132 | float diffAngle_; | ||
133 | } | ||
134 | /** creates the action */ | ||
135 | +(id) actionWithDuration:(ccTime)duration angle:(float)angle; | ||
136 | /** initializes the action */ | ||
137 | -(id) initWithDuration:(ccTime)duration angle:(float)angle; | ||
138 | @end | ||
139 | |||
140 | /** Rotates a CCNode object clockwise a number of degrees by modiying it's rotation attribute. | ||
141 | */ | ||
142 | @interface CCRotateBy : CCActionInterval <NSCopying> | ||
143 | { | ||
144 | float angle_; | ||
145 | float startAngle_; | ||
146 | } | ||
147 | /** creates the action */ | ||
148 | +(id) actionWithDuration:(ccTime)duration angle:(float)deltaAngle; | ||
149 | /** initializes the action */ | ||
150 | -(id) initWithDuration:(ccTime)duration angle:(float)deltaAngle; | ||
151 | @end | ||
152 | |||
153 | /** Moves a CCNode object to the position x,y. x and y are absolute coordinates by modifying it's position attribute. | ||
154 | */ | ||
155 | @interface CCMoveTo : CCActionInterval <NSCopying> | ||
156 | { | ||
157 | CGPoint endPosition_; | ||
158 | CGPoint startPosition_; | ||
159 | CGPoint delta_; | ||
160 | } | ||
161 | /** creates the action */ | ||
162 | +(id) actionWithDuration:(ccTime)duration position:(CGPoint)position; | ||
163 | /** initializes the action */ | ||
164 | -(id) initWithDuration:(ccTime)duration position:(CGPoint)position; | ||
165 | @end | ||
166 | |||
167 | /** Moves a CCNode object x,y pixels by modifying it's position attribute. | ||
168 | x and y are relative to the position of the object. | ||
169 | Duration is is seconds. | ||
170 | */ | ||
171 | @interface CCMoveBy : CCMoveTo <NSCopying> | ||
172 | { | ||
173 | } | ||
174 | /** creates the action */ | ||
175 | +(id) actionWithDuration: (ccTime)duration position:(CGPoint)deltaPosition; | ||
176 | /** initializes the action */ | ||
177 | -(id) initWithDuration: (ccTime)duration position:(CGPoint)deltaPosition; | ||
178 | @end | ||
179 | |||
180 | /** Skews a CCNode object to given angles by modifying it's skewX and skewY attributes | ||
181 | @since v1.0 | ||
182 | */ | ||
183 | @interface CCSkewTo : CCActionInterval <NSCopying> | ||
184 | { | ||
185 | float skewX_; | ||
186 | float skewY_; | ||
187 | float startSkewX_; | ||
188 | float startSkewY_; | ||
189 | float endSkewX_; | ||
190 | float endSkewY_; | ||
191 | float deltaX_; | ||
192 | float deltaY_; | ||
193 | } | ||
194 | /** creates the action */ | ||
195 | +(id) actionWithDuration:(ccTime)t skewX:(float)sx skewY:(float)sy; | ||
196 | /** initializes the action */ | ||
197 | -(id) initWithDuration:(ccTime)t skewX:(float)sx skewY:(float)sy; | ||
198 | @end | ||
199 | |||
200 | /** Skews a CCNode object by skewX and skewY degrees | ||
201 | @since v1.0 | ||
202 | */ | ||
203 | @interface CCSkewBy : CCSkewTo <NSCopying> | ||
204 | { | ||
205 | } | ||
206 | @end | ||
207 | |||
208 | /** Moves a CCNode object simulating a parabolic jump movement by modifying it's position attribute. | ||
209 | */ | ||
210 | @interface CCJumpBy : CCActionInterval <NSCopying> | ||
211 | { | ||
212 | CGPoint startPosition_; | ||
213 | CGPoint delta_; | ||
214 | ccTime height_; | ||
215 | NSUInteger jumps_; | ||
216 | } | ||
217 | /** creates the action */ | ||
218 | +(id) actionWithDuration: (ccTime)duration position:(CGPoint)position height:(ccTime)height jumps:(NSUInteger)jumps; | ||
219 | /** initializes the action */ | ||
220 | -(id) initWithDuration: (ccTime)duration position:(CGPoint)position height:(ccTime)height jumps:(NSUInteger)jumps; | ||
221 | @end | ||
222 | |||
223 | /** Moves a CCNode object to a parabolic position simulating a jump movement by modifying it's position attribute. | ||
224 | */ | ||
225 | @interface CCJumpTo : CCJumpBy <NSCopying> | ||
226 | { | ||
227 | } | ||
228 | @end | ||
229 | |||
230 | /** bezier configuration structure | ||
231 | */ | ||
232 | typedef struct _ccBezierConfig { | ||
233 | //! end position of the bezier | ||
234 | CGPoint endPosition; | ||
235 | //! Bezier control point 1 | ||
236 | CGPoint controlPoint_1; | ||
237 | //! Bezier control point 2 | ||
238 | CGPoint controlPoint_2; | ||
239 | } ccBezierConfig; | ||
240 | |||
241 | /** An action that moves the target with a cubic Bezier curve by a certain distance. | ||
242 | */ | ||
243 | @interface CCBezierBy : CCActionInterval <NSCopying> | ||
244 | { | ||
245 | ccBezierConfig config_; | ||
246 | CGPoint startPosition_; | ||
247 | } | ||
248 | |||
249 | /** creates the action with a duration and a bezier configuration */ | ||
250 | +(id) actionWithDuration: (ccTime) t bezier:(ccBezierConfig) c; | ||
251 | |||
252 | /** initializes the action with a duration and a bezier configuration */ | ||
253 | -(id) initWithDuration: (ccTime) t bezier:(ccBezierConfig) c; | ||
254 | @end | ||
255 | |||
256 | /** An action that moves the target with a cubic Bezier curve to a destination point. | ||
257 | @since v0.8.2 | ||
258 | */ | ||
259 | @interface CCBezierTo : CCBezierBy | ||
260 | { | ||
261 | } | ||
262 | @end | ||
263 | |||
264 | /** Scales a CCNode object to a zoom factor by modifying it's scale attribute. | ||
265 | @warning This action doesn't support "reverse" | ||
266 | */ | ||
267 | @interface CCScaleTo : CCActionInterval <NSCopying> | ||
268 | { | ||
269 | float scaleX_; | ||
270 | float scaleY_; | ||
271 | float startScaleX_; | ||
272 | float startScaleY_; | ||
273 | float endScaleX_; | ||
274 | float endScaleY_; | ||
275 | float deltaX_; | ||
276 | float deltaY_; | ||
277 | } | ||
278 | /** creates the action with the same scale factor for X and Y */ | ||
279 | +(id) actionWithDuration: (ccTime)duration scale:(float) s; | ||
280 | /** initializes the action with the same scale factor for X and Y */ | ||
281 | -(id) initWithDuration: (ccTime)duration scale:(float) s; | ||
282 | /** creates the action with and X factor and a Y factor */ | ||
283 | +(id) actionWithDuration: (ccTime)duration scaleX:(float) sx scaleY:(float)sy; | ||
284 | /** initializes the action with and X factor and a Y factor */ | ||
285 | -(id) initWithDuration: (ccTime)duration scaleX:(float) sx scaleY:(float)sy; | ||
286 | @end | ||
287 | |||
288 | /** Scales a CCNode object a zoom factor by modifying it's scale attribute. | ||
289 | */ | ||
290 | @interface CCScaleBy : CCScaleTo <NSCopying> | ||
291 | { | ||
292 | } | ||
293 | @end | ||
294 | |||
295 | /** Blinks a CCNode object by modifying it's visible attribute | ||
296 | */ | ||
297 | @interface CCBlink : CCActionInterval <NSCopying> | ||
298 | { | ||
299 | NSUInteger times_; | ||
300 | } | ||
301 | /** creates the action */ | ||
302 | +(id) actionWithDuration: (ccTime)duration blinks:(NSUInteger)blinks; | ||
303 | /** initilizes the action */ | ||
304 | -(id) initWithDuration: (ccTime)duration blinks:(NSUInteger)blinks; | ||
305 | @end | ||
306 | |||
307 | /** Fades In an object that implements the CCRGBAProtocol protocol. It modifies the opacity from 0 to 255. | ||
308 | The "reverse" of this action is FadeOut | ||
309 | */ | ||
310 | @interface CCFadeIn : CCActionInterval <NSCopying> | ||
311 | { | ||
312 | } | ||
313 | @end | ||
314 | |||
315 | /** Fades Out an object that implements the CCRGBAProtocol protocol. It modifies the opacity from 255 to 0. | ||
316 | The "reverse" of this action is FadeIn | ||
317 | */ | ||
318 | @interface CCFadeOut : CCActionInterval <NSCopying> | ||
319 | { | ||
320 | } | ||
321 | @end | ||
322 | |||
323 | /** Fades an object that implements the CCRGBAProtocol protocol. It modifies the opacity from the current value to a custom one. | ||
324 | @warning This action doesn't support "reverse" | ||
325 | */ | ||
326 | @interface CCFadeTo : CCActionInterval <NSCopying> | ||
327 | { | ||
328 | GLubyte toOpacity_; | ||
329 | GLubyte fromOpacity_; | ||
330 | } | ||
331 | /** creates an action with duration and opactiy */ | ||
332 | +(id) actionWithDuration:(ccTime)duration opacity:(GLubyte)opactiy; | ||
333 | /** initializes the action with duration and opacity */ | ||
334 | -(id) initWithDuration:(ccTime)duration opacity:(GLubyte)opacity; | ||
335 | @end | ||
336 | |||
337 | /** Tints a CCNode that implements the CCNodeRGB protocol from current tint to a custom one. | ||
338 | @warning This action doesn't support "reverse" | ||
339 | @since v0.7.2 | ||
340 | */ | ||
341 | @interface CCTintTo : CCActionInterval <NSCopying> | ||
342 | { | ||
343 | ccColor3B to_; | ||
344 | ccColor3B from_; | ||
345 | } | ||
346 | /** creates an action with duration and color */ | ||
347 | +(id) actionWithDuration:(ccTime)duration red:(GLubyte)red green:(GLubyte)green blue:(GLubyte)blue; | ||
348 | /** initializes the action with duration and color */ | ||
349 | -(id) initWithDuration:(ccTime)duration red:(GLubyte)red green:(GLubyte)green blue:(GLubyte)blue; | ||
350 | @end | ||
351 | |||
352 | /** Tints a CCNode that implements the CCNodeRGB protocol from current tint to a custom one. | ||
353 | @since v0.7.2 | ||
354 | */ | ||
355 | @interface CCTintBy : CCActionInterval <NSCopying> | ||
356 | { | ||
357 | GLshort deltaR_, deltaG_, deltaB_; | ||
358 | GLshort fromR_, fromG_, fromB_; | ||
359 | } | ||
360 | /** creates an action with duration and color */ | ||
361 | +(id) actionWithDuration:(ccTime)duration red:(GLshort)deltaRed green:(GLshort)deltaGreen blue:(GLshort)deltaBlue; | ||
362 | /** initializes the action with duration and color */ | ||
363 | -(id) initWithDuration:(ccTime)duration red:(GLshort)deltaRed green:(GLshort)deltaGreen blue:(GLshort)deltaBlue; | ||
364 | @end | ||
365 | |||
366 | /** Delays the action a certain amount of seconds | ||
367 | */ | ||
368 | @interface CCDelayTime : CCActionInterval <NSCopying> | ||
369 | { | ||
370 | } | ||
371 | @end | ||
372 | |||
373 | /** Executes an action in reverse order, from time=duration to time=0 | ||
374 | |||
375 | @warning Use this action carefully. This action is not | ||
376 | sequenceable. Use it as the default "reversed" method | ||
377 | of your own actions, but using it outside the "reversed" | ||
378 | scope is not recommended. | ||
379 | */ | ||
380 | @interface CCReverseTime : CCActionInterval <NSCopying> | ||
381 | { | ||
382 | CCFiniteTimeAction * other_; | ||
383 | } | ||
384 | /** creates the action */ | ||
385 | +(id) actionWithAction: (CCFiniteTimeAction*) action; | ||
386 | /** initializes the action */ | ||
387 | -(id) initWithAction: (CCFiniteTimeAction*) action; | ||
388 | @end | ||
389 | |||
390 | |||
391 | @class CCAnimation; | ||
392 | @class CCTexture2D; | ||
393 | /** Animates a sprite given the name of an Animation */ | ||
394 | @interface CCAnimate : CCActionInterval <NSCopying> | ||
395 | { | ||
396 | CCAnimation *animation_; | ||
397 | id origFrame_; | ||
398 | BOOL restoreOriginalFrame_; | ||
399 | } | ||
400 | /** animation used for the animage */ | ||
401 | @property (readwrite,nonatomic,retain) CCAnimation * animation; | ||
402 | |||
403 | /** creates the action with an Animation and will restore the original frame when the animation is over */ | ||
404 | +(id) actionWithAnimation:(CCAnimation*) a; | ||
405 | /** initializes the action with an Animation and will restore the original frame when the animtion is over */ | ||
406 | -(id) initWithAnimation:(CCAnimation*) a; | ||
407 | /** creates the action with an Animation */ | ||
408 | +(id) actionWithAnimation:(CCAnimation*) a restoreOriginalFrame:(BOOL)b; | ||
409 | /** initializes the action with an Animation */ | ||
410 | -(id) initWithAnimation:(CCAnimation*) a restoreOriginalFrame:(BOOL)b; | ||
411 | /** creates an action with a duration, animation and depending of the restoreOriginalFrame, it will restore the original frame or not. | ||
412 | The 'delay' parameter of the animation will be overrided by the duration parameter. | ||
413 | @since v0.99.0 | ||
414 | */ | ||
415 | +(id) actionWithDuration:(ccTime)duration animation:(CCAnimation*)animation restoreOriginalFrame:(BOOL)b; | ||
416 | /** initializes an action with a duration, animation and depending of the restoreOriginalFrame, it will restore the original frame or not. | ||
417 | The 'delay' parameter of the animation will be overrided by the duration parameter. | ||
418 | @since v0.99.0 | ||
419 | */ | ||
420 | -(id) initWithDuration:(ccTime)duration animation:(CCAnimation*)animation restoreOriginalFrame:(BOOL)b; | ||
421 | @end | ||
diff --git a/libs/cocos2d/CCActionInterval.m b/libs/cocos2d/CCActionInterval.m new file mode 100755 index 0000000..17bef40 --- /dev/null +++ b/libs/cocos2d/CCActionInterval.m | |||
@@ -0,0 +1,1355 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2011 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 | |||
29 | #import "CCActionInterval.h" | ||
30 | #import "CCSprite.h" | ||
31 | #import "CCSpriteFrame.h" | ||
32 | #import "CCAnimation.h" | ||
33 | #import "CCNode.h" | ||
34 | #import "Support/CGPointExtension.h" | ||
35 | |||
36 | // | ||
37 | // IntervalAction | ||
38 | // | ||
39 | #pragma mark - | ||
40 | #pragma mark IntervalAction | ||
41 | @implementation CCActionInterval | ||
42 | |||
43 | @synthesize elapsed = elapsed_; | ||
44 | |||
45 | -(id) init | ||
46 | { | ||
47 | NSAssert(NO, @"IntervalActionInit: Init not supported. Use InitWithDuration"); | ||
48 | [self release]; | ||
49 | return nil; | ||
50 | } | ||
51 | |||
52 | +(id) actionWithDuration: (ccTime) d | ||
53 | { | ||
54 | return [[[self alloc] initWithDuration:d ] autorelease]; | ||
55 | } | ||
56 | |||
57 | -(id) initWithDuration: (ccTime) d | ||
58 | { | ||
59 | if( (self=[super init]) ) { | ||
60 | duration_ = d; | ||
61 | |||
62 | // prevent division by 0 | ||
63 | // This comparison could be in step:, but it might decrease the performance | ||
64 | // by 3% in heavy based action games. | ||
65 | if( duration_ == 0 ) | ||
66 | duration_ = FLT_EPSILON; | ||
67 | elapsed_ = 0; | ||
68 | firstTick_ = YES; | ||
69 | } | ||
70 | return self; | ||
71 | } | ||
72 | |||
73 | -(id) copyWithZone: (NSZone*) zone | ||
74 | { | ||
75 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] ]; | ||
76 | return copy; | ||
77 | } | ||
78 | |||
79 | - (BOOL) isDone | ||
80 | { | ||
81 | return (elapsed_ >= duration_); | ||
82 | } | ||
83 | |||
84 | -(void) step: (ccTime) dt | ||
85 | { | ||
86 | if( firstTick_ ) { | ||
87 | firstTick_ = NO; | ||
88 | elapsed_ = 0; | ||
89 | } else | ||
90 | elapsed_ += dt; | ||
91 | |||
92 | [self update: MIN(1, elapsed_/duration_)]; | ||
93 | } | ||
94 | |||
95 | -(void) startWithTarget:(id)aTarget | ||
96 | { | ||
97 | [super startWithTarget:aTarget]; | ||
98 | elapsed_ = 0.0f; | ||
99 | firstTick_ = YES; | ||
100 | } | ||
101 | |||
102 | - (CCActionInterval*) reverse | ||
103 | { | ||
104 | NSAssert(NO, @"CCIntervalAction: reverse not implemented."); | ||
105 | return nil; | ||
106 | } | ||
107 | @end | ||
108 | |||
109 | // | ||
110 | // Sequence | ||
111 | // | ||
112 | #pragma mark - | ||
113 | #pragma mark Sequence | ||
114 | @implementation CCSequence | ||
115 | +(id) actions: (CCFiniteTimeAction*) action1, ... | ||
116 | { | ||
117 | va_list params; | ||
118 | va_start(params,action1); | ||
119 | |||
120 | CCFiniteTimeAction *now; | ||
121 | CCFiniteTimeAction *prev = action1; | ||
122 | |||
123 | while( action1 ) { | ||
124 | now = va_arg(params,CCFiniteTimeAction*); | ||
125 | if ( now ) | ||
126 | prev = [self actionOne: prev two: now]; | ||
127 | else | ||
128 | break; | ||
129 | } | ||
130 | va_end(params); | ||
131 | return prev; | ||
132 | } | ||
133 | |||
134 | +(id) actionsWithArray: (NSArray*) actions | ||
135 | { | ||
136 | CCFiniteTimeAction *prev = [actions objectAtIndex:0]; | ||
137 | |||
138 | for (NSUInteger i = 1; i < [actions count]; i++) | ||
139 | prev = [self actionOne:prev two:[actions objectAtIndex:i]]; | ||
140 | |||
141 | return prev; | ||
142 | } | ||
143 | |||
144 | +(id) actionOne: (CCFiniteTimeAction*) one two: (CCFiniteTimeAction*) two | ||
145 | { | ||
146 | return [[[self alloc] initOne:one two:two ] autorelease]; | ||
147 | } | ||
148 | |||
149 | -(id) initOne: (CCFiniteTimeAction*) one two: (CCFiniteTimeAction*) two | ||
150 | { | ||
151 | NSAssert( one!=nil && two!=nil, @"Sequence: arguments must be non-nil"); | ||
152 | NSAssert( one!=actions_[0] && one!=actions_[1], @"Sequence: re-init using the same parameters is not supported"); | ||
153 | NSAssert( two!=actions_[1] && two!=actions_[0], @"Sequence: re-init using the same parameters is not supported"); | ||
154 | |||
155 | ccTime d = [one duration] + [two duration]; | ||
156 | |||
157 | if( (self=[super initWithDuration: d]) ) { | ||
158 | |||
159 | // XXX: Supports re-init without leaking. Fails if one==one_ || two==two_ | ||
160 | [actions_[0] release]; | ||
161 | [actions_[1] release]; | ||
162 | |||
163 | actions_[0] = [one retain]; | ||
164 | actions_[1] = [two retain]; | ||
165 | } | ||
166 | |||
167 | return self; | ||
168 | } | ||
169 | |||
170 | -(id) copyWithZone: (NSZone*) zone | ||
171 | { | ||
172 | CCAction *copy = [[[self class] allocWithZone:zone] initOne:[[actions_[0] copy] autorelease] two:[[actions_[1] copy] autorelease] ]; | ||
173 | return copy; | ||
174 | } | ||
175 | |||
176 | -(void) dealloc | ||
177 | { | ||
178 | [actions_[0] release]; | ||
179 | [actions_[1] release]; | ||
180 | [super dealloc]; | ||
181 | } | ||
182 | |||
183 | -(void) startWithTarget:(id)aTarget | ||
184 | { | ||
185 | [super startWithTarget:aTarget]; | ||
186 | split_ = [actions_[0] duration] / duration_; | ||
187 | last_ = -1; | ||
188 | } | ||
189 | |||
190 | -(void) stop | ||
191 | { | ||
192 | [actions_[0] stop]; | ||
193 | [actions_[1] stop]; | ||
194 | [super stop]; | ||
195 | } | ||
196 | |||
197 | -(void) update: (ccTime) t | ||
198 | { | ||
199 | int found = 0; | ||
200 | ccTime new_t = 0.0f; | ||
201 | |||
202 | if( t >= split_ ) { | ||
203 | found = 1; | ||
204 | if ( split_ == 1 ) | ||
205 | new_t = 1; | ||
206 | else | ||
207 | new_t = (t-split_) / (1 - split_ ); | ||
208 | } else { | ||
209 | found = 0; | ||
210 | if( split_ != 0 ) | ||
211 | new_t = t / split_; | ||
212 | else | ||
213 | new_t = 1; | ||
214 | } | ||
215 | |||
216 | if (last_ == -1 && found==1) { | ||
217 | [actions_[0] startWithTarget:target_]; | ||
218 | [actions_[0] update:1.0f]; | ||
219 | [actions_[0] stop]; | ||
220 | } | ||
221 | |||
222 | if (last_ != found ) { | ||
223 | if( last_ != -1 ) { | ||
224 | [actions_[last_] update: 1.0f]; | ||
225 | [actions_[last_] stop]; | ||
226 | } | ||
227 | [actions_[found] startWithTarget:target_]; | ||
228 | } | ||
229 | [actions_[found] update: new_t]; | ||
230 | last_ = found; | ||
231 | } | ||
232 | |||
233 | - (CCActionInterval *) reverse | ||
234 | { | ||
235 | return [[self class] actionOne: [actions_[1] reverse] two: [actions_[0] reverse ] ]; | ||
236 | } | ||
237 | @end | ||
238 | |||
239 | // | ||
240 | // Repeat | ||
241 | // | ||
242 | #pragma mark - | ||
243 | #pragma mark CCRepeat | ||
244 | @implementation CCRepeat | ||
245 | @synthesize innerAction=innerAction_; | ||
246 | |||
247 | +(id) actionWithAction:(CCFiniteTimeAction*)action times:(NSUInteger)times | ||
248 | { | ||
249 | return [[[self alloc] initWithAction:action times:times] autorelease]; | ||
250 | } | ||
251 | |||
252 | -(id) initWithAction:(CCFiniteTimeAction*)action times:(NSUInteger)times | ||
253 | { | ||
254 | ccTime d = [action duration] * times; | ||
255 | |||
256 | if( (self=[super initWithDuration: d ]) ) { | ||
257 | times_ = times; | ||
258 | self.innerAction = action; | ||
259 | |||
260 | total_ = 0; | ||
261 | } | ||
262 | return self; | ||
263 | } | ||
264 | |||
265 | -(id) copyWithZone: (NSZone*) zone | ||
266 | { | ||
267 | CCAction *copy = [[[self class] allocWithZone:zone] initWithAction:[[innerAction_ copy] autorelease] times:times_]; | ||
268 | return copy; | ||
269 | } | ||
270 | |||
271 | -(void) dealloc | ||
272 | { | ||
273 | [innerAction_ release]; | ||
274 | [super dealloc]; | ||
275 | } | ||
276 | |||
277 | -(void) startWithTarget:(id)aTarget | ||
278 | { | ||
279 | total_ = 0; | ||
280 | [super startWithTarget:aTarget]; | ||
281 | [innerAction_ startWithTarget:aTarget]; | ||
282 | } | ||
283 | |||
284 | -(void) stop | ||
285 | { | ||
286 | [innerAction_ stop]; | ||
287 | [super stop]; | ||
288 | } | ||
289 | |||
290 | |||
291 | // issue #80. Instead of hooking step:, hook update: since it can be called by any | ||
292 | // container action like Repeat, Sequence, AccelDeccel, etc.. | ||
293 | -(void) update:(ccTime) dt | ||
294 | { | ||
295 | ccTime t = dt * times_; | ||
296 | if( t > total_+1 ) { | ||
297 | [innerAction_ update:1.0f]; | ||
298 | total_++; | ||
299 | [innerAction_ stop]; | ||
300 | [innerAction_ startWithTarget:target_]; | ||
301 | |||
302 | // repeat is over ? | ||
303 | if( total_== times_ ) | ||
304 | // so, set it in the original position | ||
305 | [innerAction_ update:0]; | ||
306 | else { | ||
307 | // no ? start next repeat with the right update | ||
308 | // to prevent jerk (issue #390) | ||
309 | [innerAction_ update: t-total_]; | ||
310 | } | ||
311 | |||
312 | } else { | ||
313 | |||
314 | float r = fmodf(t, 1.0f); | ||
315 | |||
316 | // fix last repeat position | ||
317 | // else it could be 0. | ||
318 | if( dt== 1.0f) { | ||
319 | r = 1.0f; | ||
320 | total_++; // this is the added line | ||
321 | } | ||
322 | [innerAction_ update: MIN(r,1)]; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | -(BOOL) isDone | ||
327 | { | ||
328 | return ( total_ == times_ ); | ||
329 | } | ||
330 | |||
331 | - (CCActionInterval *) reverse | ||
332 | { | ||
333 | return [[self class] actionWithAction:[innerAction_ reverse] times:times_]; | ||
334 | } | ||
335 | @end | ||
336 | |||
337 | // | ||
338 | // Spawn | ||
339 | // | ||
340 | #pragma mark - | ||
341 | #pragma mark Spawn | ||
342 | |||
343 | @implementation CCSpawn | ||
344 | +(id) actions: (CCFiniteTimeAction*) action1, ... | ||
345 | { | ||
346 | va_list params; | ||
347 | va_start(params,action1); | ||
348 | |||
349 | CCFiniteTimeAction *now; | ||
350 | CCFiniteTimeAction *prev = action1; | ||
351 | |||
352 | while( action1 ) { | ||
353 | now = va_arg(params,CCFiniteTimeAction*); | ||
354 | if ( now ) | ||
355 | prev = [self actionOne: prev two: now]; | ||
356 | else | ||
357 | break; | ||
358 | } | ||
359 | va_end(params); | ||
360 | return prev; | ||
361 | } | ||
362 | |||
363 | +(id) actionsWithArray: (NSArray*) actions | ||
364 | { | ||
365 | CCFiniteTimeAction *prev = [actions objectAtIndex:0]; | ||
366 | |||
367 | for (NSUInteger i = 1; i < [actions count]; i++) | ||
368 | prev = [self actionOne:prev two:[actions objectAtIndex:i]]; | ||
369 | |||
370 | return prev; | ||
371 | } | ||
372 | |||
373 | +(id) actionOne: (CCFiniteTimeAction*) one two: (CCFiniteTimeAction*) two | ||
374 | { | ||
375 | return [[[self alloc] initOne:one two:two ] autorelease]; | ||
376 | } | ||
377 | |||
378 | -(id) initOne: (CCFiniteTimeAction*) one two: (CCFiniteTimeAction*) two | ||
379 | { | ||
380 | NSAssert( one!=nil && two!=nil, @"Spawn: arguments must be non-nil"); | ||
381 | NSAssert( one!=one_ && one!=two_, @"Spawn: reinit using same parameters is not supported"); | ||
382 | NSAssert( two!=two_ && two!=one_, @"Spawn: reinit using same parameters is not supported"); | ||
383 | |||
384 | ccTime d1 = [one duration]; | ||
385 | ccTime d2 = [two duration]; | ||
386 | |||
387 | if( (self=[super initWithDuration: MAX(d1,d2)] ) ) { | ||
388 | |||
389 | // XXX: Supports re-init without leaking. Fails if one==one_ || two==two_ | ||
390 | [one_ release]; | ||
391 | [two_ release]; | ||
392 | |||
393 | one_ = one; | ||
394 | two_ = two; | ||
395 | |||
396 | if( d1 > d2 ) | ||
397 | two_ = [CCSequence actionOne:two two:[CCDelayTime actionWithDuration: (d1-d2)] ]; | ||
398 | else if( d1 < d2) | ||
399 | one_ = [CCSequence actionOne:one two: [CCDelayTime actionWithDuration: (d2-d1)] ]; | ||
400 | |||
401 | [one_ retain]; | ||
402 | [two_ retain]; | ||
403 | } | ||
404 | return self; | ||
405 | } | ||
406 | |||
407 | -(id) copyWithZone: (NSZone*) zone | ||
408 | { | ||
409 | CCAction *copy = [[[self class] allocWithZone: zone] initOne: [[one_ copy] autorelease] two: [[two_ copy] autorelease] ]; | ||
410 | return copy; | ||
411 | } | ||
412 | |||
413 | -(void) dealloc | ||
414 | { | ||
415 | [one_ release]; | ||
416 | [two_ release]; | ||
417 | [super dealloc]; | ||
418 | } | ||
419 | |||
420 | -(void) startWithTarget:(id)aTarget | ||
421 | { | ||
422 | [super startWithTarget:aTarget]; | ||
423 | [one_ startWithTarget:target_]; | ||
424 | [two_ startWithTarget:target_]; | ||
425 | } | ||
426 | |||
427 | -(void) stop | ||
428 | { | ||
429 | [one_ stop]; | ||
430 | [two_ stop]; | ||
431 | [super stop]; | ||
432 | } | ||
433 | |||
434 | -(void) update: (ccTime) t | ||
435 | { | ||
436 | [one_ update:t]; | ||
437 | [two_ update:t]; | ||
438 | } | ||
439 | |||
440 | - (CCActionInterval *) reverse | ||
441 | { | ||
442 | return [[self class] actionOne: [one_ reverse] two: [two_ reverse ] ]; | ||
443 | } | ||
444 | @end | ||
445 | |||
446 | // | ||
447 | // RotateTo | ||
448 | // | ||
449 | #pragma mark - | ||
450 | #pragma mark RotateTo | ||
451 | |||
452 | @implementation CCRotateTo | ||
453 | +(id) actionWithDuration: (ccTime) t angle:(float) a | ||
454 | { | ||
455 | return [[[self alloc] initWithDuration:t angle:a ] autorelease]; | ||
456 | } | ||
457 | |||
458 | -(id) initWithDuration: (ccTime) t angle:(float) a | ||
459 | { | ||
460 | if( (self=[super initWithDuration: t]) ) | ||
461 | dstAngle_ = a; | ||
462 | |||
463 | return self; | ||
464 | } | ||
465 | |||
466 | -(id) copyWithZone: (NSZone*) zone | ||
467 | { | ||
468 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration:[self duration] angle:dstAngle_]; | ||
469 | return copy; | ||
470 | } | ||
471 | |||
472 | -(void) startWithTarget:(CCNode *)aTarget | ||
473 | { | ||
474 | [super startWithTarget:aTarget]; | ||
475 | |||
476 | startAngle_ = [target_ rotation]; | ||
477 | if (startAngle_ > 0) | ||
478 | startAngle_ = fmodf(startAngle_, 360.0f); | ||
479 | else | ||
480 | startAngle_ = fmodf(startAngle_, -360.0f); | ||
481 | |||
482 | diffAngle_ =dstAngle_ - startAngle_; | ||
483 | if (diffAngle_ > 180) | ||
484 | diffAngle_ -= 360; | ||
485 | if (diffAngle_ < -180) | ||
486 | diffAngle_ += 360; | ||
487 | } | ||
488 | -(void) update: (ccTime) t | ||
489 | { | ||
490 | [target_ setRotation: startAngle_ + diffAngle_ * t]; | ||
491 | } | ||
492 | @end | ||
493 | |||
494 | |||
495 | // | ||
496 | // RotateBy | ||
497 | // | ||
498 | #pragma mark - | ||
499 | #pragma mark RotateBy | ||
500 | |||
501 | @implementation CCRotateBy | ||
502 | +(id) actionWithDuration: (ccTime) t angle:(float) a | ||
503 | { | ||
504 | return [[[self alloc] initWithDuration:t angle:a ] autorelease]; | ||
505 | } | ||
506 | |||
507 | -(id) initWithDuration: (ccTime) t angle:(float) a | ||
508 | { | ||
509 | if( (self=[super initWithDuration: t]) ) | ||
510 | angle_ = a; | ||
511 | |||
512 | return self; | ||
513 | } | ||
514 | |||
515 | -(id) copyWithZone: (NSZone*) zone | ||
516 | { | ||
517 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] angle: angle_]; | ||
518 | return copy; | ||
519 | } | ||
520 | |||
521 | -(void) startWithTarget:(id)aTarget | ||
522 | { | ||
523 | [super startWithTarget:aTarget]; | ||
524 | startAngle_ = [target_ rotation]; | ||
525 | } | ||
526 | |||
527 | -(void) update: (ccTime) t | ||
528 | { | ||
529 | // XXX: shall I add % 360 | ||
530 | [target_ setRotation: (startAngle_ +angle_ * t )]; | ||
531 | } | ||
532 | |||
533 | -(CCActionInterval*) reverse | ||
534 | { | ||
535 | return [[self class] actionWithDuration:duration_ angle:-angle_]; | ||
536 | } | ||
537 | |||
538 | @end | ||
539 | |||
540 | // | ||
541 | // MoveTo | ||
542 | // | ||
543 | #pragma mark - | ||
544 | #pragma mark MoveTo | ||
545 | |||
546 | @implementation CCMoveTo | ||
547 | +(id) actionWithDuration: (ccTime) t position: (CGPoint) p | ||
548 | { | ||
549 | return [[[self alloc] initWithDuration:t position:p ] autorelease]; | ||
550 | } | ||
551 | |||
552 | -(id) initWithDuration: (ccTime) t position: (CGPoint) p | ||
553 | { | ||
554 | if( (self=[super initWithDuration: t]) ) | ||
555 | endPosition_ = p; | ||
556 | |||
557 | return self; | ||
558 | } | ||
559 | |||
560 | -(id) copyWithZone: (NSZone*) zone | ||
561 | { | ||
562 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] position: endPosition_]; | ||
563 | return copy; | ||
564 | } | ||
565 | |||
566 | -(void) startWithTarget:(CCNode *)aTarget | ||
567 | { | ||
568 | [super startWithTarget:aTarget]; | ||
569 | startPosition_ = [(CCNode*)target_ position]; | ||
570 | delta_ = ccpSub( endPosition_, startPosition_ ); | ||
571 | } | ||
572 | |||
573 | -(void) update: (ccTime) t | ||
574 | { | ||
575 | [target_ setPosition: ccp( (startPosition_.x + delta_.x * t ), (startPosition_.y + delta_.y * t ) )]; | ||
576 | } | ||
577 | @end | ||
578 | |||
579 | // | ||
580 | // MoveBy | ||
581 | // | ||
582 | #pragma mark - | ||
583 | #pragma mark MoveBy | ||
584 | |||
585 | @implementation CCMoveBy | ||
586 | +(id) actionWithDuration: (ccTime) t position: (CGPoint) p | ||
587 | { | ||
588 | return [[[self alloc] initWithDuration:t position:p ] autorelease]; | ||
589 | } | ||
590 | |||
591 | -(id) initWithDuration: (ccTime) t position: (CGPoint) p | ||
592 | { | ||
593 | if( (self=[super initWithDuration: t]) ) | ||
594 | delta_ = p; | ||
595 | |||
596 | return self; | ||
597 | } | ||
598 | |||
599 | -(id) copyWithZone: (NSZone*) zone | ||
600 | { | ||
601 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] position: delta_]; | ||
602 | return copy; | ||
603 | } | ||
604 | |||
605 | -(void) startWithTarget:(CCNode *)aTarget | ||
606 | { | ||
607 | CGPoint dTmp = delta_; | ||
608 | [super startWithTarget:aTarget]; | ||
609 | delta_ = dTmp; | ||
610 | } | ||
611 | |||
612 | -(CCActionInterval*) reverse | ||
613 | { | ||
614 | return [[self class] actionWithDuration:duration_ position:ccp( -delta_.x, -delta_.y)]; | ||
615 | } | ||
616 | @end | ||
617 | |||
618 | |||
619 | // | ||
620 | // SkewTo | ||
621 | // | ||
622 | #pragma mark - | ||
623 | #pragma mark SkewTo | ||
624 | |||
625 | @implementation CCSkewTo | ||
626 | +(id) actionWithDuration:(ccTime)t skewX:(float)sx skewY:(float)sy | ||
627 | { | ||
628 | return [[[self alloc] initWithDuration: t skewX:sx skewY:sy] autorelease]; | ||
629 | } | ||
630 | |||
631 | -(id) initWithDuration:(ccTime)t skewX:(float)sx skewY:(float)sy | ||
632 | { | ||
633 | if( (self=[super initWithDuration:t]) ) { | ||
634 | endSkewX_ = sx; | ||
635 | endSkewY_ = sy; | ||
636 | } | ||
637 | return self; | ||
638 | } | ||
639 | |||
640 | -(id) copyWithZone: (NSZone*) zone | ||
641 | { | ||
642 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration:[self duration] skewX:endSkewX_ skewY:endSkewY_]; | ||
643 | return copy; | ||
644 | } | ||
645 | |||
646 | -(void) startWithTarget:(CCNode *)aTarget | ||
647 | { | ||
648 | [super startWithTarget:aTarget]; | ||
649 | |||
650 | startSkewX_ = [target_ skewX]; | ||
651 | |||
652 | if (startSkewX_ > 0) | ||
653 | startSkewX_ = fmodf(startSkewX_, 180.0f); | ||
654 | else | ||
655 | startSkewX_ = fmodf(startSkewX_, -180.0f); | ||
656 | |||
657 | deltaX_ = endSkewX_ - startSkewX_; | ||
658 | |||
659 | if ( deltaX_ > 180 ) { | ||
660 | deltaX_ -= 360; | ||
661 | } | ||
662 | if ( deltaX_ < -180 ) { | ||
663 | deltaX_ += 360; | ||
664 | } | ||
665 | |||
666 | startSkewY_ = [target_ skewY]; | ||
667 | |||
668 | if (startSkewY_ > 0) | ||
669 | startSkewY_ = fmodf(startSkewY_, 360.0f); | ||
670 | else | ||
671 | startSkewY_ = fmodf(startSkewY_, -360.0f); | ||
672 | |||
673 | deltaY_ = endSkewY_ - startSkewY_; | ||
674 | |||
675 | if ( deltaY_ > 180 ) { | ||
676 | deltaY_ -= 360; | ||
677 | } | ||
678 | if ( deltaY_ < -180 ) { | ||
679 | deltaY_ += 360; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | -(void) update: (ccTime) t | ||
684 | { | ||
685 | [target_ setSkewX: (startSkewX_ + deltaX_ * t ) ]; | ||
686 | [target_ setSkewY: (startSkewY_ + deltaY_ * t ) ]; | ||
687 | } | ||
688 | |||
689 | @end | ||
690 | |||
691 | // | ||
692 | // CCSkewBy | ||
693 | // | ||
694 | @implementation CCSkewBy | ||
695 | |||
696 | -(id) initWithDuration:(ccTime)t skewX:(float)deltaSkewX skewY:(float)deltaSkewY | ||
697 | { | ||
698 | if( (self=[super initWithDuration:t skewX:deltaSkewX skewY:deltaSkewY]) ) { | ||
699 | skewX_ = deltaSkewX; | ||
700 | skewY_ = deltaSkewY; | ||
701 | } | ||
702 | return self; | ||
703 | } | ||
704 | |||
705 | -(void) startWithTarget:(CCNode *)aTarget | ||
706 | { | ||
707 | [super startWithTarget:aTarget]; | ||
708 | deltaX_ = skewX_; | ||
709 | deltaY_ = skewY_; | ||
710 | endSkewX_ = startSkewX_ + deltaX_; | ||
711 | endSkewY_ = startSkewY_ + deltaY_; | ||
712 | } | ||
713 | |||
714 | -(CCActionInterval*) reverse | ||
715 | { | ||
716 | return [[self class] actionWithDuration:duration_ skewX:-skewX_ skewY:-skewY_]; | ||
717 | } | ||
718 | @end | ||
719 | |||
720 | |||
721 | // | ||
722 | // JumpBy | ||
723 | // | ||
724 | #pragma mark - | ||
725 | #pragma mark JumpBy | ||
726 | |||
727 | @implementation CCJumpBy | ||
728 | +(id) actionWithDuration: (ccTime) t position: (CGPoint) pos height: (ccTime) h jumps:(NSUInteger)j | ||
729 | { | ||
730 | return [[[self alloc] initWithDuration: t position: pos height: h jumps:j] autorelease]; | ||
731 | } | ||
732 | |||
733 | -(id) initWithDuration: (ccTime) t position: (CGPoint) pos height: (ccTime) h jumps:(NSUInteger)j | ||
734 | { | ||
735 | if( (self=[super initWithDuration:t]) ) { | ||
736 | delta_ = pos; | ||
737 | height_ = h; | ||
738 | jumps_ = j; | ||
739 | } | ||
740 | return self; | ||
741 | } | ||
742 | |||
743 | -(id) copyWithZone: (NSZone*) zone | ||
744 | { | ||
745 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration:[self duration] position:delta_ height:height_ jumps:jumps_]; | ||
746 | return copy; | ||
747 | } | ||
748 | |||
749 | -(void) startWithTarget:(id)aTarget | ||
750 | { | ||
751 | [super startWithTarget:aTarget]; | ||
752 | startPosition_ = [(CCNode*)target_ position]; | ||
753 | } | ||
754 | |||
755 | -(void) update: (ccTime) t | ||
756 | { | ||
757 | // Sin jump. Less realistic | ||
758 | // ccTime y = height * fabsf( sinf(t * (CGFloat)M_PI * jumps ) ); | ||
759 | // y += delta.y * t; | ||
760 | // ccTime x = delta.x * t; | ||
761 | // [target setPosition: ccp( startPosition.x + x, startPosition.y + y )]; | ||
762 | |||
763 | // parabolic jump (since v0.8.2) | ||
764 | ccTime frac = fmodf( t * jumps_, 1.0f ); | ||
765 | ccTime y = height_ * 4 * frac * (1 - frac); | ||
766 | y += delta_.y * t; | ||
767 | ccTime x = delta_.x * t; | ||
768 | [target_ setPosition: ccp( startPosition_.x + x, startPosition_.y + y )]; | ||
769 | |||
770 | } | ||
771 | |||
772 | -(CCActionInterval*) reverse | ||
773 | { | ||
774 | return [[self class] actionWithDuration:duration_ position: ccp(-delta_.x,-delta_.y) height:height_ jumps:jumps_]; | ||
775 | } | ||
776 | @end | ||
777 | |||
778 | // | ||
779 | // JumpTo | ||
780 | // | ||
781 | #pragma mark - | ||
782 | #pragma mark JumpTo | ||
783 | |||
784 | @implementation CCJumpTo | ||
785 | -(void) startWithTarget:(CCNode *)aTarget | ||
786 | { | ||
787 | [super startWithTarget:aTarget]; | ||
788 | delta_ = ccp( delta_.x - startPosition_.x, delta_.y - startPosition_.y ); | ||
789 | } | ||
790 | @end | ||
791 | |||
792 | |||
793 | #pragma mark - | ||
794 | #pragma mark BezierBy | ||
795 | |||
796 | // Bezier cubic formula: | ||
797 | // ((1 - t) + t)3 = 1 | ||
798 | // Expands to… | ||
799 | // (1 - t)3 + 3t(1-t)2 + 3t2(1 - t) + t3 = 1 | ||
800 | static inline float bezierat( float a, float b, float c, float d, ccTime t ) | ||
801 | { | ||
802 | return (powf(1-t,3) * a + | ||
803 | 3*t*(powf(1-t,2))*b + | ||
804 | 3*powf(t,2)*(1-t)*c + | ||
805 | powf(t,3)*d ); | ||
806 | } | ||
807 | |||
808 | // | ||
809 | // BezierBy | ||
810 | // | ||
811 | @implementation CCBezierBy | ||
812 | +(id) actionWithDuration: (ccTime) t bezier:(ccBezierConfig) c | ||
813 | { | ||
814 | return [[[self alloc] initWithDuration:t bezier:c ] autorelease]; | ||
815 | } | ||
816 | |||
817 | -(id) initWithDuration: (ccTime) t bezier:(ccBezierConfig) c | ||
818 | { | ||
819 | if( (self=[super initWithDuration: t]) ) { | ||
820 | config_ = c; | ||
821 | } | ||
822 | return self; | ||
823 | } | ||
824 | |||
825 | -(id) copyWithZone: (NSZone*) zone | ||
826 | { | ||
827 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration:[self duration] bezier:config_]; | ||
828 | return copy; | ||
829 | } | ||
830 | |||
831 | -(void) startWithTarget:(id)aTarget | ||
832 | { | ||
833 | [super startWithTarget:aTarget]; | ||
834 | startPosition_ = [(CCNode*)target_ position]; | ||
835 | } | ||
836 | |||
837 | -(void) update: (ccTime) t | ||
838 | { | ||
839 | float xa = 0; | ||
840 | float xb = config_.controlPoint_1.x; | ||
841 | float xc = config_.controlPoint_2.x; | ||
842 | float xd = config_.endPosition.x; | ||
843 | |||
844 | float ya = 0; | ||
845 | float yb = config_.controlPoint_1.y; | ||
846 | float yc = config_.controlPoint_2.y; | ||
847 | float yd = config_.endPosition.y; | ||
848 | |||
849 | float x = bezierat(xa, xb, xc, xd, t); | ||
850 | float y = bezierat(ya, yb, yc, yd, t); | ||
851 | [target_ setPosition: ccpAdd( startPosition_, ccp(x,y))]; | ||
852 | } | ||
853 | |||
854 | - (CCActionInterval*) reverse | ||
855 | { | ||
856 | ccBezierConfig r; | ||
857 | |||
858 | r.endPosition = ccpNeg(config_.endPosition); | ||
859 | r.controlPoint_1 = ccpAdd(config_.controlPoint_2, ccpNeg(config_.endPosition)); | ||
860 | r.controlPoint_2 = ccpAdd(config_.controlPoint_1, ccpNeg(config_.endPosition)); | ||
861 | |||
862 | CCBezierBy *action = [[self class] actionWithDuration:[self duration] bezier:r]; | ||
863 | return action; | ||
864 | } | ||
865 | @end | ||
866 | |||
867 | // | ||
868 | // BezierTo | ||
869 | // | ||
870 | #pragma mark - | ||
871 | #pragma mark BezierTo | ||
872 | @implementation CCBezierTo | ||
873 | -(void) startWithTarget:(id)aTarget | ||
874 | { | ||
875 | [super startWithTarget:aTarget]; | ||
876 | config_.controlPoint_1 = ccpSub(config_.controlPoint_1, startPosition_); | ||
877 | config_.controlPoint_2 = ccpSub(config_.controlPoint_2, startPosition_); | ||
878 | config_.endPosition = ccpSub(config_.endPosition, startPosition_); | ||
879 | } | ||
880 | @end | ||
881 | |||
882 | |||
883 | // | ||
884 | // ScaleTo | ||
885 | // | ||
886 | #pragma mark - | ||
887 | #pragma mark ScaleTo | ||
888 | @implementation CCScaleTo | ||
889 | +(id) actionWithDuration: (ccTime) t scale:(float) s | ||
890 | { | ||
891 | return [[[self alloc] initWithDuration: t scale:s] autorelease]; | ||
892 | } | ||
893 | |||
894 | -(id) initWithDuration: (ccTime) t scale:(float) s | ||
895 | { | ||
896 | if( (self=[super initWithDuration: t]) ) { | ||
897 | endScaleX_ = s; | ||
898 | endScaleY_ = s; | ||
899 | } | ||
900 | return self; | ||
901 | } | ||
902 | |||
903 | +(id) actionWithDuration: (ccTime) t scaleX:(float)sx scaleY:(float)sy | ||
904 | { | ||
905 | return [[[self alloc] initWithDuration: t scaleX:sx scaleY:sy] autorelease]; | ||
906 | } | ||
907 | |||
908 | -(id) initWithDuration: (ccTime) t scaleX:(float)sx scaleY:(float)sy | ||
909 | { | ||
910 | if( (self=[super initWithDuration: t]) ) { | ||
911 | endScaleX_ = sx; | ||
912 | endScaleY_ = sy; | ||
913 | } | ||
914 | return self; | ||
915 | } | ||
916 | |||
917 | -(id) copyWithZone: (NSZone*) zone | ||
918 | { | ||
919 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration:[self duration] scaleX:endScaleX_ scaleY:endScaleY_]; | ||
920 | return copy; | ||
921 | } | ||
922 | |||
923 | -(void) startWithTarget:(CCNode *)aTarget | ||
924 | { | ||
925 | [super startWithTarget:aTarget]; | ||
926 | startScaleX_ = [target_ scaleX]; | ||
927 | startScaleY_ = [target_ scaleY]; | ||
928 | deltaX_ = endScaleX_ - startScaleX_; | ||
929 | deltaY_ = endScaleY_ - startScaleY_; | ||
930 | } | ||
931 | |||
932 | -(void) update: (ccTime) t | ||
933 | { | ||
934 | [target_ setScaleX: (startScaleX_ + deltaX_ * t ) ]; | ||
935 | [target_ setScaleY: (startScaleY_ + deltaY_ * t ) ]; | ||
936 | } | ||
937 | @end | ||
938 | |||
939 | // | ||
940 | // ScaleBy | ||
941 | // | ||
942 | #pragma mark - | ||
943 | #pragma mark ScaleBy | ||
944 | @implementation CCScaleBy | ||
945 | -(void) startWithTarget:(CCNode *)aTarget | ||
946 | { | ||
947 | [super startWithTarget:aTarget]; | ||
948 | deltaX_ = startScaleX_ * endScaleX_ - startScaleX_; | ||
949 | deltaY_ = startScaleY_ * endScaleY_ - startScaleY_; | ||
950 | } | ||
951 | |||
952 | -(CCActionInterval*) reverse | ||
953 | { | ||
954 | return [[self class] actionWithDuration:duration_ scaleX:1/endScaleX_ scaleY:1/endScaleY_]; | ||
955 | } | ||
956 | @end | ||
957 | |||
958 | // | ||
959 | // Blink | ||
960 | // | ||
961 | #pragma mark - | ||
962 | #pragma mark Blink | ||
963 | @implementation CCBlink | ||
964 | +(id) actionWithDuration: (ccTime) t blinks: (NSUInteger) b | ||
965 | { | ||
966 | return [[[ self alloc] initWithDuration: t blinks: b] autorelease]; | ||
967 | } | ||
968 | |||
969 | -(id) initWithDuration: (ccTime) t blinks: (NSUInteger) b | ||
970 | { | ||
971 | if( (self=[super initWithDuration: t] ) ) | ||
972 | times_ = b; | ||
973 | |||
974 | return self; | ||
975 | } | ||
976 | |||
977 | -(id) copyWithZone: (NSZone*) zone | ||
978 | { | ||
979 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] blinks: times_]; | ||
980 | return copy; | ||
981 | } | ||
982 | |||
983 | -(void) update: (ccTime) t | ||
984 | { | ||
985 | if( ! [self isDone] ) { | ||
986 | ccTime slice = 1.0f / times_; | ||
987 | ccTime m = fmodf(t, slice); | ||
988 | [target_ setVisible: (m > slice/2) ? YES : NO]; | ||
989 | } | ||
990 | } | ||
991 | |||
992 | -(CCActionInterval*) reverse | ||
993 | { | ||
994 | // return 'self' | ||
995 | return [[self class] actionWithDuration:duration_ blinks: times_]; | ||
996 | } | ||
997 | @end | ||
998 | |||
999 | // | ||
1000 | // FadeIn | ||
1001 | // | ||
1002 | #pragma mark - | ||
1003 | #pragma mark FadeIn | ||
1004 | @implementation CCFadeIn | ||
1005 | -(void) update: (ccTime) t | ||
1006 | { | ||
1007 | [(id<CCRGBAProtocol>) target_ setOpacity: 255 *t]; | ||
1008 | } | ||
1009 | |||
1010 | -(CCActionInterval*) reverse | ||
1011 | { | ||
1012 | return [CCFadeOut actionWithDuration:duration_]; | ||
1013 | } | ||
1014 | @end | ||
1015 | |||
1016 | // | ||
1017 | // FadeOut | ||
1018 | // | ||
1019 | #pragma mark - | ||
1020 | #pragma mark FadeOut | ||
1021 | @implementation CCFadeOut | ||
1022 | -(void) update: (ccTime) t | ||
1023 | { | ||
1024 | [(id<CCRGBAProtocol>) target_ setOpacity: 255 *(1-t)]; | ||
1025 | } | ||
1026 | |||
1027 | -(CCActionInterval*) reverse | ||
1028 | { | ||
1029 | return [CCFadeIn actionWithDuration:duration_]; | ||
1030 | } | ||
1031 | @end | ||
1032 | |||
1033 | // | ||
1034 | // FadeTo | ||
1035 | // | ||
1036 | #pragma mark - | ||
1037 | #pragma mark FadeTo | ||
1038 | @implementation CCFadeTo | ||
1039 | +(id) actionWithDuration: (ccTime) t opacity: (GLubyte) o | ||
1040 | { | ||
1041 | return [[[ self alloc] initWithDuration: t opacity: o] autorelease]; | ||
1042 | } | ||
1043 | |||
1044 | -(id) initWithDuration: (ccTime) t opacity: (GLubyte) o | ||
1045 | { | ||
1046 | if( (self=[super initWithDuration: t] ) ) | ||
1047 | toOpacity_ = o; | ||
1048 | |||
1049 | return self; | ||
1050 | } | ||
1051 | |||
1052 | -(id) copyWithZone: (NSZone*) zone | ||
1053 | { | ||
1054 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration:[self duration] opacity:toOpacity_]; | ||
1055 | return copy; | ||
1056 | } | ||
1057 | |||
1058 | -(void) startWithTarget:(CCNode *)aTarget | ||
1059 | { | ||
1060 | [super startWithTarget:aTarget]; | ||
1061 | fromOpacity_ = [(id<CCRGBAProtocol>)target_ opacity]; | ||
1062 | } | ||
1063 | |||
1064 | -(void) update: (ccTime) t | ||
1065 | { | ||
1066 | [(id<CCRGBAProtocol>)target_ setOpacity:fromOpacity_ + ( toOpacity_ - fromOpacity_ ) * t]; | ||
1067 | } | ||
1068 | @end | ||
1069 | |||
1070 | // | ||
1071 | // TintTo | ||
1072 | // | ||
1073 | #pragma mark - | ||
1074 | #pragma mark TintTo | ||
1075 | @implementation CCTintTo | ||
1076 | +(id) actionWithDuration:(ccTime)t red:(GLubyte)r green:(GLubyte)g blue:(GLubyte)b | ||
1077 | { | ||
1078 | return [[(CCTintTo*)[ self alloc] initWithDuration:t red:r green:g blue:b] autorelease]; | ||
1079 | } | ||
1080 | |||
1081 | -(id) initWithDuration: (ccTime) t red:(GLubyte)r green:(GLubyte)g blue:(GLubyte)b | ||
1082 | { | ||
1083 | if( (self=[super initWithDuration:t] ) ) | ||
1084 | to_ = ccc3(r,g,b); | ||
1085 | |||
1086 | return self; | ||
1087 | } | ||
1088 | |||
1089 | -(id) copyWithZone: (NSZone*) zone | ||
1090 | { | ||
1091 | CCAction *copy = [(CCTintTo*)[[self class] allocWithZone: zone] initWithDuration:[self duration] red:to_.r green:to_.g blue:to_.b]; | ||
1092 | return copy; | ||
1093 | } | ||
1094 | |||
1095 | -(void) startWithTarget:(id)aTarget | ||
1096 | { | ||
1097 | [super startWithTarget:aTarget]; | ||
1098 | |||
1099 | id<CCRGBAProtocol> tn = (id<CCRGBAProtocol>) target_; | ||
1100 | from_ = [tn color]; | ||
1101 | } | ||
1102 | |||
1103 | -(void) update: (ccTime) t | ||
1104 | { | ||
1105 | id<CCRGBAProtocol> tn = (id<CCRGBAProtocol>) target_; | ||
1106 | [tn setColor:ccc3(from_.r + (to_.r - from_.r) * t, from_.g + (to_.g - from_.g) * t, from_.b + (to_.b - from_.b) * t)]; | ||
1107 | } | ||
1108 | @end | ||
1109 | |||
1110 | // | ||
1111 | // TintBy | ||
1112 | // | ||
1113 | #pragma mark - | ||
1114 | #pragma mark TintBy | ||
1115 | @implementation CCTintBy | ||
1116 | +(id) actionWithDuration:(ccTime)t red:(GLshort)r green:(GLshort)g blue:(GLshort)b | ||
1117 | { | ||
1118 | return [[(CCTintBy*)[ self alloc] initWithDuration:t red:r green:g blue:b] autorelease]; | ||
1119 | } | ||
1120 | |||
1121 | -(id) initWithDuration:(ccTime)t red:(GLshort)r green:(GLshort)g blue:(GLshort)b | ||
1122 | { | ||
1123 | if( (self=[super initWithDuration: t] ) ) { | ||
1124 | deltaR_ = r; | ||
1125 | deltaG_ = g; | ||
1126 | deltaB_ = b; | ||
1127 | } | ||
1128 | return self; | ||
1129 | } | ||
1130 | |||
1131 | -(id) copyWithZone: (NSZone*) zone | ||
1132 | { | ||
1133 | return[(CCTintBy*)[[self class] allocWithZone: zone] initWithDuration: [self duration] red:deltaR_ green:deltaG_ blue:deltaB_]; | ||
1134 | } | ||
1135 | |||
1136 | -(void) startWithTarget:(id)aTarget | ||
1137 | { | ||
1138 | [super startWithTarget:aTarget]; | ||
1139 | |||
1140 | id<CCRGBAProtocol> tn = (id<CCRGBAProtocol>) target_; | ||
1141 | ccColor3B color = [tn color]; | ||
1142 | fromR_ = color.r; | ||
1143 | fromG_ = color.g; | ||
1144 | fromB_ = color.b; | ||
1145 | } | ||
1146 | |||
1147 | -(void) update: (ccTime) t | ||
1148 | { | ||
1149 | id<CCRGBAProtocol> tn = (id<CCRGBAProtocol>) target_; | ||
1150 | [tn setColor:ccc3( fromR_ + deltaR_ * t, fromG_ + deltaG_ * t, fromB_ + deltaB_ * t)]; | ||
1151 | } | ||
1152 | |||
1153 | - (CCActionInterval*) reverse | ||
1154 | { | ||
1155 | return [CCTintBy actionWithDuration:duration_ red:-deltaR_ green:-deltaG_ blue:-deltaB_]; | ||
1156 | } | ||
1157 | @end | ||
1158 | |||
1159 | // | ||
1160 | // DelayTime | ||
1161 | // | ||
1162 | #pragma mark - | ||
1163 | #pragma mark DelayTime | ||
1164 | @implementation CCDelayTime | ||
1165 | -(void) update: (ccTime) t | ||
1166 | { | ||
1167 | return; | ||
1168 | } | ||
1169 | |||
1170 | -(id)reverse | ||
1171 | { | ||
1172 | return [[self class] actionWithDuration:duration_]; | ||
1173 | } | ||
1174 | @end | ||
1175 | |||
1176 | // | ||
1177 | // ReverseTime | ||
1178 | // | ||
1179 | #pragma mark - | ||
1180 | #pragma mark ReverseTime | ||
1181 | @implementation CCReverseTime | ||
1182 | +(id) actionWithAction: (CCFiniteTimeAction*) action | ||
1183 | { | ||
1184 | // casting to prevent warnings | ||
1185 | CCReverseTime *a = [super alloc]; | ||
1186 | return [[a initWithAction:action] autorelease]; | ||
1187 | } | ||
1188 | |||
1189 | -(id) initWithAction: (CCFiniteTimeAction*) action | ||
1190 | { | ||
1191 | NSAssert(action != nil, @"CCReverseTime: action should not be nil"); | ||
1192 | NSAssert(action != other_, @"CCReverseTime: re-init doesn't support using the same arguments"); | ||
1193 | |||
1194 | if( (self=[super initWithDuration: [action duration]]) ) { | ||
1195 | // Don't leak if action is reused | ||
1196 | [other_ release]; | ||
1197 | other_ = [action retain]; | ||
1198 | } | ||
1199 | |||
1200 | return self; | ||
1201 | } | ||
1202 | |||
1203 | -(id) copyWithZone: (NSZone*) zone | ||
1204 | { | ||
1205 | return [[[self class] allocWithZone: zone] initWithAction:[[other_ copy] autorelease] ]; | ||
1206 | } | ||
1207 | |||
1208 | -(void) dealloc | ||
1209 | { | ||
1210 | [other_ release]; | ||
1211 | [super dealloc]; | ||
1212 | } | ||
1213 | |||
1214 | -(void) startWithTarget:(id)aTarget | ||
1215 | { | ||
1216 | [super startWithTarget:aTarget]; | ||
1217 | [other_ startWithTarget:target_]; | ||
1218 | } | ||
1219 | |||
1220 | -(void) stop | ||
1221 | { | ||
1222 | [other_ stop]; | ||
1223 | [super stop]; | ||
1224 | } | ||
1225 | |||
1226 | -(void) update:(ccTime)t | ||
1227 | { | ||
1228 | [other_ update:1-t]; | ||
1229 | } | ||
1230 | |||
1231 | -(CCActionInterval*) reverse | ||
1232 | { | ||
1233 | return [[other_ copy] autorelease]; | ||
1234 | } | ||
1235 | @end | ||
1236 | |||
1237 | // | ||
1238 | // Animate | ||
1239 | // | ||
1240 | |||
1241 | #pragma mark - | ||
1242 | #pragma mark Animate | ||
1243 | @implementation CCAnimate | ||
1244 | |||
1245 | @synthesize animation = animation_; | ||
1246 | |||
1247 | +(id) actionWithAnimation: (CCAnimation*)anim | ||
1248 | { | ||
1249 | return [[[self alloc] initWithAnimation:anim restoreOriginalFrame:YES] autorelease]; | ||
1250 | } | ||
1251 | |||
1252 | +(id) actionWithAnimation: (CCAnimation*)anim restoreOriginalFrame:(BOOL)b | ||
1253 | { | ||
1254 | return [[[self alloc] initWithAnimation:anim restoreOriginalFrame:b] autorelease]; | ||
1255 | } | ||
1256 | |||
1257 | +(id) actionWithDuration:(ccTime)duration animation: (CCAnimation*)anim restoreOriginalFrame:(BOOL)b | ||
1258 | { | ||
1259 | return [[[self alloc] initWithDuration:duration animation:anim restoreOriginalFrame:b] autorelease]; | ||
1260 | } | ||
1261 | |||
1262 | -(id) initWithAnimation: (CCAnimation*)anim | ||
1263 | { | ||
1264 | NSAssert( anim!=nil, @"Animate: argument Animation must be non-nil"); | ||
1265 | return [self initWithAnimation:anim restoreOriginalFrame:YES]; | ||
1266 | } | ||
1267 | |||
1268 | -(id) initWithAnimation: (CCAnimation*)anim restoreOriginalFrame:(BOOL) b | ||
1269 | { | ||
1270 | NSAssert( anim!=nil, @"Animate: argument Animation must be non-nil"); | ||
1271 | |||
1272 | if( (self=[super initWithDuration: [[anim frames] count] * [anim delay]]) ) { | ||
1273 | |||
1274 | restoreOriginalFrame_ = b; | ||
1275 | self.animation = anim; | ||
1276 | origFrame_ = nil; | ||
1277 | } | ||
1278 | return self; | ||
1279 | } | ||
1280 | |||
1281 | -(id) initWithDuration:(ccTime)aDuration animation: (CCAnimation*)anim restoreOriginalFrame:(BOOL) b | ||
1282 | { | ||
1283 | NSAssert( anim!=nil, @"Animate: argument Animation must be non-nil"); | ||
1284 | |||
1285 | if( (self=[super initWithDuration:aDuration] ) ) { | ||
1286 | |||
1287 | restoreOriginalFrame_ = b; | ||
1288 | self.animation = anim; | ||
1289 | origFrame_ = nil; | ||
1290 | } | ||
1291 | return self; | ||
1292 | } | ||
1293 | |||
1294 | |||
1295 | -(id) copyWithZone: (NSZone*) zone | ||
1296 | { | ||
1297 | return [[[self class] allocWithZone: zone] initWithDuration:duration_ animation:animation_ restoreOriginalFrame:restoreOriginalFrame_]; | ||
1298 | } | ||
1299 | |||
1300 | -(void) dealloc | ||
1301 | { | ||
1302 | [animation_ release]; | ||
1303 | [origFrame_ release]; | ||
1304 | [super dealloc]; | ||
1305 | } | ||
1306 | |||
1307 | -(void) startWithTarget:(id)aTarget | ||
1308 | { | ||
1309 | [super startWithTarget:aTarget]; | ||
1310 | CCSprite *sprite = target_; | ||
1311 | |||
1312 | [origFrame_ release]; | ||
1313 | |||
1314 | if( restoreOriginalFrame_ ) | ||
1315 | origFrame_ = [[sprite displayedFrame] retain]; | ||
1316 | } | ||
1317 | |||
1318 | -(void) stop | ||
1319 | { | ||
1320 | if( restoreOriginalFrame_ ) { | ||
1321 | CCSprite *sprite = target_; | ||
1322 | [sprite setDisplayFrame:origFrame_]; | ||
1323 | } | ||
1324 | |||
1325 | [super stop]; | ||
1326 | } | ||
1327 | |||
1328 | -(void) update: (ccTime) t | ||
1329 | { | ||
1330 | NSArray *frames = [animation_ frames]; | ||
1331 | NSUInteger numberOfFrames = [frames count]; | ||
1332 | |||
1333 | NSUInteger idx = t * numberOfFrames; | ||
1334 | |||
1335 | if( idx >= numberOfFrames ) | ||
1336 | idx = numberOfFrames -1; | ||
1337 | |||
1338 | CCSprite *sprite = target_; | ||
1339 | if (! [sprite isFrameDisplayed: [frames objectAtIndex: idx]] ) | ||
1340 | [sprite setDisplayFrame: [frames objectAtIndex:idx]]; | ||
1341 | } | ||
1342 | |||
1343 | - (CCActionInterval *) reverse | ||
1344 | { | ||
1345 | NSArray *oldArray = [animation_ frames]; | ||
1346 | NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:[oldArray count]]; | ||
1347 | NSEnumerator *enumerator = [oldArray reverseObjectEnumerator]; | ||
1348 | for (id element in enumerator) | ||
1349 | [newArray addObject:[[element copy] autorelease]]; | ||
1350 | |||
1351 | CCAnimation *newAnim = [CCAnimation animationWithFrames:newArray delay:animation_.delay]; | ||
1352 | return [[self class] actionWithDuration:duration_ animation:newAnim restoreOriginalFrame:restoreOriginalFrame_]; | ||
1353 | } | ||
1354 | |||
1355 | @end | ||
diff --git a/libs/cocos2d/CCActionManager.h b/libs/cocos2d/CCActionManager.h new file mode 100755 index 0000000..0eeda91 --- /dev/null +++ b/libs/cocos2d/CCActionManager.h | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
7 | * Copyright (c) 2011 Zynga Inc. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | |||
30 | #import "CCAction.h" | ||
31 | #import "Support/ccCArray.h" | ||
32 | #import "Support/uthash.h" | ||
33 | |||
34 | typedef struct _hashElement | ||
35 | { | ||
36 | struct ccArray *actions; | ||
37 | id target; | ||
38 | NSUInteger actionIndex; | ||
39 | CCAction *currentAction; | ||
40 | BOOL currentActionSalvaged; | ||
41 | BOOL paused; | ||
42 | UT_hash_handle hh; | ||
43 | } tHashElement; | ||
44 | |||
45 | |||
46 | /** CCActionManager is a singleton that manages all the actions. | ||
47 | Normally you won't need to use this singleton directly. 99% of the cases you will use the CCNode interface, | ||
48 | which uses this singleton. | ||
49 | But there are some cases where you might need to use this singleton. | ||
50 | Examples: | ||
51 | - When you want to run an action where the target is different from a CCNode. | ||
52 | - When you want to pause / resume the actions | ||
53 | |||
54 | @since v0.8 | ||
55 | */ | ||
56 | @interface CCActionManager : NSObject | ||
57 | { | ||
58 | tHashElement *targets; | ||
59 | tHashElement *currentTarget; | ||
60 | BOOL currentTargetSalvaged; | ||
61 | } | ||
62 | |||
63 | /** returns a shared instance of the CCActionManager */ | ||
64 | + (CCActionManager *)sharedManager; | ||
65 | |||
66 | /** purges the shared action manager. It releases the retained instance. | ||
67 | @since v0.99.0 | ||
68 | */ | ||
69 | +(void)purgeSharedManager; | ||
70 | |||
71 | // actions | ||
72 | |||
73 | /** Adds an action with a target. | ||
74 | If the target is already present, then the action will be added to the existing target. | ||
75 | If the target is not present, a new instance of this target will be created either paused or paused, and the action will be added to the newly created target. | ||
76 | When the target is paused, the queued actions won't be 'ticked'. | ||
77 | */ | ||
78 | -(void) addAction: (CCAction*) action target:(id)target paused:(BOOL)paused; | ||
79 | /** Removes all actions from all the targers. | ||
80 | */ | ||
81 | -(void) removeAllActions; | ||
82 | |||
83 | /** Removes all actions from a certain target. | ||
84 | All the actions that belongs to the target will be removed. | ||
85 | */ | ||
86 | -(void) removeAllActionsFromTarget:(id)target; | ||
87 | /** Removes an action given an action reference. | ||
88 | */ | ||
89 | -(void) removeAction: (CCAction*) action; | ||
90 | /** Removes an action given its tag and the target */ | ||
91 | -(void) removeActionByTag:(NSInteger)tag target:(id)target; | ||
92 | /** Gets an action given its tag an a target | ||
93 | @return the Action the with the given tag | ||
94 | */ | ||
95 | -(CCAction*) getActionByTag:(NSInteger) tag target:(id)target; | ||
96 | /** Returns the numbers of actions that are running in a certain target | ||
97 | * Composable actions are counted as 1 action. Example: | ||
98 | * If you are running 1 Sequence of 7 actions, it will return 1. | ||
99 | * If you are running 7 Sequences of 2 actions, it will return 7. | ||
100 | */ | ||
101 | -(NSUInteger) numberOfRunningActionsInTarget:(id)target; | ||
102 | |||
103 | /** Pauses the target: all running actions and newly added actions will be paused. | ||
104 | */ | ||
105 | -(void) pauseTarget:(id)target; | ||
106 | /** Resumes the target. All queued actions will be resumed. | ||
107 | */ | ||
108 | -(void) resumeTarget:(id)target; | ||
109 | |||
110 | @end | ||
111 | |||
diff --git a/libs/cocos2d/CCActionManager.m b/libs/cocos2d/CCActionManager.m new file mode 100755 index 0000000..8bdfbb7 --- /dev/null +++ b/libs/cocos2d/CCActionManager.m | |||
@@ -0,0 +1,345 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
7 | * Copyright (c) 2011 Zynga Inc. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | |||
30 | #import "CCActionManager.h" | ||
31 | #import "CCScheduler.h" | ||
32 | #import "ccMacros.h" | ||
33 | |||
34 | |||
35 | // | ||
36 | // singleton stuff | ||
37 | // | ||
38 | static CCActionManager *sharedManager_ = nil; | ||
39 | |||
40 | @interface CCActionManager (Private) | ||
41 | -(void) removeActionAtIndex:(NSUInteger)index hashElement:(tHashElement*)element; | ||
42 | -(void) deleteHashElement:(tHashElement*)element; | ||
43 | -(void) actionAllocWithHashElement:(tHashElement*)element; | ||
44 | @end | ||
45 | |||
46 | |||
47 | @implementation CCActionManager | ||
48 | |||
49 | #pragma mark ActionManager - init | ||
50 | + (CCActionManager *)sharedManager | ||
51 | { | ||
52 | if (!sharedManager_) | ||
53 | sharedManager_ = [[self alloc] init]; | ||
54 | |||
55 | return sharedManager_; | ||
56 | } | ||
57 | |||
58 | +(id)alloc | ||
59 | { | ||
60 | NSAssert(sharedManager_ == nil, @"Attempted to allocate a second instance of a singleton."); | ||
61 | return [super alloc]; | ||
62 | } | ||
63 | |||
64 | +(void)purgeSharedManager | ||
65 | { | ||
66 | [[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self]; | ||
67 | [sharedManager_ release]; | ||
68 | sharedManager_ = nil; | ||
69 | } | ||
70 | |||
71 | -(id) init | ||
72 | { | ||
73 | if ((self=[super init]) ) { | ||
74 | [[CCScheduler sharedScheduler] scheduleUpdateForTarget:self priority:0 paused:NO]; | ||
75 | targets = NULL; | ||
76 | } | ||
77 | |||
78 | return self; | ||
79 | } | ||
80 | |||
81 | - (void) dealloc | ||
82 | { | ||
83 | CCLOGINFO( @"cocos2d: deallocing %@", self); | ||
84 | |||
85 | [self removeAllActions]; | ||
86 | |||
87 | sharedManager_ = nil; | ||
88 | |||
89 | [super dealloc]; | ||
90 | } | ||
91 | |||
92 | #pragma mark ActionManager - Private | ||
93 | |||
94 | -(void) deleteHashElement:(tHashElement*)element | ||
95 | { | ||
96 | ccArrayFree(element->actions); | ||
97 | HASH_DEL(targets, element); | ||
98 | // CCLOG(@"cocos2d: ---- buckets: %d/%d - %@", targets->entries, targets->size, element->target); | ||
99 | [element->target release]; | ||
100 | free(element); | ||
101 | } | ||
102 | |||
103 | -(void) actionAllocWithHashElement:(tHashElement*)element | ||
104 | { | ||
105 | // 4 actions per Node by default | ||
106 | if( element->actions == nil ) | ||
107 | element->actions = ccArrayNew(4); | ||
108 | else if( element->actions->num == element->actions->max ) | ||
109 | ccArrayDoubleCapacity(element->actions); | ||
110 | } | ||
111 | |||
112 | -(void) removeActionAtIndex:(NSUInteger)index hashElement:(tHashElement*)element | ||
113 | { | ||
114 | id action = element->actions->arr[index]; | ||
115 | |||
116 | if( action == element->currentAction && !element->currentActionSalvaged ) { | ||
117 | [element->currentAction retain]; | ||
118 | element->currentActionSalvaged = YES; | ||
119 | } | ||
120 | |||
121 | ccArrayRemoveObjectAtIndex(element->actions, index); | ||
122 | |||
123 | // update actionIndex in case we are in tick:, looping over the actions | ||
124 | if( element->actionIndex >= index ) | ||
125 | element->actionIndex--; | ||
126 | |||
127 | if( element->actions->num == 0 ) { | ||
128 | if( currentTarget == element ) | ||
129 | currentTargetSalvaged = YES; | ||
130 | else | ||
131 | [self deleteHashElement: element]; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | #pragma mark ActionManager - Pause / Resume | ||
136 | |||
137 | -(void) pauseTarget:(id)target | ||
138 | { | ||
139 | tHashElement *element = NULL; | ||
140 | HASH_FIND_INT(targets, &target, element); | ||
141 | if( element ) | ||
142 | element->paused = YES; | ||
143 | // else | ||
144 | // CCLOG(@"cocos2d: pauseAllActions: Target not found"); | ||
145 | } | ||
146 | |||
147 | -(void) resumeTarget:(id)target | ||
148 | { | ||
149 | tHashElement *element = NULL; | ||
150 | HASH_FIND_INT(targets, &target, element); | ||
151 | if( element ) | ||
152 | element->paused = NO; | ||
153 | // else | ||
154 | // CCLOG(@"cocos2d: resumeAllActions: Target not found"); | ||
155 | } | ||
156 | |||
157 | #pragma mark ActionManager - run | ||
158 | |||
159 | -(void) addAction:(CCAction*)action target:(id)target paused:(BOOL)paused | ||
160 | { | ||
161 | NSAssert( action != nil, @"Argument action must be non-nil"); | ||
162 | NSAssert( target != nil, @"Argument target must be non-nil"); | ||
163 | |||
164 | tHashElement *element = NULL; | ||
165 | HASH_FIND_INT(targets, &target, element); | ||
166 | if( ! element ) { | ||
167 | element = calloc( sizeof( *element ), 1 ); | ||
168 | element->paused = paused; | ||
169 | element->target = [target retain]; | ||
170 | HASH_ADD_INT(targets, target, element); | ||
171 | // CCLOG(@"cocos2d: ---- buckets: %d/%d - %@", targets->entries, targets->size, element->target); | ||
172 | |||
173 | } | ||
174 | |||
175 | [self actionAllocWithHashElement:element]; | ||
176 | |||
177 | NSAssert( !ccArrayContainsObject(element->actions, action), @"runAction: Action already running"); | ||
178 | ccArrayAppendObject(element->actions, action); | ||
179 | |||
180 | [action startWithTarget:target]; | ||
181 | } | ||
182 | |||
183 | #pragma mark ActionManager - remove | ||
184 | |||
185 | -(void) removeAllActions | ||
186 | { | ||
187 | for(tHashElement *element=targets; element != NULL; ) { | ||
188 | id target = element->target; | ||
189 | element = element->hh.next; | ||
190 | [self removeAllActionsFromTarget:target]; | ||
191 | } | ||
192 | } | ||
193 | -(void) removeAllActionsFromTarget:(id)target | ||
194 | { | ||
195 | // explicit nil handling | ||
196 | if( target == nil ) | ||
197 | return; | ||
198 | |||
199 | tHashElement *element = NULL; | ||
200 | HASH_FIND_INT(targets, &target, element); | ||
201 | if( element ) { | ||
202 | if( ccArrayContainsObject(element->actions, element->currentAction) && !element->currentActionSalvaged ) { | ||
203 | [element->currentAction retain]; | ||
204 | element->currentActionSalvaged = YES; | ||
205 | } | ||
206 | ccArrayRemoveAllObjects(element->actions); | ||
207 | if( currentTarget == element ) | ||
208 | currentTargetSalvaged = YES; | ||
209 | else | ||
210 | [self deleteHashElement:element]; | ||
211 | } | ||
212 | // else { | ||
213 | // CCLOG(@"cocos2d: removeAllActionsFromTarget: Target not found"); | ||
214 | // } | ||
215 | } | ||
216 | |||
217 | -(void) removeAction: (CCAction*) action | ||
218 | { | ||
219 | // explicit nil handling | ||
220 | if (action == nil) | ||
221 | return; | ||
222 | |||
223 | tHashElement *element = NULL; | ||
224 | id target = [action originalTarget]; | ||
225 | HASH_FIND_INT(targets, &target, element ); | ||
226 | if( element ) { | ||
227 | NSUInteger i = ccArrayGetIndexOfObject(element->actions, action); | ||
228 | if( i != NSNotFound ) | ||
229 | [self removeActionAtIndex:i hashElement:element]; | ||
230 | } | ||
231 | // else { | ||
232 | // CCLOG(@"cocos2d: removeAction: Target not found"); | ||
233 | // } | ||
234 | } | ||
235 | |||
236 | -(void) removeActionByTag:(NSInteger)aTag target:(id)target | ||
237 | { | ||
238 | NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag"); | ||
239 | NSAssert( target != nil, @"Target should be ! nil"); | ||
240 | |||
241 | tHashElement *element = NULL; | ||
242 | HASH_FIND_INT(targets, &target, element); | ||
243 | |||
244 | if( element ) { | ||
245 | NSUInteger limit = element->actions->num; | ||
246 | for( NSUInteger i = 0; i < limit; i++) { | ||
247 | CCAction *a = element->actions->arr[i]; | ||
248 | |||
249 | if( a.tag == aTag && [a originalTarget]==target) { | ||
250 | [self removeActionAtIndex:i hashElement:element]; | ||
251 | break; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | } | ||
256 | } | ||
257 | |||
258 | #pragma mark ActionManager - get | ||
259 | |||
260 | -(CCAction*) getActionByTag:(NSInteger)aTag target:(id)target | ||
261 | { | ||
262 | NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag"); | ||
263 | |||
264 | tHashElement *element = NULL; | ||
265 | HASH_FIND_INT(targets, &target, element); | ||
266 | |||
267 | if( element ) { | ||
268 | if( element->actions != nil ) { | ||
269 | NSUInteger limit = element->actions->num; | ||
270 | for( NSUInteger i = 0; i < limit; i++) { | ||
271 | CCAction *a = element->actions->arr[i]; | ||
272 | |||
273 | if( a.tag == aTag ) | ||
274 | return a; | ||
275 | } | ||
276 | } | ||
277 | // CCLOG(@"cocos2d: getActionByTag: Action not found"); | ||
278 | } | ||
279 | // else { | ||
280 | // CCLOG(@"cocos2d: getActionByTag: Target not found"); | ||
281 | // } | ||
282 | return nil; | ||
283 | } | ||
284 | |||
285 | -(NSUInteger) numberOfRunningActionsInTarget:(id) target | ||
286 | { | ||
287 | tHashElement *element = NULL; | ||
288 | HASH_FIND_INT(targets, &target, element); | ||
289 | if( element ) | ||
290 | return element->actions ? element->actions->num : 0; | ||
291 | |||
292 | // CCLOG(@"cocos2d: numberOfRunningActionsInTarget: Target not found"); | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | #pragma mark ActionManager - main loop | ||
297 | |||
298 | -(void) update: (ccTime) dt | ||
299 | { | ||
300 | for(tHashElement *elt = targets; elt != NULL; ) { | ||
301 | |||
302 | currentTarget = elt; | ||
303 | currentTargetSalvaged = NO; | ||
304 | |||
305 | if( ! currentTarget->paused ) { | ||
306 | |||
307 | // The 'actions' ccArray may change while inside this loop. | ||
308 | for( currentTarget->actionIndex = 0; currentTarget->actionIndex < currentTarget->actions->num; currentTarget->actionIndex++) { | ||
309 | currentTarget->currentAction = currentTarget->actions->arr[currentTarget->actionIndex]; | ||
310 | currentTarget->currentActionSalvaged = NO; | ||
311 | |||
312 | [currentTarget->currentAction step: dt]; | ||
313 | |||
314 | if( currentTarget->currentActionSalvaged ) { | ||
315 | // The currentAction told the node to remove it. To prevent the action from | ||
316 | // accidentally deallocating itself before finishing its step, we retained | ||
317 | // it. Now that step is done, it's safe to release it. | ||
318 | [currentTarget->currentAction release]; | ||
319 | |||
320 | } else if( [currentTarget->currentAction isDone] ) { | ||
321 | [currentTarget->currentAction stop]; | ||
322 | |||
323 | CCAction *a = currentTarget->currentAction; | ||
324 | // Make currentAction nil to prevent removeAction from salvaging it. | ||
325 | currentTarget->currentAction = nil; | ||
326 | [self removeAction:a]; | ||
327 | } | ||
328 | |||
329 | currentTarget->currentAction = nil; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | // elt, at this moment, is still valid | ||
334 | // so it is safe to ask this here (issue #490) | ||
335 | elt = elt->hh.next; | ||
336 | |||
337 | // only delete currentTarget if no actions were scheduled during the cycle (issue #481) | ||
338 | if( currentTargetSalvaged && currentTarget->actions->num == 0 ) | ||
339 | [self deleteHashElement:currentTarget]; | ||
340 | } | ||
341 | |||
342 | // issue #635 | ||
343 | currentTarget = nil; | ||
344 | } | ||
345 | @end | ||
diff --git a/libs/cocos2d/CCActionPageTurn3D.h b/libs/cocos2d/CCActionPageTurn3D.h new file mode 100755 index 0000000..39eb31d --- /dev/null +++ b/libs/cocos2d/CCActionPageTurn3D.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Sindesso Pty Ltd http://www.sindesso.com/ | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCActionGrid3D.h" | ||
28 | |||
29 | /** | ||
30 | * This action simulates a page turn from the bottom right hand corner of the screen | ||
31 | * It's not much use by itself but is used by the PageTurnTransition. | ||
32 | * | ||
33 | * Based on an original paper by L Hong et al. | ||
34 | * http://www.parc.com/publication/1638/turning-pages-of-3d-electronic-books.html | ||
35 | * | ||
36 | * @since v0.8.2 | ||
37 | */ | ||
38 | @interface CCPageTurn3D : CCGrid3DAction | ||
39 | { | ||
40 | } | ||
41 | |||
42 | @end | ||
diff --git a/libs/cocos2d/CCActionPageTurn3D.m b/libs/cocos2d/CCActionPageTurn3D.m new file mode 100755 index 0000000..ee59500 --- /dev/null +++ b/libs/cocos2d/CCActionPageTurn3D.m | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Sindesso Pty Ltd http://www.sindesso.com/ | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import "CCActionPageTurn3D.h" | ||
27 | |||
28 | @implementation CCPageTurn3D | ||
29 | |||
30 | /* | ||
31 | * Update each tick | ||
32 | * Time is the percentage of the way through the duration | ||
33 | */ | ||
34 | -(void)update:(ccTime)time | ||
35 | { | ||
36 | float tt = MAX( 0, time - 0.25f ); | ||
37 | float deltaAy = ( tt * tt * 500); | ||
38 | float ay = -100 - deltaAy; | ||
39 | |||
40 | float deltaTheta = - (float) M_PI_2 * sqrtf( time) ; | ||
41 | float theta = /*0.01f*/ + (float) M_PI_2 +deltaTheta; | ||
42 | |||
43 | float sinTheta = sinf(theta); | ||
44 | float cosTheta = cosf(theta); | ||
45 | |||
46 | for( int i = 0; i <=gridSize_.x; i++ ) | ||
47 | { | ||
48 | for( int j = 0; j <= gridSize_.y; j++ ) | ||
49 | { | ||
50 | // Get original vertex | ||
51 | ccVertex3F p = [self originalVertex:ccg(i,j)]; | ||
52 | |||
53 | float R = sqrtf(p.x*p.x + (p.y - ay) * (p.y - ay)); | ||
54 | float r = R * sinTheta; | ||
55 | float alpha = asinf( p.x / R ); | ||
56 | float beta = alpha / sinTheta; | ||
57 | float cosBeta = cosf( beta ); | ||
58 | |||
59 | // If beta > PI then we've wrapped around the cone | ||
60 | // Reduce the radius to stop these points interfering with others | ||
61 | if( beta <= M_PI) | ||
62 | p.x = ( r * sinf(beta)); | ||
63 | else | ||
64 | { | ||
65 | // Force X = 0 to stop wrapped | ||
66 | // points | ||
67 | p.x = 0; | ||
68 | } | ||
69 | |||
70 | p.y = ( R + ay - ( r*(1 - cosBeta)*sinTheta)); | ||
71 | |||
72 | // We scale z here to avoid the animation being | ||
73 | // too much bigger than the screen due to perspectve transform | ||
74 | p.z = (r * ( 1 - cosBeta ) * cosTheta) / 7; // "100" didn't work for | ||
75 | |||
76 | // Stop z coord from dropping beneath underlying page in a transition | ||
77 | // issue #751 | ||
78 | if( p.z<0.5f ) | ||
79 | p.z = 0.5f; | ||
80 | |||
81 | // Set new coords | ||
82 | [self setVertex:ccg(i,j) vertex:p]; | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | @end | ||
diff --git a/libs/cocos2d/CCActionProgressTimer.h b/libs/cocos2d/CCActionProgressTimer.h new file mode 100755 index 0000000..500631b --- /dev/null +++ b/libs/cocos2d/CCActionProgressTimer.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (C) 2010 Lam Pham | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import <Foundation/Foundation.h> | ||
28 | #import "CCProgressTimer.h" | ||
29 | #import "CCActionInterval.h" | ||
30 | |||
31 | /** | ||
32 | Progress to percentage | ||
33 | @since v0.99.1 | ||
34 | */ | ||
35 | @interface CCProgressTo : CCActionInterval <NSCopying> | ||
36 | { | ||
37 | float to_; | ||
38 | float from_; | ||
39 | } | ||
40 | /** Creates and initializes with a duration and a percent */ | ||
41 | +(id) actionWithDuration:(ccTime)duration percent:(float)percent; | ||
42 | /** Initializes with a duration and a percent */ | ||
43 | -(id) initWithDuration:(ccTime)duration percent:(float)percent; | ||
44 | @end | ||
45 | |||
46 | /** | ||
47 | Progress from a percentage to another percentage | ||
48 | @since v0.99.1 | ||
49 | */ | ||
50 | @interface CCProgressFromTo : CCActionInterval <NSCopying> | ||
51 | { | ||
52 | float to_; | ||
53 | float from_; | ||
54 | } | ||
55 | /** Creates and initializes the action with a duration, a "from" percentage and a "to" percentage */ | ||
56 | +(id) actionWithDuration:(ccTime)duration from:(float)fromPercentage to:(float) toPercentage; | ||
57 | /** Initializes the action with a duration, a "from" percentage and a "to" percentage */ | ||
58 | -(id) initWithDuration:(ccTime)duration from:(float)fromPercentage to:(float) toPercentage; | ||
59 | @end | ||
diff --git a/libs/cocos2d/CCActionProgressTimer.m b/libs/cocos2d/CCActionProgressTimer.m new file mode 100755 index 0000000..c242570 --- /dev/null +++ b/libs/cocos2d/CCActionProgressTimer.m | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (C) 2010 Lam Pham | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCActionProgressTimer.h" | ||
28 | |||
29 | #define kProgressTimerCast CCProgressTimer* | ||
30 | |||
31 | @implementation CCProgressTo | ||
32 | +(id) actionWithDuration: (ccTime) t percent: (float) v | ||
33 | { | ||
34 | return [[[ self alloc] initWithDuration: t percent: v] autorelease]; | ||
35 | } | ||
36 | |||
37 | -(id) initWithDuration: (ccTime) t percent: (float) v | ||
38 | { | ||
39 | if( (self=[super initWithDuration: t] ) ) | ||
40 | to_ = v; | ||
41 | |||
42 | return self; | ||
43 | } | ||
44 | |||
45 | -(id) copyWithZone: (NSZone*) zone | ||
46 | { | ||
47 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration:duration_ percent:to_]; | ||
48 | return copy; | ||
49 | } | ||
50 | |||
51 | -(void) startWithTarget:(id) aTarget; | ||
52 | { | ||
53 | [super startWithTarget:aTarget]; | ||
54 | from_ = [(kProgressTimerCast)target_ percentage]; | ||
55 | |||
56 | // XXX: Is this correct ? | ||
57 | // Adding it to support CCRepeat | ||
58 | if( from_ == 100) | ||
59 | from_ = 0; | ||
60 | } | ||
61 | |||
62 | -(void) update: (ccTime) t | ||
63 | { | ||
64 | [(kProgressTimerCast)target_ setPercentage: from_ + ( to_ - from_ ) * t]; | ||
65 | } | ||
66 | @end | ||
67 | |||
68 | @implementation CCProgressFromTo | ||
69 | +(id) actionWithDuration: (ccTime) t from:(float)fromPercentage to:(float) toPercentage | ||
70 | { | ||
71 | return [[[self alloc] initWithDuration: t from: fromPercentage to: toPercentage] autorelease]; | ||
72 | } | ||
73 | |||
74 | -(id) initWithDuration: (ccTime) t from:(float)fromPercentage to:(float) toPercentage | ||
75 | { | ||
76 | if( (self=[super initWithDuration: t] ) ){ | ||
77 | to_ = toPercentage; | ||
78 | from_ = fromPercentage; | ||
79 | } | ||
80 | return self; | ||
81 | } | ||
82 | |||
83 | -(id) copyWithZone: (NSZone*) zone | ||
84 | { | ||
85 | CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration:duration_ from:from_ to:to_]; | ||
86 | return copy; | ||
87 | } | ||
88 | |||
89 | - (CCActionInterval *) reverse | ||
90 | { | ||
91 | return [[self class] actionWithDuration:duration_ from:to_ to:from_]; | ||
92 | } | ||
93 | |||
94 | -(void) startWithTarget:(id) aTarget; | ||
95 | { | ||
96 | [super startWithTarget:aTarget]; | ||
97 | } | ||
98 | |||
99 | -(void) update: (ccTime) t | ||
100 | { | ||
101 | [(kProgressTimerCast)target_ setPercentage: from_ + ( to_ - from_ ) * t]; | ||
102 | } | ||
103 | @end | ||
diff --git a/libs/cocos2d/CCActionTiledGrid.h b/libs/cocos2d/CCActionTiledGrid.h new file mode 100755 index 0000000..d66132d --- /dev/null +++ b/libs/cocos2d/CCActionTiledGrid.h | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 On-Core | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import "CCActionGrid.h" | ||
27 | |||
28 | /** CCShakyTiles3D action */ | ||
29 | @interface CCShakyTiles3D : CCTiledGrid3DAction | ||
30 | { | ||
31 | int randrange; | ||
32 | BOOL shakeZ; | ||
33 | } | ||
34 | |||
35 | /** creates the action with a range, whether or not to shake Z vertices, a grid size, and duration */ | ||
36 | +(id)actionWithRange:(int)range shakeZ:(BOOL)shakeZ grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
37 | /** initializes the action with a range, whether or not to shake Z vertices, a grid size, and duration */ | ||
38 | -(id)initWithRange:(int)range shakeZ:(BOOL)shakeZ grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
39 | |||
40 | @end | ||
41 | |||
42 | //////////////////////////////////////////////////////////// | ||
43 | |||
44 | /** CCShatteredTiles3D action */ | ||
45 | @interface CCShatteredTiles3D : CCTiledGrid3DAction | ||
46 | { | ||
47 | int randrange; | ||
48 | BOOL once; | ||
49 | BOOL shatterZ; | ||
50 | } | ||
51 | |||
52 | /** creates the action with a range, whether of not to shatter Z vertices, a grid size and duration */ | ||
53 | +(id)actionWithRange:(int)range shatterZ:(BOOL)shatterZ grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
54 | /** initializes the action with a range, whether or not to shatter Z vertices, a grid size and duration */ | ||
55 | -(id)initWithRange:(int)range shatterZ:(BOOL)shatterZ grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
56 | |||
57 | @end | ||
58 | |||
59 | //////////////////////////////////////////////////////////// | ||
60 | |||
61 | /** CCShuffleTiles action | ||
62 | Shuffle the tiles in random order | ||
63 | */ | ||
64 | @interface CCShuffleTiles : CCTiledGrid3DAction | ||
65 | { | ||
66 | int seed; | ||
67 | NSUInteger tilesCount; | ||
68 | int *tilesOrder; | ||
69 | void *tiles; | ||
70 | } | ||
71 | |||
72 | /** creates the action with a random seed, the grid size and the duration */ | ||
73 | +(id)actionWithSeed:(int)s grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
74 | /** initializes the action with a random seed, the grid size and the duration */ | ||
75 | -(id)initWithSeed:(int)s grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
76 | |||
77 | @end | ||
78 | |||
79 | //////////////////////////////////////////////////////////// | ||
80 | |||
81 | /** CCFadeOutTRTiles action | ||
82 | Fades out the tiles in a Top-Right direction | ||
83 | */ | ||
84 | @interface CCFadeOutTRTiles : CCTiledGrid3DAction | ||
85 | { | ||
86 | } | ||
87 | @end | ||
88 | |||
89 | //////////////////////////////////////////////////////////// | ||
90 | |||
91 | /** CCFadeOutBLTiles action. | ||
92 | Fades out the tiles in a Bottom-Left direction | ||
93 | */ | ||
94 | @interface CCFadeOutBLTiles : CCFadeOutTRTiles | ||
95 | { | ||
96 | } | ||
97 | @end | ||
98 | |||
99 | //////////////////////////////////////////////////////////// | ||
100 | |||
101 | /** CCFadeOutUpTiles action. | ||
102 | Fades out the tiles in upwards direction | ||
103 | */ | ||
104 | @interface CCFadeOutUpTiles : CCFadeOutTRTiles | ||
105 | { | ||
106 | } | ||
107 | @end | ||
108 | |||
109 | //////////////////////////////////////////////////////////// | ||
110 | |||
111 | /** CCFadeOutDownTiles action. | ||
112 | Fades out the tiles in downwards direction | ||
113 | */ | ||
114 | @interface CCFadeOutDownTiles : CCFadeOutUpTiles | ||
115 | { | ||
116 | } | ||
117 | @end | ||
118 | |||
119 | //////////////////////////////////////////////////////////// | ||
120 | |||
121 | /** CCTurnOffTiles action. | ||
122 | Turn off the files in random order | ||
123 | */ | ||
124 | @interface CCTurnOffTiles : CCTiledGrid3DAction | ||
125 | { | ||
126 | int seed; | ||
127 | NSUInteger tilesCount; | ||
128 | int *tilesOrder; | ||
129 | } | ||
130 | |||
131 | /** creates the action with a random seed, the grid size and the duration */ | ||
132 | +(id)actionWithSeed:(int)s grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
133 | /** initializes the action with a random seed, the grid size and the duration */ | ||
134 | -(id)initWithSeed:(int)s grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
135 | @end | ||
136 | |||
137 | //////////////////////////////////////////////////////////// | ||
138 | |||
139 | /** CCWavesTiles3D action. */ | ||
140 | @interface CCWavesTiles3D : CCTiledGrid3DAction | ||
141 | { | ||
142 | int waves; | ||
143 | float amplitude; | ||
144 | float amplitudeRate; | ||
145 | } | ||
146 | |||
147 | /** waves amplitude */ | ||
148 | @property (nonatomic,readwrite) float amplitude; | ||
149 | /** waves amplitude rate */ | ||
150 | @property (nonatomic,readwrite) float amplitudeRate; | ||
151 | |||
152 | /** creates the action with a number of waves, the waves amplitude, the grid size and the duration */ | ||
153 | +(id)actionWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
154 | /** initializes the action with a number of waves, the waves amplitude, the grid size and the duration */ | ||
155 | -(id)initWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
156 | |||
157 | @end | ||
158 | |||
159 | //////////////////////////////////////////////////////////// | ||
160 | |||
161 | /** CCJumpTiles3D action. | ||
162 | A sin function is executed to move the tiles across the Z axis | ||
163 | */ | ||
164 | @interface CCJumpTiles3D : CCTiledGrid3DAction | ||
165 | { | ||
166 | int jumps; | ||
167 | float amplitude; | ||
168 | float amplitudeRate; | ||
169 | } | ||
170 | |||
171 | /** amplitude of the sin*/ | ||
172 | @property (nonatomic,readwrite) float amplitude; | ||
173 | /** amplitude rate */ | ||
174 | @property (nonatomic,readwrite) float amplitudeRate; | ||
175 | |||
176 | /** creates the action with the number of jumps, the sin amplitude, the grid size and the duration */ | ||
177 | +(id)actionWithJumps:(int)j amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
178 | /** initializes the action with the number of jumps, the sin amplitude, the grid size and the duration */ | ||
179 | -(id)initWithJumps:(int)j amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d; | ||
180 | |||
181 | @end | ||
182 | |||
183 | //////////////////////////////////////////////////////////// | ||
184 | |||
185 | /** CCSplitRows action */ | ||
186 | @interface CCSplitRows : CCTiledGrid3DAction | ||
187 | { | ||
188 | int rows; | ||
189 | CGSize winSize; | ||
190 | } | ||
191 | /** creates the action with the number of rows to split and the duration */ | ||
192 | +(id)actionWithRows:(int)rows duration:(ccTime)duration; | ||
193 | /** initializes the action with the number of rows to split and the duration */ | ||
194 | -(id)initWithRows:(int)rows duration:(ccTime)duration; | ||
195 | |||
196 | @end | ||
197 | |||
198 | //////////////////////////////////////////////////////////// | ||
199 | |||
200 | /** CCSplitCols action */ | ||
201 | @interface CCSplitCols : CCTiledGrid3DAction | ||
202 | { | ||
203 | int cols; | ||
204 | CGSize winSize; | ||
205 | } | ||
206 | /** creates the action with the number of columns to split and the duration */ | ||
207 | +(id)actionWithCols:(int)cols duration:(ccTime)duration; | ||
208 | /** initializes the action with the number of columns to split and the duration */ | ||
209 | -(id)initWithCols:(int)cols duration:(ccTime)duration; | ||
210 | |||
211 | @end | ||
diff --git a/libs/cocos2d/CCActionTiledGrid.m b/libs/cocos2d/CCActionTiledGrid.m new file mode 100755 index 0000000..75965ec --- /dev/null +++ b/libs/cocos2d/CCActionTiledGrid.m | |||
@@ -0,0 +1,768 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 On-Core | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCActionTiledGrid.h" | ||
28 | #import "CCDirector.h" | ||
29 | #import "ccMacros.h" | ||
30 | #import "Support/CGPointExtension.h" | ||
31 | |||
32 | typedef struct | ||
33 | { | ||
34 | CGPoint position; | ||
35 | CGPoint startPosition; | ||
36 | ccGridSize delta; | ||
37 | } Tile; | ||
38 | |||
39 | #pragma mark - | ||
40 | #pragma mark ShakyTiles3D | ||
41 | |||
42 | @implementation CCShakyTiles3D | ||
43 | |||
44 | +(id)actionWithRange:(int)range shakeZ:(BOOL)shakeZ grid:(ccGridSize)gridSize duration:(ccTime)d | ||
45 | { | ||
46 | return [[[self alloc] initWithRange:range shakeZ:shakeZ grid:gridSize duration:d] autorelease]; | ||
47 | } | ||
48 | |||
49 | -(id)initWithRange:(int)range shakeZ:(BOOL)sz grid:(ccGridSize)gSize duration:(ccTime)d | ||
50 | { | ||
51 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
52 | { | ||
53 | randrange = range; | ||
54 | shakeZ = sz; | ||
55 | } | ||
56 | |||
57 | return self; | ||
58 | } | ||
59 | |||
60 | -(id) copyWithZone: (NSZone*) zone | ||
61 | { | ||
62 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithRange:randrange shakeZ:shakeZ grid:gridSize_ duration:duration_]; | ||
63 | return copy; | ||
64 | } | ||
65 | |||
66 | |||
67 | -(void)update:(ccTime)time | ||
68 | { | ||
69 | int i, j; | ||
70 | |||
71 | for( i = 0; i < gridSize_.x; i++ ) | ||
72 | { | ||
73 | for( j = 0; j < gridSize_.y; j++ ) | ||
74 | { | ||
75 | ccQuad3 coords = [self originalTile:ccg(i,j)]; | ||
76 | |||
77 | // X | ||
78 | coords.bl.x += ( rand() % (randrange*2) ) - randrange; | ||
79 | coords.br.x += ( rand() % (randrange*2) ) - randrange; | ||
80 | coords.tl.x += ( rand() % (randrange*2) ) - randrange; | ||
81 | coords.tr.x += ( rand() % (randrange*2) ) - randrange; | ||
82 | |||
83 | // Y | ||
84 | coords.bl.y += ( rand() % (randrange*2) ) - randrange; | ||
85 | coords.br.y += ( rand() % (randrange*2) ) - randrange; | ||
86 | coords.tl.y += ( rand() % (randrange*2) ) - randrange; | ||
87 | coords.tr.y += ( rand() % (randrange*2) ) - randrange; | ||
88 | |||
89 | if( shakeZ ) { | ||
90 | coords.bl.z += ( rand() % (randrange*2) ) - randrange; | ||
91 | coords.br.z += ( rand() % (randrange*2) ) - randrange; | ||
92 | coords.tl.z += ( rand() % (randrange*2) ) - randrange; | ||
93 | coords.tr.z += ( rand() % (randrange*2) ) - randrange; | ||
94 | } | ||
95 | |||
96 | [self setTile:ccg(i,j) coords:coords]; | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | |||
101 | @end | ||
102 | |||
103 | //////////////////////////////////////////////////////////// | ||
104 | |||
105 | #pragma mark - | ||
106 | #pragma mark CCShatteredTiles3D | ||
107 | |||
108 | @implementation CCShatteredTiles3D | ||
109 | |||
110 | +(id)actionWithRange:(int)range shatterZ:(BOOL)sz grid:(ccGridSize)gridSize duration:(ccTime)d | ||
111 | { | ||
112 | return [[[self alloc] initWithRange:range shatterZ:sz grid:gridSize duration:d] autorelease]; | ||
113 | } | ||
114 | |||
115 | -(id)initWithRange:(int)range shatterZ:(BOOL)sz grid:(ccGridSize)gSize duration:(ccTime)d | ||
116 | { | ||
117 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
118 | { | ||
119 | once = NO; | ||
120 | randrange = range; | ||
121 | shatterZ = sz; | ||
122 | } | ||
123 | |||
124 | return self; | ||
125 | } | ||
126 | |||
127 | -(id) copyWithZone: (NSZone*) zone | ||
128 | { | ||
129 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithRange:randrange shatterZ:shatterZ grid:gridSize_ duration:duration_]; | ||
130 | return copy; | ||
131 | } | ||
132 | |||
133 | |||
134 | -(void)update:(ccTime)time | ||
135 | { | ||
136 | int i, j; | ||
137 | |||
138 | if ( once == NO ) | ||
139 | { | ||
140 | for( i = 0; i < gridSize_.x; i++ ) | ||
141 | { | ||
142 | for( j = 0; j < gridSize_.y; j++ ) | ||
143 | { | ||
144 | ccQuad3 coords = [self originalTile:ccg(i,j)]; | ||
145 | |||
146 | // X | ||
147 | coords.bl.x += ( rand() % (randrange*2) ) - randrange; | ||
148 | coords.br.x += ( rand() % (randrange*2) ) - randrange; | ||
149 | coords.tl.x += ( rand() % (randrange*2) ) - randrange; | ||
150 | coords.tr.x += ( rand() % (randrange*2) ) - randrange; | ||
151 | |||
152 | // Y | ||
153 | coords.bl.y += ( rand() % (randrange*2) ) - randrange; | ||
154 | coords.br.y += ( rand() % (randrange*2) ) - randrange; | ||
155 | coords.tl.y += ( rand() % (randrange*2) ) - randrange; | ||
156 | coords.tr.y += ( rand() % (randrange*2) ) - randrange; | ||
157 | |||
158 | if( shatterZ ) { | ||
159 | coords.bl.z += ( rand() % (randrange*2) ) - randrange; | ||
160 | coords.br.z += ( rand() % (randrange*2) ) - randrange; | ||
161 | coords.tl.z += ( rand() % (randrange*2) ) - randrange; | ||
162 | coords.tr.z += ( rand() % (randrange*2) ) - randrange; | ||
163 | } | ||
164 | |||
165 | [self setTile:ccg(i,j) coords:coords]; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | once = YES; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | @end | ||
174 | |||
175 | //////////////////////////////////////////////////////////// | ||
176 | |||
177 | #pragma mark - | ||
178 | #pragma mark CCShuffleTiles | ||
179 | |||
180 | @implementation CCShuffleTiles | ||
181 | |||
182 | +(id)actionWithSeed:(int)s grid:(ccGridSize)gridSize duration:(ccTime)d | ||
183 | { | ||
184 | return [[[self alloc] initWithSeed:s grid:gridSize duration:d] autorelease]; | ||
185 | } | ||
186 | |||
187 | -(id)initWithSeed:(int)s grid:(ccGridSize)gSize duration:(ccTime)d | ||
188 | { | ||
189 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
190 | { | ||
191 | seed = s; | ||
192 | tilesOrder = nil; | ||
193 | tiles = nil; | ||
194 | } | ||
195 | |||
196 | return self; | ||
197 | } | ||
198 | |||
199 | -(id) copyWithZone: (NSZone*) zone | ||
200 | { | ||
201 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithSeed:seed grid:gridSize_ duration:duration_]; | ||
202 | return copy; | ||
203 | } | ||
204 | |||
205 | |||
206 | -(void)dealloc | ||
207 | { | ||
208 | if ( tilesOrder ) free(tilesOrder); | ||
209 | if ( tiles ) free(tiles); | ||
210 | [super dealloc]; | ||
211 | } | ||
212 | |||
213 | -(void)shuffle:(int*)array count:(NSUInteger)len | ||
214 | { | ||
215 | NSInteger i; | ||
216 | for( i = len - 1; i >= 0; i-- ) | ||
217 | { | ||
218 | NSInteger j = rand() % (i+1); | ||
219 | int v = array[i]; | ||
220 | array[i] = array[j]; | ||
221 | array[j] = v; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | -(ccGridSize)getDelta:(ccGridSize)pos | ||
226 | { | ||
227 | CGPoint pos2; | ||
228 | |||
229 | NSInteger idx = pos.x * gridSize_.y + pos.y; | ||
230 | |||
231 | pos2.x = tilesOrder[idx] / (int)gridSize_.y; | ||
232 | pos2.y = tilesOrder[idx] % (int)gridSize_.y; | ||
233 | |||
234 | return ccg(pos2.x - pos.x, pos2.y - pos.y); | ||
235 | } | ||
236 | |||
237 | -(void)placeTile:(ccGridSize)pos tile:(Tile)t | ||
238 | { | ||
239 | ccQuad3 coords = [self originalTile:pos]; | ||
240 | |||
241 | CGPoint step = [[target_ grid] step]; | ||
242 | coords.bl.x += (int)(t.position.x * step.x); | ||
243 | coords.bl.y += (int)(t.position.y * step.y); | ||
244 | |||
245 | coords.br.x += (int)(t.position.x * step.x); | ||
246 | coords.br.y += (int)(t.position.y * step.y); | ||
247 | |||
248 | coords.tl.x += (int)(t.position.x * step.x); | ||
249 | coords.tl.y += (int)(t.position.y * step.y); | ||
250 | |||
251 | coords.tr.x += (int)(t.position.x * step.x); | ||
252 | coords.tr.y += (int)(t.position.y * step.y); | ||
253 | |||
254 | [self setTile:pos coords:coords]; | ||
255 | } | ||
256 | |||
257 | -(void)startWithTarget:(id)aTarget | ||
258 | { | ||
259 | [super startWithTarget:aTarget]; | ||
260 | |||
261 | if ( seed != -1 ) | ||
262 | srand(seed); | ||
263 | |||
264 | tilesCount = gridSize_.x * gridSize_.y; | ||
265 | tilesOrder = (int*)malloc(tilesCount*sizeof(int)); | ||
266 | int i, j; | ||
267 | |||
268 | for( i = 0; i < tilesCount; i++ ) | ||
269 | tilesOrder[i] = i; | ||
270 | |||
271 | [self shuffle:tilesOrder count:tilesCount]; | ||
272 | |||
273 | tiles = malloc(tilesCount*sizeof(Tile)); | ||
274 | Tile *tileArray = (Tile*)tiles; | ||
275 | |||
276 | for( i = 0; i < gridSize_.x; i++ ) | ||
277 | { | ||
278 | for( j = 0; j < gridSize_.y; j++ ) | ||
279 | { | ||
280 | tileArray->position = ccp(i,j); | ||
281 | tileArray->startPosition = ccp(i,j); | ||
282 | tileArray->delta = [self getDelta:ccg(i,j)]; | ||
283 | tileArray++; | ||
284 | } | ||
285 | } | ||
286 | } | ||
287 | |||
288 | -(void)update:(ccTime)time | ||
289 | { | ||
290 | int i, j; | ||
291 | |||
292 | Tile *tileArray = (Tile*)tiles; | ||
293 | |||
294 | for( i = 0; i < gridSize_.x; i++ ) | ||
295 | { | ||
296 | for( j = 0; j < gridSize_.y; j++ ) | ||
297 | { | ||
298 | tileArray->position = ccpMult( ccp(tileArray->delta.x, tileArray->delta.y), time); | ||
299 | [self placeTile:ccg(i,j) tile:*tileArray]; | ||
300 | tileArray++; | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | |||
305 | @end | ||
306 | |||
307 | //////////////////////////////////////////////////////////// | ||
308 | |||
309 | #pragma mark - | ||
310 | #pragma mark CCFadeOutTRTiles | ||
311 | |||
312 | @implementation CCFadeOutTRTiles | ||
313 | |||
314 | -(float)testFunc:(ccGridSize)pos time:(ccTime)time | ||
315 | { | ||
316 | CGPoint n = ccpMult( ccp(gridSize_.x,gridSize_.y), time); | ||
317 | if ( (n.x+n.y) == 0.0f ) | ||
318 | return 1.0f; | ||
319 | |||
320 | return powf( (pos.x+pos.y) / (n.x+n.y), 6 ); | ||
321 | } | ||
322 | |||
323 | -(void)turnOnTile:(ccGridSize)pos | ||
324 | { | ||
325 | [self setTile:pos coords:[self originalTile:pos]]; | ||
326 | } | ||
327 | |||
328 | -(void)turnOffTile:(ccGridSize)pos | ||
329 | { | ||
330 | ccQuad3 coords; | ||
331 | bzero(&coords, sizeof(ccQuad3)); | ||
332 | [self setTile:pos coords:coords]; | ||
333 | } | ||
334 | |||
335 | -(void)transformTile:(ccGridSize)pos distance:(float)distance | ||
336 | { | ||
337 | ccQuad3 coords = [self originalTile:pos]; | ||
338 | CGPoint step = [[target_ grid] step]; | ||
339 | |||
340 | coords.bl.x += (step.x / 2) * (1.0f - distance); | ||
341 | coords.bl.y += (step.y / 2) * (1.0f - distance); | ||
342 | |||
343 | coords.br.x -= (step.x / 2) * (1.0f - distance); | ||
344 | coords.br.y += (step.y / 2) * (1.0f - distance); | ||
345 | |||
346 | coords.tl.x += (step.x / 2) * (1.0f - distance); | ||
347 | coords.tl.y -= (step.y / 2) * (1.0f - distance); | ||
348 | |||
349 | coords.tr.x -= (step.x / 2) * (1.0f - distance); | ||
350 | coords.tr.y -= (step.y / 2) * (1.0f - distance); | ||
351 | |||
352 | [self setTile:pos coords:coords]; | ||
353 | } | ||
354 | |||
355 | -(void)update:(ccTime)time | ||
356 | { | ||
357 | int i, j; | ||
358 | |||
359 | for( i = 0; i < gridSize_.x; i++ ) | ||
360 | { | ||
361 | for( j = 0; j < gridSize_.y; j++ ) | ||
362 | { | ||
363 | float distance = [self testFunc:ccg(i,j) time:time]; | ||
364 | if ( distance == 0 ) | ||
365 | [self turnOffTile:ccg(i,j)]; | ||
366 | else if ( distance < 1 ) | ||
367 | [self transformTile:ccg(i,j) distance:distance]; | ||
368 | else | ||
369 | [self turnOnTile:ccg(i,j)]; | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | |||
374 | @end | ||
375 | |||
376 | //////////////////////////////////////////////////////////// | ||
377 | |||
378 | #pragma mark - | ||
379 | #pragma mark CCFadeOutBLTiles | ||
380 | |||
381 | @implementation CCFadeOutBLTiles | ||
382 | |||
383 | -(float)testFunc:(ccGridSize)pos time:(ccTime)time | ||
384 | { | ||
385 | CGPoint n = ccpMult(ccp(gridSize_.x, gridSize_.y), (1.0f-time)); | ||
386 | if ( (pos.x+pos.y) == 0 ) | ||
387 | return 1.0f; | ||
388 | |||
389 | return powf( (n.x+n.y) / (pos.x+pos.y), 6 ); | ||
390 | } | ||
391 | |||
392 | @end | ||
393 | |||
394 | //////////////////////////////////////////////////////////// | ||
395 | |||
396 | #pragma mark - | ||
397 | #pragma mark CCFadeOutUpTiles | ||
398 | |||
399 | @implementation CCFadeOutUpTiles | ||
400 | |||
401 | -(float)testFunc:(ccGridSize)pos time:(ccTime)time | ||
402 | { | ||
403 | CGPoint n = ccpMult(ccp(gridSize_.x, gridSize_.y), time); | ||
404 | if ( n.y == 0 ) | ||
405 | return 1.0f; | ||
406 | |||
407 | return powf( pos.y / n.y, 6 ); | ||
408 | } | ||
409 | |||
410 | -(void)transformTile:(ccGridSize)pos distance:(float)distance | ||
411 | { | ||
412 | ccQuad3 coords = [self originalTile:pos]; | ||
413 | CGPoint step = [[target_ grid] step]; | ||
414 | |||
415 | coords.bl.y += (step.y / 2) * (1.0f - distance); | ||
416 | coords.br.y += (step.y / 2) * (1.0f - distance); | ||
417 | coords.tl.y -= (step.y / 2) * (1.0f - distance); | ||
418 | coords.tr.y -= (step.y / 2) * (1.0f - distance); | ||
419 | |||
420 | [self setTile:pos coords:coords]; | ||
421 | } | ||
422 | |||
423 | @end | ||
424 | |||
425 | //////////////////////////////////////////////////////////// | ||
426 | |||
427 | #pragma mark - | ||
428 | #pragma mark CCFadeOutDownTiles | ||
429 | |||
430 | @implementation CCFadeOutDownTiles | ||
431 | |||
432 | -(float)testFunc:(ccGridSize)pos time:(ccTime)time | ||
433 | { | ||
434 | CGPoint n = ccpMult(ccp(gridSize_.x,gridSize_.y), (1.0f - time)); | ||
435 | if ( pos.y == 0 ) | ||
436 | return 1.0f; | ||
437 | |||
438 | return powf( n.y / pos.y, 6 ); | ||
439 | } | ||
440 | |||
441 | @end | ||
442 | |||
443 | //////////////////////////////////////////////////////////// | ||
444 | |||
445 | #pragma mark - | ||
446 | #pragma mark TurnOffTiles | ||
447 | |||
448 | @implementation CCTurnOffTiles | ||
449 | |||
450 | +(id)actionWithSeed:(int)s grid:(ccGridSize)gridSize duration:(ccTime)d | ||
451 | { | ||
452 | return [[[self alloc] initWithSeed:s grid:gridSize duration:d] autorelease]; | ||
453 | } | ||
454 | |||
455 | -(id)initWithSeed:(int)s grid:(ccGridSize)gSize duration:(ccTime)d | ||
456 | { | ||
457 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
458 | { | ||
459 | seed = s; | ||
460 | tilesOrder = nil; | ||
461 | } | ||
462 | |||
463 | return self; | ||
464 | } | ||
465 | |||
466 | -(id) copyWithZone: (NSZone*) zone | ||
467 | { | ||
468 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithSeed:seed grid:gridSize_ duration:duration_]; | ||
469 | return copy; | ||
470 | } | ||
471 | |||
472 | -(void)dealloc | ||
473 | { | ||
474 | if ( tilesOrder ) free(tilesOrder); | ||
475 | [super dealloc]; | ||
476 | } | ||
477 | |||
478 | -(void)shuffle:(int*)array count:(NSUInteger)len | ||
479 | { | ||
480 | NSInteger i; | ||
481 | for( i = len - 1; i >= 0; i-- ) | ||
482 | { | ||
483 | NSInteger j = rand() % (i+1); | ||
484 | int v = array[i]; | ||
485 | array[i] = array[j]; | ||
486 | array[j] = v; | ||
487 | } | ||
488 | } | ||
489 | |||
490 | -(void)turnOnTile:(ccGridSize)pos | ||
491 | { | ||
492 | [self setTile:pos coords:[self originalTile:pos]]; | ||
493 | } | ||
494 | |||
495 | -(void)turnOffTile:(ccGridSize)pos | ||
496 | { | ||
497 | ccQuad3 coords; | ||
498 | |||
499 | bzero(&coords, sizeof(ccQuad3)); | ||
500 | [self setTile:pos coords:coords]; | ||
501 | } | ||
502 | |||
503 | -(void)startWithTarget:(id)aTarget | ||
504 | { | ||
505 | int i; | ||
506 | |||
507 | [super startWithTarget:aTarget]; | ||
508 | |||
509 | if ( seed != -1 ) | ||
510 | srand(seed); | ||
511 | |||
512 | tilesCount = gridSize_.x * gridSize_.y; | ||
513 | tilesOrder = (int*)malloc(tilesCount*sizeof(int)); | ||
514 | |||
515 | for( i = 0; i < tilesCount; i++ ) | ||
516 | tilesOrder[i] = i; | ||
517 | |||
518 | [self shuffle:tilesOrder count:tilesCount]; | ||
519 | } | ||
520 | |||
521 | -(void)update:(ccTime)time | ||
522 | { | ||
523 | int i, l, t; | ||
524 | |||
525 | l = (int)(time * (float)tilesCount); | ||
526 | |||
527 | for( i = 0; i < tilesCount; i++ ) | ||
528 | { | ||
529 | t = tilesOrder[i]; | ||
530 | ccGridSize tilePos = ccg( t / gridSize_.y, t % gridSize_.y ); | ||
531 | |||
532 | if ( i < l ) | ||
533 | [self turnOffTile:tilePos]; | ||
534 | else | ||
535 | [self turnOnTile:tilePos]; | ||
536 | } | ||
537 | } | ||
538 | |||
539 | @end | ||
540 | |||
541 | //////////////////////////////////////////////////////////// | ||
542 | |||
543 | #pragma mark - | ||
544 | #pragma mark CCWavesTiles3D | ||
545 | |||
546 | @implementation CCWavesTiles3D | ||
547 | |||
548 | @synthesize amplitude; | ||
549 | @synthesize amplitudeRate; | ||
550 | |||
551 | +(id)actionWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d | ||
552 | { | ||
553 | return [[[self alloc] initWithWaves:wav amplitude:amp grid:gridSize duration:d] autorelease]; | ||
554 | } | ||
555 | |||
556 | -(id)initWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gSize duration:(ccTime)d | ||
557 | { | ||
558 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
559 | { | ||
560 | waves = wav; | ||
561 | amplitude = amp; | ||
562 | amplitudeRate = 1.0f; | ||
563 | } | ||
564 | |||
565 | return self; | ||
566 | } | ||
567 | |||
568 | -(id) copyWithZone: (NSZone*) zone | ||
569 | { | ||
570 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithWaves:waves amplitude:amplitude grid:gridSize_ duration:duration_]; | ||
571 | return copy; | ||
572 | } | ||
573 | |||
574 | |||
575 | -(void)update:(ccTime)time | ||
576 | { | ||
577 | int i, j; | ||
578 | |||
579 | for( i = 0; i < gridSize_.x; i++ ) | ||
580 | { | ||
581 | for( j = 0; j < gridSize_.y; j++ ) | ||
582 | { | ||
583 | ccQuad3 coords = [self originalTile:ccg(i,j)]; | ||
584 | |||
585 | coords.bl.z = (sinf(time*(CGFloat)M_PI*waves*2 + (coords.bl.y+coords.bl.x) * .01f) * amplitude * amplitudeRate ); | ||
586 | coords.br.z = coords.bl.z; | ||
587 | coords.tl.z = coords.bl.z; | ||
588 | coords.tr.z = coords.bl.z; | ||
589 | |||
590 | [self setTile:ccg(i,j) coords:coords]; | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | @end | ||
595 | |||
596 | //////////////////////////////////////////////////////////// | ||
597 | |||
598 | #pragma mark - | ||
599 | #pragma mark CCJumpTiles3D | ||
600 | |||
601 | @implementation CCJumpTiles3D | ||
602 | |||
603 | @synthesize amplitude; | ||
604 | @synthesize amplitudeRate; | ||
605 | |||
606 | +(id)actionWithJumps:(int)j amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d | ||
607 | { | ||
608 | return [[[self alloc] initWithJumps:j amplitude:amp grid:gridSize duration:d] autorelease]; | ||
609 | } | ||
610 | |||
611 | -(id)initWithJumps:(int)j amplitude:(float)amp grid:(ccGridSize)gSize duration:(ccTime)d | ||
612 | { | ||
613 | if ( (self = [super initWithSize:gSize duration:d]) ) | ||
614 | { | ||
615 | jumps = j; | ||
616 | amplitude = amp; | ||
617 | amplitudeRate = 1.0f; | ||
618 | } | ||
619 | |||
620 | return self; | ||
621 | } | ||
622 | |||
623 | -(id) copyWithZone: (NSZone*) zone | ||
624 | { | ||
625 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithJumps:jumps amplitude:amplitude grid:gridSize_ duration:duration_]; | ||
626 | return copy; | ||
627 | } | ||
628 | |||
629 | |||
630 | -(void)update:(ccTime)time | ||
631 | { | ||
632 | int i, j; | ||
633 | |||
634 | float sinz = (sinf((CGFloat)M_PI*time*jumps*2) * amplitude * amplitudeRate ); | ||
635 | float sinz2 = (sinf((CGFloat)M_PI*(time*jumps*2 + 1)) * amplitude * amplitudeRate ); | ||
636 | |||
637 | for( i = 0; i < gridSize_.x; i++ ) | ||
638 | { | ||
639 | for( j = 0; j < gridSize_.y; j++ ) | ||
640 | { | ||
641 | ccQuad3 coords = [self originalTile:ccg(i,j)]; | ||
642 | |||
643 | if ( ((i+j) % 2) == 0 ) | ||
644 | { | ||
645 | coords.bl.z += sinz; | ||
646 | coords.br.z += sinz; | ||
647 | coords.tl.z += sinz; | ||
648 | coords.tr.z += sinz; | ||
649 | } | ||
650 | else | ||
651 | { | ||
652 | coords.bl.z += sinz2; | ||
653 | coords.br.z += sinz2; | ||
654 | coords.tl.z += sinz2; | ||
655 | coords.tr.z += sinz2; | ||
656 | } | ||
657 | |||
658 | [self setTile:ccg(i,j) coords:coords]; | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | @end | ||
663 | |||
664 | //////////////////////////////////////////////////////////// | ||
665 | |||
666 | #pragma mark - | ||
667 | #pragma mark SplitRows | ||
668 | |||
669 | @implementation CCSplitRows | ||
670 | |||
671 | +(id)actionWithRows:(int)r duration:(ccTime)d | ||
672 | { | ||
673 | return [[[self alloc] initWithRows:r duration:d] autorelease]; | ||
674 | } | ||
675 | |||
676 | -(id)initWithRows:(int)r duration:(ccTime)d | ||
677 | { | ||
678 | rows = r; | ||
679 | return [super initWithSize:ccg(1,r) duration:d]; | ||
680 | } | ||
681 | |||
682 | -(id) copyWithZone: (NSZone*) zone | ||
683 | { | ||
684 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithRows:rows duration:duration_]; | ||
685 | return copy; | ||
686 | } | ||
687 | |||
688 | -(void)startWithTarget:(id)aTarget | ||
689 | { | ||
690 | [super startWithTarget:aTarget]; | ||
691 | winSize = [[CCDirector sharedDirector] winSizeInPixels]; | ||
692 | } | ||
693 | |||
694 | -(void)update:(ccTime)time | ||
695 | { | ||
696 | int j; | ||
697 | |||
698 | for( j = 0; j < gridSize_.y; j++ ) | ||
699 | { | ||
700 | ccQuad3 coords = [self originalTile:ccg(0,j)]; | ||
701 | float direction = 1; | ||
702 | |||
703 | if ( (j % 2 ) == 0 ) | ||
704 | direction = -1; | ||
705 | |||
706 | coords.bl.x += direction * winSize.width * time; | ||
707 | coords.br.x += direction * winSize.width * time; | ||
708 | coords.tl.x += direction * winSize.width * time; | ||
709 | coords.tr.x += direction * winSize.width * time; | ||
710 | |||
711 | [self setTile:ccg(0,j) coords:coords]; | ||
712 | } | ||
713 | } | ||
714 | |||
715 | @end | ||
716 | |||
717 | //////////////////////////////////////////////////////////// | ||
718 | |||
719 | #pragma mark - | ||
720 | #pragma mark CCSplitCols | ||
721 | |||
722 | @implementation CCSplitCols | ||
723 | |||
724 | +(id)actionWithCols:(int)c duration:(ccTime)d | ||
725 | { | ||
726 | return [[[self alloc] initWithCols:c duration:d] autorelease]; | ||
727 | } | ||
728 | |||
729 | -(id)initWithCols:(int)c duration:(ccTime)d | ||
730 | { | ||
731 | cols = c; | ||
732 | return [super initWithSize:ccg(c,1) duration:d]; | ||
733 | } | ||
734 | |||
735 | -(id) copyWithZone: (NSZone*) zone | ||
736 | { | ||
737 | CCGridAction *copy = [[[self class] allocWithZone:zone] initWithCols:cols duration:duration_]; | ||
738 | return copy; | ||
739 | } | ||
740 | |||
741 | -(void)startWithTarget:(id)aTarget | ||
742 | { | ||
743 | [super startWithTarget:aTarget]; | ||
744 | winSize = [[CCDirector sharedDirector] winSizeInPixels]; | ||
745 | } | ||
746 | |||
747 | -(void)update:(ccTime)time | ||
748 | { | ||
749 | int i; | ||
750 | |||
751 | for( i = 0; i < gridSize_.x; i++ ) | ||
752 | { | ||
753 | ccQuad3 coords = [self originalTile:ccg(i,0)]; | ||
754 | float direction = 1; | ||
755 | |||
756 | if ( (i % 2 ) == 0 ) | ||
757 | direction = -1; | ||
758 | |||
759 | coords.bl.y += direction * winSize.height * time; | ||
760 | coords.br.y += direction * winSize.height * time; | ||
761 | coords.tl.y += direction * winSize.height * time; | ||
762 | coords.tr.y += direction * winSize.height * time; | ||
763 | |||
764 | [self setTile:ccg(i,0) coords:coords]; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | @end | ||
diff --git a/libs/cocos2d/CCActionTween.h b/libs/cocos2d/CCActionTween.h new file mode 100755 index 0000000..69fdea5 --- /dev/null +++ b/libs/cocos2d/CCActionTween.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright 2009 lhunath (Maarten Billemont) | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import <Foundation/Foundation.h> | ||
28 | #import "CCActionInterval.h" | ||
29 | |||
30 | /** CCActionTween | ||
31 | |||
32 | CCActionTween is an action that lets you update any property of an object. | ||
33 | For example, if you want to modify the "width" property of a target from 200 to 300 in 2 senconds, then: | ||
34 | |||
35 | id modifyWidth = [CCActionTween actionWithDuration:2 key:@"width" from:200 to:300]; | ||
36 | [target runAction:modifyWidth]; | ||
37 | |||
38 | |||
39 | Another example: CCScaleTo action could be rewriten using CCPropertyAction: | ||
40 | |||
41 | // scaleA and scaleB are equivalents | ||
42 | id scaleA = [CCScaleTo actionWithDuration:2 scale:3]; | ||
43 | id scaleB = [CCActionTween actionWithDuration:2 key:@"scale" from:1 to:3]; | ||
44 | |||
45 | |||
46 | @since v0.99.2 | ||
47 | */ | ||
48 | @interface CCActionTween : CCActionInterval | ||
49 | { | ||
50 | NSString *key_; | ||
51 | |||
52 | float from_, to_; | ||
53 | float delta_; | ||
54 | } | ||
55 | |||
56 | /** creates an initializes the action with the property name (key), and the from and to parameters. */ | ||
57 | + (id)actionWithDuration:(ccTime)aDuration key:(NSString *)key from:(float)from to:(float)to; | ||
58 | |||
59 | /** initializes the action with the property name (key), and the from and to parameters. */ | ||
60 | - (id)initWithDuration:(ccTime)aDuration key:(NSString *)key from:(float)from to:(float)to; | ||
61 | |||
62 | @end | ||
diff --git a/libs/cocos2d/CCActionTween.m b/libs/cocos2d/CCActionTween.m new file mode 100755 index 0000000..95ae572 --- /dev/null +++ b/libs/cocos2d/CCActionTween.m | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright 2009 lhunath (Maarten Billemont) | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import "CCActionTween.h" | ||
27 | |||
28 | |||
29 | @implementation CCActionTween | ||
30 | |||
31 | + (id)actionWithDuration:(ccTime)aDuration key:(NSString *)aKey from:(float)aFrom to:(float)aTo { | ||
32 | |||
33 | return [[[[self class] alloc] initWithDuration:aDuration key:aKey from:aFrom to:aTo] autorelease]; | ||
34 | } | ||
35 | |||
36 | - (id)initWithDuration:(ccTime)aDuration key:(NSString *)key from:(float)from to:(float)to { | ||
37 | |||
38 | if ((self = [super initWithDuration:aDuration])) { | ||
39 | |||
40 | key_ = [key copy]; | ||
41 | to_ = to; | ||
42 | from_ = from; | ||
43 | |||
44 | } | ||
45 | |||
46 | return self; | ||
47 | } | ||
48 | |||
49 | - (void) dealloc | ||
50 | { | ||
51 | [key_ release]; | ||
52 | [super dealloc]; | ||
53 | } | ||
54 | |||
55 | - (void)startWithTarget:aTarget | ||
56 | { | ||
57 | [super startWithTarget:aTarget]; | ||
58 | delta_ = to_ - from_; | ||
59 | } | ||
60 | |||
61 | - (void) update:(ccTime) dt | ||
62 | { | ||
63 | [target_ setValue:[NSNumber numberWithFloat:to_ - delta_ * (1 - dt)] forKey:key_]; | ||
64 | } | ||
65 | |||
66 | - (CCActionInterval *) reverse | ||
67 | { | ||
68 | return [[self class] actionWithDuration:duration_ key:key_ from:to_ to:from_]; | ||
69 | } | ||
70 | |||
71 | |||
72 | @end | ||
diff --git a/libs/cocos2d/CCAnimation.h b/libs/cocos2d/CCAnimation.h new file mode 100755 index 0000000..24b3d96 --- /dev/null +++ b/libs/cocos2d/CCAnimation.h | |||
@@ -0,0 +1,136 @@ | |||
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 | #import <Foundation/Foundation.h> | ||
28 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
29 | #import <CoreGraphics/CoreGraphics.h> | ||
30 | #endif // IPHONE | ||
31 | |||
32 | @class CCSpriteFrame; | ||
33 | @class CCTexture2D; | ||
34 | |||
35 | /** A CCAnimation object is used to perform animations on the CCSprite objects. | ||
36 | |||
37 | The CCAnimation object contains CCSpriteFrame objects, and a possible delay between the frames. | ||
38 | You can animate a CCAnimation object by using the CCAnimate action. Example: | ||
39 | |||
40 | [sprite runAction:[CCAnimate actionWithAnimation:animation]]; | ||
41 | |||
42 | */ | ||
43 | @interface CCAnimation : NSObject | ||
44 | { | ||
45 | NSString *name_; | ||
46 | float delay_; | ||
47 | NSMutableArray *frames_; | ||
48 | } | ||
49 | |||
50 | /** name of the animation */ | ||
51 | @property (nonatomic,readwrite,retain) NSString *name; | ||
52 | /** delay between frames in seconds. */ | ||
53 | @property (nonatomic,readwrite,assign) float delay; | ||
54 | /** array of frames */ | ||
55 | @property (nonatomic,readwrite,retain) NSMutableArray *frames; | ||
56 | |||
57 | /** Creates an animation | ||
58 | @since v0.99.5 | ||
59 | */ | ||
60 | +(id) animation; | ||
61 | |||
62 | /** Creates an animation with frames. | ||
63 | @since v0.99.5 | ||
64 | */ | ||
65 | +(id) animationWithFrames:(NSArray*)frames; | ||
66 | |||
67 | /* Creates an animation with frames and a delay between frames. | ||
68 | @since v0.99.5 | ||
69 | */ | ||
70 | +(id) animationWithFrames:(NSArray*)frames delay:(float)delay; | ||
71 | |||
72 | /** Creates a CCAnimation with a name | ||
73 | @since v0.99.3 | ||
74 | @deprecated Will be removed in 1.0.1. Use "animation" instead. | ||
75 | */ | ||
76 | +(id) animationWithName:(NSString*)name DEPRECATED_ATTRIBUTE; | ||
77 | |||
78 | /** Creates a CCAnimation with a name and frames | ||
79 | @since v0.99.3 | ||
80 | @deprecated Will be removed in 1.0.1. Use "animationWithFrames" instead. | ||
81 | */ | ||
82 | +(id) animationWithName:(NSString*)name frames:(NSArray*)frames DEPRECATED_ATTRIBUTE; | ||
83 | |||
84 | /** Creates a CCAnimation with a name and delay between frames. */ | ||
85 | +(id) animationWithName:(NSString*)name delay:(float)delay DEPRECATED_ATTRIBUTE; | ||
86 | |||
87 | /** Creates a CCAnimation with a name, delay and an array of CCSpriteFrames. */ | ||
88 | +(id) animationWithName:(NSString*)name delay:(float)delay frames:(NSArray*)frames DEPRECATED_ATTRIBUTE; | ||
89 | |||
90 | |||
91 | /** Initializes a CCAnimation with frames. | ||
92 | @since v0.99.5 | ||
93 | */ | ||
94 | -(id) initWithFrames:(NSArray*)frames; | ||
95 | |||
96 | /** Initializes a CCAnimation with frames and a delay between frames | ||
97 | @since v0.99.5 | ||
98 | */ | ||
99 | -(id) initWithFrames:(NSArray *)frames delay:(float)delay; | ||
100 | |||
101 | /** Initializes a CCAnimation with a name | ||
102 | @since v0.99.3 | ||
103 | @deprecated Will be removed in 1.0.1. Use "init" instead. | ||
104 | */ | ||
105 | -(id) initWithName:(NSString*)name DEPRECATED_ATTRIBUTE; | ||
106 | |||
107 | /** Initializes a CCAnimation with a name and frames | ||
108 | @since v0.99.3 | ||
109 | @deprecated Will be removed in 1.0.1. Use "initWithFrames" instead. | ||
110 | */ | ||
111 | -(id) initWithName:(NSString*)name frames:(NSArray*)frames DEPRECATED_ATTRIBUTE; | ||
112 | |||
113 | /** Initializes a CCAnimation with a name and delay between frames. | ||
114 | @deprecated Will be removed in 1.0.1. Use "initWithFrames:nil delay:delay" instead. | ||
115 | */ | ||
116 | -(id) initWithName:(NSString*)name delay:(float)delay DEPRECATED_ATTRIBUTE; | ||
117 | |||
118 | /** Initializes a CCAnimation with a name, delay and an array of CCSpriteFrames. | ||
119 | @deprecated Will be removed in 1.0.1. Use "initWithFrames:frames delay:delay" instead. | ||
120 | */ | ||
121 | -(id) initWithName:(NSString*)name delay:(float)delay frames:(NSArray*)frames DEPRECATED_ATTRIBUTE; | ||
122 | |||
123 | /** Adds a frame to a CCAnimation. */ | ||
124 | -(void) addFrame:(CCSpriteFrame*)frame; | ||
125 | |||
126 | /** Adds a frame with an image filename. Internally it will create a CCSpriteFrame and it will add it. | ||
127 | Added to facilitate the migration from v0.8 to v0.9. | ||
128 | */ | ||
129 | -(void) addFrameWithFilename:(NSString*)filename; | ||
130 | |||
131 | /** Adds a frame with a texture and a rect. Internally it will create a CCSpriteFrame and it will add it. | ||
132 | Added to facilitate the migration from v0.8 to v0.9. | ||
133 | */ | ||
134 | -(void) addFrameWithTexture:(CCTexture2D*)texture rect:(CGRect)rect; | ||
135 | |||
136 | @end | ||
diff --git a/libs/cocos2d/CCAnimation.m b/libs/cocos2d/CCAnimation.m new file mode 100755 index 0000000..eb674c6 --- /dev/null +++ b/libs/cocos2d/CCAnimation.m | |||
@@ -0,0 +1,153 @@ | |||
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 | #import "ccMacros.h" | ||
28 | #import "CCAnimation.h" | ||
29 | #import "CCSpriteFrame.h" | ||
30 | #import "CCTexture2D.h" | ||
31 | #import "CCTextureCache.h" | ||
32 | |||
33 | @implementation CCAnimation | ||
34 | @synthesize name = name_, delay = delay_, frames = frames_; | ||
35 | |||
36 | +(id) animation | ||
37 | { | ||
38 | return [[[self alloc] init] autorelease]; | ||
39 | } | ||
40 | |||
41 | +(id) animationWithFrames:(NSArray*)frames | ||
42 | { | ||
43 | return [[[self alloc] initWithFrames:frames] autorelease]; | ||
44 | } | ||
45 | |||
46 | +(id) animationWithFrames:(NSArray*)frames delay:(float)delay | ||
47 | { | ||
48 | return [[[self alloc] initWithFrames:frames delay:delay] autorelease]; | ||
49 | } | ||
50 | |||
51 | +(id) animationWithName:(NSString*)name | ||
52 | { | ||
53 | return [[[self alloc] initWithName:name] autorelease]; | ||
54 | } | ||
55 | |||
56 | +(id) animationWithName:(NSString*)name frames:(NSArray*)frames | ||
57 | { | ||
58 | return [[[self alloc] initWithName:name frames:frames] autorelease]; | ||
59 | } | ||
60 | |||
61 | +(id) animationWithName:(NSString*)aname delay:(float)d frames:(NSArray*)array | ||
62 | { | ||
63 | return [[[self alloc] initWithName:aname delay:d frames:array] autorelease]; | ||
64 | } | ||
65 | |||
66 | +(id) animationWithName:(NSString*)aname delay:(float)d | ||
67 | { | ||
68 | return [[[self alloc] initWithName:aname delay:d] autorelease]; | ||
69 | } | ||
70 | |||
71 | -(id) init | ||
72 | { | ||
73 | return [self initWithFrames:nil delay:0]; | ||
74 | } | ||
75 | |||
76 | -(id) initWithFrames:(NSArray*)frames | ||
77 | { | ||
78 | return [self initWithFrames:frames delay:0]; | ||
79 | } | ||
80 | |||
81 | -(id) initWithFrames:(NSArray*)array delay:(float)delay | ||
82 | { | ||
83 | if( (self=[super init]) ) { | ||
84 | |||
85 | delay_ = delay; | ||
86 | self.frames = [NSMutableArray arrayWithArray:array]; | ||
87 | } | ||
88 | return self; | ||
89 | } | ||
90 | |||
91 | -(id) initWithName:(NSString*)name | ||
92 | { | ||
93 | return [self initWithName:name delay:0 frames:nil]; | ||
94 | } | ||
95 | |||
96 | -(id) initWithName:(NSString*)name frames:(NSArray*)frames | ||
97 | { | ||
98 | return [self initWithName:name delay:0 frames:frames]; | ||
99 | } | ||
100 | |||
101 | -(id) initWithName:(NSString*)t delay:(float)d | ||
102 | { | ||
103 | return [self initWithName:t delay:d frames:nil]; | ||
104 | } | ||
105 | |||
106 | -(id) initWithName:(NSString*)name delay:(float)delay frames:(NSArray*)array | ||
107 | { | ||
108 | if( (self=[super init]) ) { | ||
109 | |||
110 | delay_ = delay; | ||
111 | self.name = name; | ||
112 | self.frames = [NSMutableArray arrayWithArray:array]; | ||
113 | } | ||
114 | return self; | ||
115 | } | ||
116 | |||
117 | - (NSString*) description | ||
118 | { | ||
119 | return [NSString stringWithFormat:@"<%@ = %08X | frames=%d, delay:%f>", [self class], self, | ||
120 | [frames_ count], | ||
121 | delay_ | ||
122 | ]; | ||
123 | } | ||
124 | |||
125 | -(void) dealloc | ||
126 | { | ||
127 | CCLOGINFO( @"cocos2d: deallocing %@",self); | ||
128 | [name_ release]; | ||
129 | [frames_ release]; | ||
130 | [super dealloc]; | ||
131 | } | ||
132 | |||
133 | -(void) addFrame:(CCSpriteFrame*)frame | ||
134 | { | ||
135 | [frames_ addObject:frame]; | ||
136 | } | ||
137 | |||
138 | -(void) addFrameWithFilename:(NSString*)filename | ||
139 | { | ||
140 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage:filename]; | ||
141 | CGRect rect = CGRectZero; | ||
142 | rect.size = texture.contentSize; | ||
143 | CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:texture rect:rect]; | ||
144 | [frames_ addObject:frame]; | ||
145 | } | ||
146 | |||
147 | -(void) addFrameWithTexture:(CCTexture2D*)texture rect:(CGRect)rect | ||
148 | { | ||
149 | CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:texture rect:rect]; | ||
150 | [frames_ addObject:frame]; | ||
151 | } | ||
152 | |||
153 | @end | ||
diff --git a/libs/cocos2d/CCAnimationCache.h b/libs/cocos2d/CCAnimationCache.h new file mode 100755 index 0000000..075c836 --- /dev/null +++ b/libs/cocos2d/CCAnimationCache.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | #import <Foundation/Foundation.h> | ||
28 | |||
29 | @class CCAnimation; | ||
30 | |||
31 | /** Singleton that manages the Animations. | ||
32 | It saves in a cache the animations. You should use this class if you want to save your animations in a cache. | ||
33 | |||
34 | Before v0.99.5, the recommend way was to save them on the CCSprite. Since v0.99.5, you should use this class instead. | ||
35 | |||
36 | @since v0.99.5 | ||
37 | */ | ||
38 | @interface CCAnimationCache : NSObject | ||
39 | { | ||
40 | NSMutableDictionary *animations_; | ||
41 | } | ||
42 | |||
43 | /** Retruns ths shared instance of the Animation cache */ | ||
44 | + (CCAnimationCache *) sharedAnimationCache; | ||
45 | |||
46 | /** Purges the cache. It releases all the CCAnimation objects and the shared instance. | ||
47 | */ | ||
48 | +(void)purgeSharedAnimationCache; | ||
49 | |||
50 | /** Adds a CCAnimation with a name. | ||
51 | */ | ||
52 | -(void) addAnimation:(CCAnimation*)animation name:(NSString*)name; | ||
53 | |||
54 | /** Deletes a CCAnimation from the cache. | ||
55 | */ | ||
56 | -(void) removeAnimationByName:(NSString*)name; | ||
57 | |||
58 | /** Returns a CCAnimation that was previously added. | ||
59 | If the name is not found it will return nil. | ||
60 | You should retain the returned copy if you are going to use it. | ||
61 | */ | ||
62 | -(CCAnimation*) animationByName:(NSString*)name; | ||
63 | |||
64 | @end | ||
diff --git a/libs/cocos2d/CCAnimationCache.m b/libs/cocos2d/CCAnimationCache.m new file mode 100755 index 0000000..f508227 --- /dev/null +++ b/libs/cocos2d/CCAnimationCache.m | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | #import "ccMacros.h" | ||
28 | #import "CCAnimationCache.h" | ||
29 | #import "CCAnimation.h" | ||
30 | #import "CCSprite.h" | ||
31 | |||
32 | |||
33 | @implementation CCAnimationCache | ||
34 | |||
35 | #pragma mark CCAnimationCache - Alloc, Init & Dealloc | ||
36 | |||
37 | static CCAnimationCache *sharedAnimationCache_=nil; | ||
38 | |||
39 | + (CCAnimationCache *)sharedAnimationCache | ||
40 | { | ||
41 | if (!sharedAnimationCache_) | ||
42 | sharedAnimationCache_ = [[CCAnimationCache alloc] init]; | ||
43 | |||
44 | return sharedAnimationCache_; | ||
45 | } | ||
46 | |||
47 | +(id)alloc | ||
48 | { | ||
49 | NSAssert(sharedAnimationCache_ == nil, @"Attempted to allocate a second instance of a singleton."); | ||
50 | return [super alloc]; | ||
51 | } | ||
52 | |||
53 | +(void)purgeSharedAnimationCache | ||
54 | { | ||
55 | [sharedAnimationCache_ release]; | ||
56 | sharedAnimationCache_ = nil; | ||
57 | } | ||
58 | |||
59 | -(id) init | ||
60 | { | ||
61 | if( (self=[super init]) ) { | ||
62 | animations_ = [[NSMutableDictionary alloc] initWithCapacity: 20]; | ||
63 | } | ||
64 | |||
65 | return self; | ||
66 | } | ||
67 | |||
68 | - (NSString*) description | ||
69 | { | ||
70 | return [NSString stringWithFormat:@"<%@ = %08X | num of animations = %i>", [self class], self, [animations_ count]]; | ||
71 | } | ||
72 | |||
73 | -(void) dealloc | ||
74 | { | ||
75 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
76 | |||
77 | [animations_ release]; | ||
78 | [super dealloc]; | ||
79 | } | ||
80 | |||
81 | #pragma mark CCAnimationCache - load/get/del | ||
82 | |||
83 | -(void) addAnimation:(CCAnimation*)animation name:(NSString*)name | ||
84 | { | ||
85 | [animations_ setObject:animation forKey:name]; | ||
86 | } | ||
87 | |||
88 | -(void) removeAnimationByName:(NSString*)name | ||
89 | { | ||
90 | if( ! name ) | ||
91 | return; | ||
92 | |||
93 | [animations_ removeObjectForKey:name]; | ||
94 | } | ||
95 | |||
96 | -(CCAnimation*) animationByName:(NSString*)name | ||
97 | { | ||
98 | return [animations_ objectForKey:name]; | ||
99 | } | ||
100 | |||
101 | @end | ||
diff --git a/libs/cocos2d/CCAtlasNode.h b/libs/cocos2d/CCAtlasNode.h new file mode 100755 index 0000000..43e57c2 --- /dev/null +++ b/libs/cocos2d/CCAtlasNode.h | |||
@@ -0,0 +1,93 @@ | |||
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 | * | ||
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
9 | * of this software and associated documentation files (the "Software"), to deal | ||
10 | * in the Software without restriction, including without limitation the rights | ||
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
12 | * copies of the Software, and to permit persons to whom the Software is | ||
13 | * furnished to do so, subject to the following conditions: | ||
14 | * | ||
15 | * The above copyright notice and this permission notice shall be included in | ||
16 | * all copies or substantial portions of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
24 | * THE SOFTWARE. | ||
25 | */ | ||
26 | |||
27 | |||
28 | #import "CCTextureAtlas.h" | ||
29 | #import "CCNode.h" | ||
30 | #import "CCProtocols.h" | ||
31 | |||
32 | /** CCAtlasNode is a subclass of CCNode that implements the CCRGBAProtocol and | ||
33 | CCTextureProtocol protocol | ||
34 | |||
35 | It knows how to render a TextureAtlas object. | ||
36 | If you are going to render a TextureAtlas consider subclassing CCAtlasNode (or a subclass of CCAtlasNode) | ||
37 | |||
38 | All features from CCNode are valid, plus the following features: | ||
39 | - opacity and RGB colors | ||
40 | */ | ||
41 | @interface CCAtlasNode : CCNode <CCRGBAProtocol, CCTextureProtocol> | ||
42 | { | ||
43 | // texture atlas | ||
44 | CCTextureAtlas *textureAtlas_; | ||
45 | |||
46 | // chars per row | ||
47 | NSUInteger itemsPerRow_; | ||
48 | // chars per column | ||
49 | NSUInteger itemsPerColumn_; | ||
50 | |||
51 | // width of each char | ||
52 | NSUInteger itemWidth_; | ||
53 | // height of each char | ||
54 | NSUInteger itemHeight_; | ||
55 | |||
56 | // quads to draw | ||
57 | NSUInteger quadsToDraw_; | ||
58 | |||
59 | // blend function | ||
60 | ccBlendFunc blendFunc_; | ||
61 | |||
62 | // texture RGBA. | ||
63 | GLubyte opacity_; | ||
64 | ccColor3B color_; | ||
65 | ccColor3B colorUnmodified_; | ||
66 | BOOL opacityModifyRGB_; | ||
67 | } | ||
68 | |||
69 | /** conforms to CCTextureProtocol protocol */ | ||
70 | @property (nonatomic,readwrite,retain) CCTextureAtlas *textureAtlas; | ||
71 | |||
72 | /** conforms to CCTextureProtocol protocol */ | ||
73 | @property (nonatomic,readwrite) ccBlendFunc blendFunc; | ||
74 | |||
75 | /** conforms to CCRGBAProtocol protocol */ | ||
76 | @property (nonatomic,readwrite) GLubyte opacity; | ||
77 | /** conforms to CCRGBAProtocol protocol */ | ||
78 | @property (nonatomic,readwrite) ccColor3B color; | ||
79 | |||
80 | /** how many quads to draw */ | ||
81 | @property (readwrite) NSUInteger quadsToDraw; | ||
82 | |||
83 | /** creates a CCAtlasNode with an Atlas file the width and height of each item measured in points and the quantity of items to render*/ | ||
84 | +(id) atlasWithTileFile:(NSString*)tile tileWidth:(NSUInteger)w tileHeight:(NSUInteger)h itemsToRender: (NSUInteger) c; | ||
85 | |||
86 | /** initializes an CCAtlasNode with an Atlas file the width and height of each item measured in points and the quantity of items to render*/ | ||
87 | -(id) initWithTileFile:(NSString*)tile tileWidth:(NSUInteger)w tileHeight:(NSUInteger)h itemsToRender: (NSUInteger) c; | ||
88 | |||
89 | /** updates the Atlas (indexed vertex array). | ||
90 | * Shall be overriden in subclasses | ||
91 | */ | ||
92 | -(void) updateAtlasValues; | ||
93 | @end | ||
diff --git a/libs/cocos2d/CCAtlasNode.m b/libs/cocos2d/CCAtlasNode.m new file mode 100755 index 0000000..3f44633 --- /dev/null +++ b/libs/cocos2d/CCAtlasNode.m | |||
@@ -0,0 +1,211 @@ | |||
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 | #import "CCAtlasNode.h" | ||
28 | #import "ccMacros.h" | ||
29 | |||
30 | |||
31 | @interface CCAtlasNode () | ||
32 | -(void) calculateMaxItems; | ||
33 | -(void) updateBlendFunc; | ||
34 | -(void) updateOpacityModifyRGB; | ||
35 | @end | ||
36 | |||
37 | @implementation CCAtlasNode | ||
38 | |||
39 | @synthesize textureAtlas = textureAtlas_; | ||
40 | @synthesize blendFunc = blendFunc_; | ||
41 | @synthesize quadsToDraw = quadsToDraw_; | ||
42 | |||
43 | #pragma mark CCAtlasNode - Creation & Init | ||
44 | +(id) atlasWithTileFile:(NSString*)tile tileWidth:(NSUInteger)w tileHeight:(NSUInteger)h itemsToRender: (NSUInteger) c | ||
45 | { | ||
46 | return [[[self alloc] initWithTileFile:tile tileWidth:w tileHeight:h itemsToRender:c] autorelease]; | ||
47 | } | ||
48 | |||
49 | -(id) initWithTileFile:(NSString*)tile tileWidth:(NSUInteger)w tileHeight:(NSUInteger)h itemsToRender: (NSUInteger) c | ||
50 | { | ||
51 | if( (self=[super init]) ) { | ||
52 | |||
53 | itemWidth_ = w * CC_CONTENT_SCALE_FACTOR(); | ||
54 | itemHeight_ = h * CC_CONTENT_SCALE_FACTOR(); | ||
55 | |||
56 | opacity_ = 255; | ||
57 | color_ = colorUnmodified_ = ccWHITE; | ||
58 | opacityModifyRGB_ = YES; | ||
59 | |||
60 | blendFunc_.src = CC_BLEND_SRC; | ||
61 | blendFunc_.dst = CC_BLEND_DST; | ||
62 | |||
63 | // double retain to avoid the autorelease pool | ||
64 | // also, using: self.textureAtlas supports re-initialization without leaking | ||
65 | self.textureAtlas = [[CCTextureAtlas alloc] initWithFile:tile capacity:c]; | ||
66 | [textureAtlas_ release]; | ||
67 | |||
68 | if( ! textureAtlas_ ) { | ||
69 | CCLOG(@"cocos2d: Could not initialize CCAtlasNode. Invalid Texture"); | ||
70 | [self release]; | ||
71 | return nil; | ||
72 | } | ||
73 | |||
74 | [self updateBlendFunc]; | ||
75 | [self updateOpacityModifyRGB]; | ||
76 | |||
77 | [self calculateMaxItems]; | ||
78 | |||
79 | self.quadsToDraw = c; | ||
80 | |||
81 | } | ||
82 | return self; | ||
83 | } | ||
84 | |||
85 | -(void) dealloc | ||
86 | { | ||
87 | [textureAtlas_ release]; | ||
88 | |||
89 | [super dealloc]; | ||
90 | } | ||
91 | |||
92 | #pragma mark CCAtlasNode - Atlas generation | ||
93 | |||
94 | -(void) calculateMaxItems | ||
95 | { | ||
96 | CGSize s = [[textureAtlas_ texture] contentSizeInPixels]; | ||
97 | itemsPerColumn_ = s.height / itemHeight_; | ||
98 | itemsPerRow_ = s.width / itemWidth_; | ||
99 | } | ||
100 | |||
101 | -(void) updateAtlasValues | ||
102 | { | ||
103 | [NSException raise:@"CCAtlasNode:Abstract" format:@"updateAtlasValue not overriden"]; | ||
104 | } | ||
105 | |||
106 | #pragma mark CCAtlasNode - draw | ||
107 | - (void) draw | ||
108 | { | ||
109 | [super draw]; | ||
110 | |||
111 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
112 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
113 | // Unneeded states: GL_COLOR_ARRAY | ||
114 | glDisableClientState(GL_COLOR_ARRAY); | ||
115 | |||
116 | glColor4ub( color_.r, color_.g, color_.b, opacity_); | ||
117 | |||
118 | BOOL newBlend = blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST; | ||
119 | if( newBlend ) | ||
120 | glBlendFunc( blendFunc_.src, blendFunc_.dst ); | ||
121 | |||
122 | [textureAtlas_ drawNumberOfQuads:quadsToDraw_ fromIndex:0]; | ||
123 | |||
124 | if( newBlend ) | ||
125 | glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); | ||
126 | |||
127 | // is this chepear than saving/restoring color state ? | ||
128 | // XXX: There is no need to restore the color to (255,255,255,255). Objects should use the color | ||
129 | // XXX: that they need | ||
130 | // glColor4ub( 255, 255, 255, 255); | ||
131 | |||
132 | // restore default GL state | ||
133 | glEnableClientState(GL_COLOR_ARRAY); | ||
134 | |||
135 | } | ||
136 | |||
137 | #pragma mark CCAtlasNode - RGBA protocol | ||
138 | |||
139 | - (ccColor3B) color | ||
140 | { | ||
141 | if(opacityModifyRGB_) | ||
142 | return colorUnmodified_; | ||
143 | |||
144 | return color_; | ||
145 | } | ||
146 | |||
147 | -(void) setColor:(ccColor3B)color3 | ||
148 | { | ||
149 | color_ = colorUnmodified_ = color3; | ||
150 | |||
151 | if( opacityModifyRGB_ ){ | ||
152 | color_.r = color3.r * opacity_/255; | ||
153 | color_.g = color3.g * opacity_/255; | ||
154 | color_.b = color3.b * opacity_/255; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | -(GLubyte) opacity | ||
159 | { | ||
160 | return opacity_; | ||
161 | } | ||
162 | |||
163 | -(void) setOpacity:(GLubyte) anOpacity | ||
164 | { | ||
165 | opacity_ = anOpacity; | ||
166 | |||
167 | // special opacity for premultiplied textures | ||
168 | if( opacityModifyRGB_ ) | ||
169 | [self setColor: colorUnmodified_]; | ||
170 | } | ||
171 | |||
172 | -(void) setOpacityModifyRGB:(BOOL)modify | ||
173 | { | ||
174 | ccColor3B oldColor = self.color; | ||
175 | opacityModifyRGB_ = modify; | ||
176 | self.color = oldColor; | ||
177 | } | ||
178 | |||
179 | -(BOOL) doesOpacityModifyRGB | ||
180 | { | ||
181 | return opacityModifyRGB_; | ||
182 | } | ||
183 | |||
184 | -(void) updateOpacityModifyRGB | ||
185 | { | ||
186 | opacityModifyRGB_ = [textureAtlas_.texture hasPremultipliedAlpha]; | ||
187 | } | ||
188 | |||
189 | #pragma mark CCAtlasNode - CocosNodeTexture protocol | ||
190 | |||
191 | -(void) updateBlendFunc | ||
192 | { | ||
193 | if( ! [textureAtlas_.texture hasPremultipliedAlpha] ) { | ||
194 | blendFunc_.src = GL_SRC_ALPHA; | ||
195 | blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | -(void) setTexture:(CCTexture2D*)texture | ||
200 | { | ||
201 | textureAtlas_.texture = texture; | ||
202 | [self updateBlendFunc]; | ||
203 | [self updateOpacityModifyRGB]; | ||
204 | } | ||
205 | |||
206 | -(CCTexture2D*) texture | ||
207 | { | ||
208 | return textureAtlas_.texture; | ||
209 | } | ||
210 | |||
211 | @end | ||
diff --git a/libs/cocos2d/CCBlockSupport.h b/libs/cocos2d/CCBlockSupport.h new file mode 100755 index 0000000..339d5aa --- /dev/null +++ b/libs/cocos2d/CCBlockSupport.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Stuart Carnie | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import <Foundation/Foundation.h> | ||
28 | |||
29 | /** @file | ||
30 | cocos2d blocks support | ||
31 | */ | ||
32 | |||
33 | // To comply with Apple Objective C runtime (this is defined in NSObjCRuntime.h) | ||
34 | #if !defined(NS_BLOCKS_AVAILABLE) | ||
35 | #if __BLOCKS__ | ||
36 | #define NS_BLOCKS_AVAILABLE 1 | ||
37 | #else | ||
38 | #define NS_BLOCKS_AVAILABLE 0 | ||
39 | #endif | ||
40 | #endif | ||
41 | |||
42 | #if NS_BLOCKS_AVAILABLE | ||
43 | |||
44 | @interface NSObject(CCBlocksAdditions) | ||
45 | |||
46 | - (void)ccCallbackBlock; | ||
47 | - (void)ccCallbackBlockWithSender:(id)sender; | ||
48 | |||
49 | @end | ||
50 | |||
51 | #endif // NS_BLOCKS_AVAILABLE | ||
diff --git a/libs/cocos2d/CCBlockSupport.m b/libs/cocos2d/CCBlockSupport.m new file mode 100755 index 0000000..9ac99b3 --- /dev/null +++ b/libs/cocos2d/CCBlockSupport.m | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Stuart Carnie | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCBlockSupport.h" | ||
28 | |||
29 | #if NS_BLOCKS_AVAILABLE | ||
30 | |||
31 | @implementation NSObject(CCBlocksAdditions) | ||
32 | |||
33 | - (void)ccCallbackBlock { | ||
34 | void (^block)(void) = (id)self; | ||
35 | block(); | ||
36 | } | ||
37 | |||
38 | - (void)ccCallbackBlockWithSender:(id)sender { | ||
39 | void (^block)(id) = (id)self; | ||
40 | block(sender); | ||
41 | } | ||
42 | |||
43 | |||
44 | @end | ||
45 | |||
46 | #endif | ||
diff --git a/libs/cocos2d/CCCamera.h b/libs/cocos2d/CCCamera.h new file mode 100755 index 0000000..19a7712 --- /dev/null +++ b/libs/cocos2d/CCCamera.h | |||
@@ -0,0 +1,95 @@ | |||
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 | #import "CCNode.h" | ||
29 | |||
30 | /** | ||
31 | A CCCamera is used in every CCNode. | ||
32 | Useful to look at the object from different views. | ||
33 | The OpenGL gluLookAt() function is used to locate the | ||
34 | camera. | ||
35 | |||
36 | If the object is transformed by any of the scale, rotation or | ||
37 | position attributes, then they will override the camera. | ||
38 | |||
39 | IMPORTANT: Either your use the camera or the rotation/scale/position properties. You can't use both. | ||
40 | World coordinates won't work if you use the camera. | ||
41 | |||
42 | Limitations: | ||
43 | |||
44 | - Some nodes, like CCParallaxNode, CCParticle uses world node coordinates, and they won't work properly if you move them (or any of their ancestors) | ||
45 | using the camera. | ||
46 | |||
47 | - It doesn't work on batched nodes like CCSprite objects when they are parented to a CCSpriteBatchNode object. | ||
48 | |||
49 | - It is recommended to use it ONLY if you are going to create 3D effects. For 2D effecs, use the action CCFollow or position/scale/rotate. | ||
50 | |||
51 | */ | ||
52 | |||
53 | @interface CCCamera : NSObject | ||
54 | { | ||
55 | float eyeX_; | ||
56 | float eyeY_; | ||
57 | float eyeZ_; | ||
58 | |||
59 | float centerX_; | ||
60 | float centerY_; | ||
61 | float centerZ_; | ||
62 | |||
63 | float upX_; | ||
64 | float upY_; | ||
65 | float upZ_; | ||
66 | |||
67 | BOOL dirty_; | ||
68 | } | ||
69 | |||
70 | /** whether of not the camera is dirty */ | ||
71 | @property (nonatomic,readwrite) BOOL dirty; | ||
72 | |||
73 | /** returns the Z eye */ | ||
74 | +(float) getZEye; | ||
75 | |||
76 | /** sets the camera in the defaul position */ | ||
77 | -(void) restore; | ||
78 | /** Sets the camera using gluLookAt using its eye, center and up_vector */ | ||
79 | -(void) locate; | ||
80 | /** sets the eye values in points */ | ||
81 | -(void) setEyeX: (float)x eyeY:(float)y eyeZ:(float)z; | ||
82 | /** sets the center values in points */ | ||
83 | -(void) setCenterX: (float)x centerY:(float)y centerZ:(float)z; | ||
84 | /** sets the up values */ | ||
85 | -(void) setUpX: (float)x upY:(float)y upZ:(float)z; | ||
86 | |||
87 | /** get the eye vector values in points */ | ||
88 | -(void) eyeX:(float*)x eyeY:(float*)y eyeZ:(float*)z; | ||
89 | /** get the center vector values in points */ | ||
90 | -(void) centerX:(float*)x centerY:(float*)y centerZ:(float*)z; | ||
91 | /** get the up vector values */ | ||
92 | -(void) upX:(float*)x upY:(float*)y upZ:(float*)z; | ||
93 | |||
94 | |||
95 | @end | ||
diff --git a/libs/cocos2d/CCCamera.m b/libs/cocos2d/CCCamera.m new file mode 100755 index 0000000..1ef6655 --- /dev/null +++ b/libs/cocos2d/CCCamera.m | |||
@@ -0,0 +1,131 @@ | |||
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 | #import "Platforms/CCGL.h" | ||
28 | #import "CCCamera.h" | ||
29 | #import "ccMacros.h" | ||
30 | #import "CCDrawingPrimitives.h" | ||
31 | |||
32 | @implementation CCCamera | ||
33 | |||
34 | @synthesize dirty = dirty_; | ||
35 | |||
36 | -(id) init | ||
37 | { | ||
38 | if( (self=[super init]) ) | ||
39 | [self restore]; | ||
40 | |||
41 | return self; | ||
42 | } | ||
43 | |||
44 | - (NSString*) description | ||
45 | { | ||
46 | return [NSString stringWithFormat:@"<%@ = %08X | center = (%.2f,%.2f,%.2f)>", [self class], self, centerX_, centerY_, centerZ_]; | ||
47 | } | ||
48 | |||
49 | |||
50 | - (void) dealloc | ||
51 | { | ||
52 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
53 | [super dealloc]; | ||
54 | } | ||
55 | |||
56 | -(void) restore | ||
57 | { | ||
58 | eyeX_ = eyeY_ = 0; | ||
59 | eyeZ_ = [CCCamera getZEye]; | ||
60 | |||
61 | centerX_ = centerY_ = centerZ_ = 0; | ||
62 | |||
63 | upX_ = 0.0f; | ||
64 | upY_ = 1.0f; | ||
65 | upZ_ = 0.0f; | ||
66 | |||
67 | dirty_ = NO; | ||
68 | } | ||
69 | |||
70 | -(void) locate | ||
71 | { | ||
72 | if( dirty_ ) | ||
73 | gluLookAt( eyeX_, eyeY_, eyeZ_, | ||
74 | centerX_, centerY_, centerZ_, | ||
75 | upX_, upY_, upZ_ | ||
76 | ); | ||
77 | } | ||
78 | |||
79 | +(float) getZEye | ||
80 | { | ||
81 | return FLT_EPSILON; | ||
82 | // CGSize s = [[CCDirector sharedDirector] displaySize]; | ||
83 | // return ( s.height / 1.1566f ); | ||
84 | } | ||
85 | |||
86 | -(void) setEyeX: (float)x eyeY:(float)y eyeZ:(float)z | ||
87 | { | ||
88 | eyeX_ = x * CC_CONTENT_SCALE_FACTOR(); | ||
89 | eyeY_ = y * CC_CONTENT_SCALE_FACTOR(); | ||
90 | eyeZ_ = z * CC_CONTENT_SCALE_FACTOR(); | ||
91 | dirty_ = YES; | ||
92 | } | ||
93 | |||
94 | -(void) setCenterX: (float)x centerY:(float)y centerZ:(float)z | ||
95 | { | ||
96 | centerX_ = x * CC_CONTENT_SCALE_FACTOR(); | ||
97 | centerY_ = y * CC_CONTENT_SCALE_FACTOR(); | ||
98 | centerZ_ = z * CC_CONTENT_SCALE_FACTOR(); | ||
99 | dirty_ = YES; | ||
100 | } | ||
101 | |||
102 | -(void) setUpX: (float)x upY:(float)y upZ:(float)z | ||
103 | { | ||
104 | upX_ = x; | ||
105 | upY_ = y; | ||
106 | upZ_ = z; | ||
107 | dirty_ = YES; | ||
108 | } | ||
109 | |||
110 | -(void) eyeX: (float*)x eyeY:(float*)y eyeZ:(float*)z | ||
111 | { | ||
112 | *x = eyeX_ / CC_CONTENT_SCALE_FACTOR(); | ||
113 | *y = eyeY_ / CC_CONTENT_SCALE_FACTOR(); | ||
114 | *z = eyeZ_ / CC_CONTENT_SCALE_FACTOR(); | ||
115 | } | ||
116 | |||
117 | -(void) centerX: (float*)x centerY:(float*)y centerZ:(float*)z | ||
118 | { | ||
119 | *x = centerX_ / CC_CONTENT_SCALE_FACTOR(); | ||
120 | *y = centerY_ / CC_CONTENT_SCALE_FACTOR(); | ||
121 | *z = centerZ_ / CC_CONTENT_SCALE_FACTOR(); | ||
122 | } | ||
123 | |||
124 | -(void) upX: (float*)x upY:(float*)y upZ:(float*)z | ||
125 | { | ||
126 | *x = upX_; | ||
127 | *y = upY_; | ||
128 | *z = upZ_; | ||
129 | } | ||
130 | |||
131 | @end | ||
diff --git a/libs/cocos2d/CCConfiguration.h b/libs/cocos2d/CCConfiguration.h new file mode 100755 index 0000000..04e1b55 --- /dev/null +++ b/libs/cocos2d/CCConfiguration.h | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | #import <Foundation/Foundation.h> | ||
27 | |||
28 | #import "Platforms/CCGL.h" | ||
29 | |||
30 | /** OS version definitions. Includes both iOS and Mac OS versions | ||
31 | */ | ||
32 | enum { | ||
33 | kCCiOSVersion_3_0 = 0x03000000, | ||
34 | kCCiOSVersion_3_1 = 0x03010000, | ||
35 | kCCiOSVersion_3_1_1 = 0x03010100, | ||
36 | kCCiOSVersion_3_1_2 = 0x03010200, | ||
37 | kCCiOSVersion_3_1_3 = 0x03010300, | ||
38 | kCCiOSVersion_3_2 = 0x03020000, | ||
39 | kCCiOSVersion_3_2_1 = 0x03020100, | ||
40 | kCCiOSVersion_4_0 = 0x04000000, | ||
41 | kCCiOSVersion_4_0_1 = 0x04000100, | ||
42 | kCCiOSVersion_4_1 = 0x04010000, | ||
43 | kCCiOSVersion_4_2 = 0x04020000, | ||
44 | kCCiOSVersion_4_3 = 0x04030000, | ||
45 | kCCiOSVersion_4_3_1 = 0x04030100, | ||
46 | kCCiOSVersion_4_3_2 = 0x04030200, | ||
47 | kCCiOSVersion_4_3_3 = 0x04030300, | ||
48 | |||
49 | kCCMacVersion_10_5 = 0x0a050000, | ||
50 | kCCMacVersion_10_6 = 0x0a060000, | ||
51 | kCCMacVersion_10_7 = 0x0a070000, | ||
52 | }; | ||
53 | |||
54 | /** | ||
55 | CCConfiguration contains some openGL variables | ||
56 | @since v0.99.0 | ||
57 | */ | ||
58 | @interface CCConfiguration : NSObject { | ||
59 | |||
60 | GLint maxTextureSize_; | ||
61 | GLint maxModelviewStackDepth_; | ||
62 | BOOL supportsPVRTC_; | ||
63 | BOOL supportsNPOT_; | ||
64 | BOOL supportsBGRA8888_; | ||
65 | BOOL supportsDiscardFramebuffer_; | ||
66 | unsigned int OSVersion_; | ||
67 | GLint maxSamplesAllowed_; | ||
68 | } | ||
69 | |||
70 | /** OpenGL Max texture size. */ | ||
71 | @property (nonatomic, readonly) GLint maxTextureSize; | ||
72 | |||
73 | /** OpenGL Max Modelview Stack Depth. */ | ||
74 | @property (nonatomic, readonly) GLint maxModelviewStackDepth; | ||
75 | |||
76 | /** Whether or not the GPU supports NPOT (Non Power Of Two) textures. | ||
77 | NPOT textures have the following limitations: | ||
78 | - They can't have mipmaps | ||
79 | - They only accept GL_CLAMP_TO_EDGE in GL_TEXTURE_WRAP_{S,T} | ||
80 | |||
81 | @since v0.99.2 | ||
82 | */ | ||
83 | @property (nonatomic, readonly) BOOL supportsNPOT; | ||
84 | |||
85 | /** Whether or not PVR Texture Compressed is supported */ | ||
86 | @property (nonatomic, readonly) BOOL supportsPVRTC; | ||
87 | |||
88 | /** Whether or not BGRA8888 textures are supported. | ||
89 | |||
90 | @since v0.99.2 | ||
91 | */ | ||
92 | @property (nonatomic, readonly) BOOL supportsBGRA8888; | ||
93 | |||
94 | /** Whether or not glDiscardFramebufferEXT is supported | ||
95 | |||
96 | @since v0.99.2 | ||
97 | */ | ||
98 | @property (nonatomic, readonly) BOOL supportsDiscardFramebuffer; | ||
99 | |||
100 | /** returns the OS version. | ||
101 | - On iOS devices it returns the firmware version. | ||
102 | - On Mac returns the OS version | ||
103 | |||
104 | @since v0.99.5 | ||
105 | */ | ||
106 | @property (nonatomic, readonly) unsigned int OSVersion; | ||
107 | |||
108 | /** returns a shared instance of the CCConfiguration */ | ||
109 | +(CCConfiguration *) sharedConfiguration; | ||
110 | |||
111 | /** returns whether or not an OpenGL is supported */ | ||
112 | - (BOOL) checkForGLExtension:(NSString *)searchName; | ||
113 | |||
114 | |||
115 | |||
116 | @end | ||
diff --git a/libs/cocos2d/CCConfiguration.m b/libs/cocos2d/CCConfiguration.m new file mode 100755 index 0000000..d51cd58 --- /dev/null +++ b/libs/cocos2d/CCConfiguration.m | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | #import <Availability.h> | ||
27 | |||
28 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
29 | #import <UIKit/UIKit.h> // Needed for UIDevice | ||
30 | #endif | ||
31 | |||
32 | #import "Platforms/CCGL.h" | ||
33 | #import "CCBlockSupport.h" | ||
34 | #import "CCConfiguration.h" | ||
35 | #import "ccMacros.h" | ||
36 | #import "ccConfig.h" | ||
37 | #import "Support/OpenGL_Internal.h" | ||
38 | |||
39 | @implementation CCConfiguration | ||
40 | |||
41 | @synthesize maxTextureSize = maxTextureSize_; | ||
42 | @synthesize supportsPVRTC = supportsPVRTC_; | ||
43 | @synthesize maxModelviewStackDepth = maxModelviewStackDepth_; | ||
44 | @synthesize supportsNPOT = supportsNPOT_; | ||
45 | @synthesize supportsBGRA8888 = supportsBGRA8888_; | ||
46 | @synthesize supportsDiscardFramebuffer = supportsDiscardFramebuffer_; | ||
47 | @synthesize OSVersion = OSVersion_; | ||
48 | |||
49 | // | ||
50 | // singleton stuff | ||
51 | // | ||
52 | static CCConfiguration *_sharedConfiguration = nil; | ||
53 | |||
54 | static char * glExtensions; | ||
55 | |||
56 | + (CCConfiguration *)sharedConfiguration | ||
57 | { | ||
58 | if (!_sharedConfiguration) | ||
59 | _sharedConfiguration = [[self alloc] init]; | ||
60 | |||
61 | return _sharedConfiguration; | ||
62 | } | ||
63 | |||
64 | +(id)alloc | ||
65 | { | ||
66 | NSAssert(_sharedConfiguration == nil, @"Attempted to allocate a second instance of a singleton."); | ||
67 | return [super alloc]; | ||
68 | } | ||
69 | |||
70 | |||
71 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
72 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
73 | - (NSString*)getMacVersion | ||
74 | { | ||
75 | SInt32 versionMajor, versionMinor, versionBugFix; | ||
76 | Gestalt(gestaltSystemVersionMajor, &versionMajor); | ||
77 | Gestalt(gestaltSystemVersionMinor, &versionMinor); | ||
78 | Gestalt(gestaltSystemVersionBugFix, &versionBugFix); | ||
79 | |||
80 | return [NSString stringWithFormat:@"%d.%d.%d", versionMajor, versionMinor, versionBugFix]; | ||
81 | } | ||
82 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
83 | |||
84 | -(id) init | ||
85 | { | ||
86 | if( (self=[super init])) { | ||
87 | |||
88 | // Obtain iOS version | ||
89 | OSVersion_ = 0; | ||
90 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
91 | NSString *OSVer = [[UIDevice currentDevice] systemVersion]; | ||
92 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
93 | NSString *OSVer = [self getMacVersion]; | ||
94 | #endif | ||
95 | NSArray *arr = [OSVer componentsSeparatedByString:@"."]; | ||
96 | int idx=0x01000000; | ||
97 | for( NSString *str in arr ) { | ||
98 | int value = [str intValue]; | ||
99 | OSVersion_ += value * idx; | ||
100 | idx = idx >> 8; | ||
101 | } | ||
102 | CCLOG(@"cocos2d: OS version: %@ (0x%08x)", OSVer, OSVersion_); | ||
103 | |||
104 | CCLOG(@"cocos2d: GL_VENDOR: %s", glGetString(GL_VENDOR) ); | ||
105 | CCLOG(@"cocos2d: GL_RENDERER: %s", glGetString ( GL_RENDERER ) ); | ||
106 | CCLOG(@"cocos2d: GL_VERSION: %s", glGetString ( GL_VERSION ) ); | ||
107 | |||
108 | glExtensions = (char*) glGetString(GL_EXTENSIONS); | ||
109 | |||
110 | glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize_); | ||
111 | glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &maxModelviewStackDepth_); | ||
112 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
113 | if( OSVersion_ >= kCCiOSVersion_4_0 ) | ||
114 | glGetIntegerv(GL_MAX_SAMPLES_APPLE, &maxSamplesAllowed_); | ||
115 | else | ||
116 | maxSamplesAllowed_ = 0; | ||
117 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
118 | glGetIntegerv(GL_MAX_SAMPLES, &maxSamplesAllowed_); | ||
119 | #endif | ||
120 | |||
121 | supportsPVRTC_ = [self checkForGLExtension:@"GL_IMG_texture_compression_pvrtc"]; | ||
122 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
123 | supportsNPOT_ = [self checkForGLExtension:@"GL_APPLE_texture_2D_limited_npot"]; | ||
124 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
125 | supportsNPOT_ = [self checkForGLExtension:@"GL_ARB_texture_non_power_of_two"]; | ||
126 | #endif | ||
127 | // It seems that somewhere between firmware iOS 3.0 and 4.2 Apple renamed | ||
128 | // GL_IMG_... to GL_APPLE.... So we should check both names | ||
129 | |||
130 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
131 | BOOL bgra8a = [self checkForGLExtension:@"GL_IMG_texture_format_BGRA8888"]; | ||
132 | BOOL bgra8b = [self checkForGLExtension:@"GL_APPLE_texture_format_BGRA8888"]; | ||
133 | supportsBGRA8888_ = bgra8a | bgra8b; | ||
134 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
135 | supportsBGRA8888_ = [self checkForGLExtension:@"GL_EXT_bgra"]; | ||
136 | #endif | ||
137 | |||
138 | supportsDiscardFramebuffer_ = [self checkForGLExtension:@"GL_EXT_discard_framebuffer"]; | ||
139 | |||
140 | CCLOG(@"cocos2d: GL_MAX_TEXTURE_SIZE: %d", maxTextureSize_); | ||
141 | CCLOG(@"cocos2d: GL_MAX_MODELVIEW_STACK_DEPTH: %d",maxModelviewStackDepth_); | ||
142 | CCLOG(@"cocos2d: GL_MAX_SAMPLES: %d", maxSamplesAllowed_); | ||
143 | CCLOG(@"cocos2d: GL supports PVRTC: %s", (supportsPVRTC_ ? "YES" : "NO") ); | ||
144 | CCLOG(@"cocos2d: GL supports BGRA8888 textures: %s", (supportsBGRA8888_ ? "YES" : "NO") ); | ||
145 | CCLOG(@"cocos2d: GL supports NPOT textures: %s", (supportsNPOT_ ? "YES" : "NO") ); | ||
146 | CCLOG(@"cocos2d: GL supports discard_framebuffer: %s", (supportsDiscardFramebuffer_ ? "YES" : "NO") ); | ||
147 | CCLOG(@"cocos2d: compiled with NPOT support: %s", | ||
148 | #if CC_TEXTURE_NPOT_SUPPORT | ||
149 | "YES" | ||
150 | #else | ||
151 | "NO" | ||
152 | #endif | ||
153 | ); | ||
154 | CCLOG(@"cocos2d: compiled with VBO support in TextureAtlas : %s", | ||
155 | #if CC_USES_VBO | ||
156 | "YES" | ||
157 | #else | ||
158 | "NO" | ||
159 | #endif | ||
160 | ); | ||
161 | |||
162 | CCLOG(@"cocos2d: compiled with Affine Matrix transformation in CCNode : %s", | ||
163 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
164 | "YES" | ||
165 | #else | ||
166 | "NO" | ||
167 | #endif | ||
168 | ); | ||
169 | |||
170 | CCLOG(@"cocos2d: compiled with Profiling Support: %s", | ||
171 | #if CC_ENABLE_PROFILERS | ||
172 | |||
173 | "YES - *** Disable it when you finish profiling ***" | ||
174 | #else | ||
175 | "NO" | ||
176 | #endif | ||
177 | ); | ||
178 | |||
179 | CHECK_GL_ERROR(); | ||
180 | } | ||
181 | |||
182 | return self; | ||
183 | } | ||
184 | |||
185 | - (BOOL) checkForGLExtension:(NSString *)searchName | ||
186 | { | ||
187 | // For best results, extensionsNames should be stored in your renderer so that it does not | ||
188 | // need to be recreated on each invocation. | ||
189 | NSString *extensionsString = [NSString stringWithCString:glExtensions encoding: NSASCIIStringEncoding]; | ||
190 | NSArray *extensionsNames = [extensionsString componentsSeparatedByString:@" "]; | ||
191 | return [extensionsNames containsObject: searchName]; | ||
192 | } | ||
193 | @end | ||
diff --git a/libs/cocos2d/CCDirector.h b/libs/cocos2d/CCDirector.h new file mode 100755 index 0000000..9c3f3fe --- /dev/null +++ b/libs/cocos2d/CCDirector.h | |||
@@ -0,0 +1,307 @@ | |||
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 | #import "ccConfig.h" | ||
28 | #import "ccTypes.h" | ||
29 | |||
30 | // OpenGL related | ||
31 | #import "Platforms/CCGL.h" | ||
32 | #import "CCProtocols.h" | ||
33 | |||
34 | /** @typedef ccDirectorProjection | ||
35 | Possible OpenGL projections used by director | ||
36 | */ | ||
37 | typedef enum { | ||
38 | /// sets a 2D projection (orthogonal projection). | ||
39 | kCCDirectorProjection2D, | ||
40 | |||
41 | /// sets a 3D projection with a fovy=60, znear=0.5f and zfar=1500. | ||
42 | kCCDirectorProjection3D, | ||
43 | |||
44 | /// it calls "updateProjection" on the projection delegate. | ||
45 | kCCDirectorProjectionCustom, | ||
46 | |||
47 | /// Detault projection is 3D projection | ||
48 | kCCDirectorProjectionDefault = kCCDirectorProjection3D, | ||
49 | |||
50 | // backward compatibility stuff | ||
51 | CCDirectorProjection2D = kCCDirectorProjection2D, | ||
52 | CCDirectorProjection3D = kCCDirectorProjection3D, | ||
53 | CCDirectorProjectionCustom = kCCDirectorProjectionCustom, | ||
54 | |||
55 | } ccDirectorProjection; | ||
56 | |||
57 | |||
58 | @class CCLabelAtlas; | ||
59 | @class CCScene; | ||
60 | |||
61 | /**Class that creates and handle the main Window and manages how | ||
62 | and when to execute the Scenes. | ||
63 | |||
64 | The CCDirector is also resposible for: | ||
65 | - initializing the OpenGL ES context | ||
66 | - setting the OpenGL pixel format (default on is RGB565) | ||
67 | - setting the OpenGL buffer depth (default one is 0-bit) | ||
68 | - setting the projection (default one is 3D) | ||
69 | - setting the orientation (default one is Protrait) | ||
70 | |||
71 | Since the CCDirector is a singleton, the standard way to use it is by calling: | ||
72 | - [[CCDirector sharedDirector] methodName]; | ||
73 | |||
74 | The CCDirector also sets the default OpenGL context: | ||
75 | - GL_TEXTURE_2D is enabled | ||
76 | - GL_VERTEX_ARRAY is enabled | ||
77 | - GL_COLOR_ARRAY is enabled | ||
78 | - GL_TEXTURE_COORD_ARRAY is enabled | ||
79 | */ | ||
80 | @interface CCDirector : NSObject | ||
81 | { | ||
82 | CC_GLVIEW *openGLView_; | ||
83 | |||
84 | // internal timer | ||
85 | NSTimeInterval animationInterval_; | ||
86 | NSTimeInterval oldAnimationInterval_; | ||
87 | |||
88 | /* display FPS ? */ | ||
89 | BOOL displayFPS_; | ||
90 | |||
91 | NSUInteger frames_; | ||
92 | ccTime accumDt_; | ||
93 | ccTime frameRate_; | ||
94 | #if CC_DIRECTOR_FAST_FPS | ||
95 | CCLabelAtlas *FPSLabel_; | ||
96 | #endif | ||
97 | |||
98 | /* is the running scene paused */ | ||
99 | BOOL isPaused_; | ||
100 | |||
101 | /* The running scene */ | ||
102 | CCScene *runningScene_; | ||
103 | |||
104 | /* This object will be visited after the scene. Useful to hook a notification node */ | ||
105 | id notificationNode_; | ||
106 | |||
107 | /* will be the next 'runningScene' in the next frame | ||
108 | nextScene is a weak reference. */ | ||
109 | CCScene *nextScene_; | ||
110 | |||
111 | /* If YES, then "old" scene will receive the cleanup message */ | ||
112 | BOOL sendCleanupToScene_; | ||
113 | |||
114 | /* scheduled scenes */ | ||
115 | NSMutableArray *scenesStack_; | ||
116 | |||
117 | /* last time the main loop was updated */ | ||
118 | struct timeval lastUpdate_; | ||
119 | /* delta time since last tick to main loop */ | ||
120 | ccTime dt; | ||
121 | /* whether or not the next delta time will be zero */ | ||
122 | BOOL nextDeltaTimeZero_; | ||
123 | |||
124 | /* projection used */ | ||
125 | ccDirectorProjection projection_; | ||
126 | |||
127 | /* Projection protocol delegate */ | ||
128 | id<CCProjectionProtocol> projectionDelegate_; | ||
129 | |||
130 | /* window size in points */ | ||
131 | CGSize winSizeInPoints_; | ||
132 | |||
133 | /* window size in pixels */ | ||
134 | CGSize winSizeInPixels_; | ||
135 | |||
136 | /* the cocos2d running thread */ | ||
137 | NSThread *runningThread_; | ||
138 | |||
139 | // profiler | ||
140 | #if CC_ENABLE_PROFILERS | ||
141 | ccTime accumDtForProfiler_; | ||
142 | #endif | ||
143 | } | ||
144 | |||
145 | /** returns the cocos2d thread. | ||
146 | If you want to run any cocos2d task, run it in this thread. | ||
147 | On iOS usually it is the main thread. | ||
148 | @since v0.99.5 | ||
149 | */ | ||
150 | @property (readonly, nonatomic ) NSThread *runningThread; | ||
151 | /** The current running Scene. Director can only run one Scene at the time */ | ||
152 | @property (nonatomic,readonly) CCScene* runningScene; | ||
153 | /** The FPS value */ | ||
154 | @property (nonatomic,readwrite, assign) NSTimeInterval animationInterval; | ||
155 | /** Whether or not to display the FPS on the bottom-left corner */ | ||
156 | @property (nonatomic,readwrite, assign) BOOL displayFPS; | ||
157 | /** The OpenGLView, where everything is rendered */ | ||
158 | @property (nonatomic,readwrite,retain) CC_GLVIEW *openGLView; | ||
159 | /** whether or not the next delta time will be zero */ | ||
160 | @property (nonatomic,readwrite,assign) BOOL nextDeltaTimeZero; | ||
161 | /** Whether or not the Director is paused */ | ||
162 | @property (nonatomic,readonly) BOOL isPaused; | ||
163 | /** Sets an OpenGL projection | ||
164 | @since v0.8.2 | ||
165 | */ | ||
166 | @property (nonatomic,readwrite) ccDirectorProjection projection; | ||
167 | /** How many frames were called since the director started */ | ||
168 | @property (readonly) NSUInteger frames; | ||
169 | |||
170 | /** Whether or not the replaced scene will receive the cleanup message. | ||
171 | If the new scene is pushed, then the old scene won't receive the "cleanup" message. | ||
172 | If the new scene replaces the old one, the it will receive the "cleanup" message. | ||
173 | @since v0.99.0 | ||
174 | */ | ||
175 | @property (nonatomic, readonly) BOOL sendCleanupToScene; | ||
176 | |||
177 | /** This object will be visited after the main scene is visited. | ||
178 | This object MUST implement the "visit" selector. | ||
179 | Useful to hook a notification object, like CCNotifications (http://github.com/manucorporat/CCNotifications) | ||
180 | @since v0.99.5 | ||
181 | */ | ||
182 | @property (nonatomic, readwrite, retain) id notificationNode; | ||
183 | |||
184 | /** This object will be called when the OpenGL projection is udpated and only when the kCCDirectorProjectionCustom projection is used. | ||
185 | @since v0.99.5 | ||
186 | */ | ||
187 | @property (nonatomic, readwrite, retain) id<CCProjectionProtocol> projectionDelegate; | ||
188 | |||
189 | /** returns a shared instance of the director */ | ||
190 | +(CCDirector *)sharedDirector; | ||
191 | |||
192 | |||
193 | |||
194 | // Window size | ||
195 | |||
196 | /** returns the size of the OpenGL view in points. | ||
197 | It takes into account any possible rotation (device orientation) of the window | ||
198 | */ | ||
199 | - (CGSize) winSize; | ||
200 | |||
201 | /** returns the size of the OpenGL view in pixels. | ||
202 | It takes into account any possible rotation (device orientation) of the window. | ||
203 | On Mac winSize and winSizeInPixels return the same value. | ||
204 | */ | ||
205 | - (CGSize) winSizeInPixels; | ||
206 | /** returns the display size of the OpenGL view in pixels. | ||
207 | It doesn't take into account any possible rotation of the window. | ||
208 | */ | ||
209 | -(CGSize) displaySizeInPixels; | ||
210 | /** changes the projection size */ | ||
211 | -(void) reshapeProjection:(CGSize)newWindowSize; | ||
212 | |||
213 | /** converts a UIKit coordinate to an OpenGL coordinate | ||
214 | Useful to convert (multi) touchs coordinates to the current layout (portrait or landscape) | ||
215 | */ | ||
216 | -(CGPoint) convertToGL: (CGPoint) p; | ||
217 | /** converts an OpenGL coordinate to a UIKit coordinate | ||
218 | Useful to convert node points to window points for calls such as glScissor | ||
219 | */ | ||
220 | -(CGPoint) convertToUI:(CGPoint)p; | ||
221 | |||
222 | /// XXX: missing description | ||
223 | -(float) getZEye; | ||
224 | |||
225 | // Scene Management | ||
226 | |||
227 | /**Enters the Director's main loop with the given Scene. | ||
228 | * Call it to run only your FIRST scene. | ||
229 | * Don't call it if there is already a running scene. | ||
230 | */ | ||
231 | - (void) runWithScene:(CCScene*) scene; | ||
232 | |||
233 | /**Suspends the execution of the running scene, pushing it on the stack of suspended scenes. | ||
234 | * The new scene will be executed. | ||
235 | * Try to avoid big stacks of pushed scenes to reduce memory allocation. | ||
236 | * ONLY call it if there is a running scene. | ||
237 | */ | ||
238 | - (void) pushScene:(CCScene*) scene; | ||
239 | |||
240 | /**Pops out a scene from the queue. | ||
241 | * This scene will replace the running one. | ||
242 | * The running scene will be deleted. If there are no more scenes in the stack the execution is terminated. | ||
243 | * ONLY call it if there is a running scene. | ||
244 | */ | ||
245 | - (void) popScene; | ||
246 | |||
247 | /** Replaces the running scene with a new one. The running scene is terminated. | ||
248 | * ONLY call it if there is a running scene. | ||
249 | */ | ||
250 | -(void) replaceScene: (CCScene*) scene; | ||
251 | |||
252 | /** Ends the execution, releases the running scene. | ||
253 | It doesn't remove the OpenGL view from its parent. You have to do it manually. | ||
254 | */ | ||
255 | -(void) end; | ||
256 | |||
257 | /** Pauses the running scene. | ||
258 | The running scene will be _drawed_ but all scheduled timers will be paused | ||
259 | While paused, the draw rate will be 4 FPS to reduce CPU consuption | ||
260 | */ | ||
261 | -(void) pause; | ||
262 | |||
263 | /** Resumes the paused scene | ||
264 | The scheduled timers will be activated again. | ||
265 | The "delta time" will be 0 (as if the game wasn't paused) | ||
266 | */ | ||
267 | -(void) resume; | ||
268 | |||
269 | /** Stops the animation. Nothing will be drawn. The main loop won't be triggered anymore. | ||
270 | If you wan't to pause your animation call [pause] instead. | ||
271 | */ | ||
272 | -(void) stopAnimation; | ||
273 | |||
274 | /** The main loop is triggered again. | ||
275 | Call this function only if [stopAnimation] was called earlier | ||
276 | @warning Dont' call this function to start the main loop. To run the main loop call runWithScene | ||
277 | */ | ||
278 | -(void) startAnimation; | ||
279 | |||
280 | /** Draw the scene. | ||
281 | This method is called every frame. Don't call it manually. | ||
282 | */ | ||
283 | -(void) drawScene; | ||
284 | |||
285 | // Memory Helper | ||
286 | |||
287 | /** Removes all the cocos2d data that was cached automatically. | ||
288 | It will purge the CCTextureCache, CCLabelBMFont cache. | ||
289 | IMPORTANT: The CCSpriteFrameCache won't be purged. If you want to purge it, you have to purge it manually. | ||
290 | @since v0.99.3 | ||
291 | */ | ||
292 | -(void) purgeCachedData; | ||
293 | |||
294 | // OpenGL Helper | ||
295 | |||
296 | /** sets the OpenGL default values */ | ||
297 | -(void) setGLDefaultValues; | ||
298 | |||
299 | /** enables/disables OpenGL alpha blending */ | ||
300 | - (void) setAlphaBlending: (BOOL) on; | ||
301 | /** enables/disables OpenGL depth test */ | ||
302 | - (void) setDepthTest: (BOOL) on; | ||
303 | |||
304 | // Profiler | ||
305 | -(void) showProfilers; | ||
306 | |||
307 | @end | ||
diff --git a/libs/cocos2d/CCDirector.m b/libs/cocos2d/CCDirector.m new file mode 100755 index 0000000..292bc28 --- /dev/null +++ b/libs/cocos2d/CCDirector.m | |||
@@ -0,0 +1,565 @@ | |||
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 | /* Idea of decoupling Window from Director taken from OC3D project: http://code.google.com/p/oc3d/ | ||
28 | */ | ||
29 | |||
30 | #import <unistd.h> | ||
31 | #import <Availability.h> | ||
32 | |||
33 | // cocos2d imports | ||
34 | #import "CCDirector.h" | ||
35 | #import "CCScheduler.h" | ||
36 | #import "CCActionManager.h" | ||
37 | #import "CCTextureCache.h" | ||
38 | #import "CCAnimationCache.h" | ||
39 | #import "CCLabelAtlas.h" | ||
40 | #import "ccMacros.h" | ||
41 | #import "CCTransition.h" | ||
42 | #import "CCScene.h" | ||
43 | #import "CCSpriteFrameCache.h" | ||
44 | #import "CCTexture2D.h" | ||
45 | #import "CCLabelBMFont.h" | ||
46 | #import "CCLayer.h" | ||
47 | |||
48 | // support imports | ||
49 | #import "Platforms/CCGL.h" | ||
50 | #import "Platforms/CCNS.h" | ||
51 | |||
52 | #import "Support/OpenGL_Internal.h" | ||
53 | #import "Support/CGPointExtension.h" | ||
54 | |||
55 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
56 | #import "Platforms/iOS/CCDirectorIOS.h" | ||
57 | #define CC_DIRECTOR_DEFAULT CCDirectorTimer | ||
58 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
59 | #import "Platforms/Mac/CCDirectorMac.h" | ||
60 | #define CC_DIRECTOR_DEFAULT CCDirectorDisplayLink | ||
61 | #endif | ||
62 | |||
63 | #import "Support/CCProfiling.h" | ||
64 | |||
65 | #define kDefaultFPS 60.0 // 60 frames per second | ||
66 | |||
67 | extern NSString * cocos2dVersion(void); | ||
68 | |||
69 | |||
70 | @interface CCDirector (Private) | ||
71 | -(void) setNextScene; | ||
72 | // shows the FPS in the screen | ||
73 | -(void) showFPS; | ||
74 | // calculates delta time since last time it was called | ||
75 | -(void) calculateDeltaTime; | ||
76 | @end | ||
77 | |||
78 | @implementation CCDirector | ||
79 | |||
80 | @synthesize animationInterval = animationInterval_; | ||
81 | @synthesize runningScene = runningScene_; | ||
82 | @synthesize displayFPS = displayFPS_; | ||
83 | @synthesize nextDeltaTimeZero = nextDeltaTimeZero_; | ||
84 | @synthesize isPaused = isPaused_; | ||
85 | @synthesize sendCleanupToScene = sendCleanupToScene_; | ||
86 | @synthesize runningThread = runningThread_; | ||
87 | @synthesize notificationNode = notificationNode_; | ||
88 | @synthesize projectionDelegate = projectionDelegate_; | ||
89 | @synthesize frames = frames_; | ||
90 | // | ||
91 | // singleton stuff | ||
92 | // | ||
93 | static CCDirector *_sharedDirector = nil; | ||
94 | |||
95 | + (CCDirector *)sharedDirector | ||
96 | { | ||
97 | if (!_sharedDirector) { | ||
98 | |||
99 | // | ||
100 | // Default Director is TimerDirector | ||
101 | // | ||
102 | if( [ [CCDirector class] isEqual:[self class]] ) | ||
103 | _sharedDirector = [[CC_DIRECTOR_DEFAULT alloc] init]; | ||
104 | else | ||
105 | _sharedDirector = [[self alloc] init]; | ||
106 | } | ||
107 | |||
108 | return _sharedDirector; | ||
109 | } | ||
110 | |||
111 | +(id)alloc | ||
112 | { | ||
113 | NSAssert(_sharedDirector == nil, @"Attempted to allocate a second instance of a singleton."); | ||
114 | return [super alloc]; | ||
115 | } | ||
116 | |||
117 | - (id) init | ||
118 | { | ||
119 | CCLOG(@"cocos2d: %@", cocos2dVersion() ); | ||
120 | |||
121 | if( (self=[super init]) ) { | ||
122 | |||
123 | CCLOG(@"cocos2d: Using Director Type:%@", [self class]); | ||
124 | |||
125 | // scenes | ||
126 | runningScene_ = nil; | ||
127 | nextScene_ = nil; | ||
128 | |||
129 | notificationNode_ = nil; | ||
130 | |||
131 | oldAnimationInterval_ = animationInterval_ = 1.0 / kDefaultFPS; | ||
132 | scenesStack_ = [[NSMutableArray alloc] initWithCapacity:10]; | ||
133 | |||
134 | // Set default projection (3D) | ||
135 | projection_ = kCCDirectorProjectionDefault; | ||
136 | |||
137 | // projection delegate if "Custom" projection is used | ||
138 | projectionDelegate_ = nil; | ||
139 | |||
140 | // FPS | ||
141 | displayFPS_ = NO; | ||
142 | frames_ = 0; | ||
143 | |||
144 | // paused ? | ||
145 | isPaused_ = NO; | ||
146 | |||
147 | // running thread | ||
148 | runningThread_ = nil; | ||
149 | |||
150 | winSizeInPixels_ = winSizeInPoints_ = CGSizeZero; | ||
151 | } | ||
152 | |||
153 | return self; | ||
154 | } | ||
155 | |||
156 | - (void) dealloc | ||
157 | { | ||
158 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
159 | |||
160 | #if CC_DIRECTOR_FAST_FPS | ||
161 | [FPSLabel_ release]; | ||
162 | #endif | ||
163 | [runningScene_ release]; | ||
164 | [notificationNode_ release]; | ||
165 | [scenesStack_ release]; | ||
166 | |||
167 | [projectionDelegate_ release]; | ||
168 | |||
169 | _sharedDirector = nil; | ||
170 | |||
171 | [super dealloc]; | ||
172 | } | ||
173 | |||
174 | -(void) setGLDefaultValues | ||
175 | { | ||
176 | // This method SHOULD be called only after openGLView_ was initialized | ||
177 | NSAssert( openGLView_, @"openGLView_ must be initialized"); | ||
178 | |||
179 | [self setAlphaBlending: YES]; | ||
180 | [self setDepthTest: YES]; | ||
181 | [self setProjection: projection_]; | ||
182 | |||
183 | // set other opengl default values | ||
184 | glClearColor(0.0f, 0.0f, 0.0f, 1.0f); | ||
185 | |||
186 | #if CC_DIRECTOR_FAST_FPS | ||
187 | if (!FPSLabel_) { | ||
188 | CCTexture2DPixelFormat currentFormat = [CCTexture2D defaultAlphaPixelFormat]; | ||
189 | [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA4444]; | ||
190 | FPSLabel_ = [[CCLabelAtlas labelWithString:@"00.0" charMapFile:@"fps_images.png" itemWidth:16 itemHeight:24 startCharMap:'.'] retain]; | ||
191 | [CCTexture2D setDefaultAlphaPixelFormat:currentFormat]; | ||
192 | } | ||
193 | #endif // CC_DIRECTOR_FAST_FPS | ||
194 | } | ||
195 | |||
196 | // | ||
197 | // Draw the Scene | ||
198 | // | ||
199 | - (void) drawScene | ||
200 | { | ||
201 | // Override me | ||
202 | } | ||
203 | |||
204 | -(void) calculateDeltaTime | ||
205 | { | ||
206 | struct timeval now; | ||
207 | |||
208 | if( gettimeofday( &now, NULL) != 0 ) { | ||
209 | CCLOG(@"cocos2d: error in gettimeofday"); | ||
210 | dt = 0; | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | // new delta time | ||
215 | if( nextDeltaTimeZero_ ) { | ||
216 | dt = 0; | ||
217 | nextDeltaTimeZero_ = NO; | ||
218 | } else { | ||
219 | dt = (now.tv_sec - lastUpdate_.tv_sec) + (now.tv_usec - lastUpdate_.tv_usec) / 1000000.0f; | ||
220 | dt = MAX(0,dt); | ||
221 | } | ||
222 | |||
223 | #ifdef DEBUG | ||
224 | // If we are debugging our code, prevent big delta time | ||
225 | if( dt > 0.2f ) | ||
226 | dt = 1/60.0f; | ||
227 | #endif | ||
228 | |||
229 | lastUpdate_ = now; | ||
230 | } | ||
231 | |||
232 | #pragma mark Director - Memory Helper | ||
233 | |||
234 | -(void) purgeCachedData | ||
235 | { | ||
236 | [CCLabelBMFont purgeCachedData]; | ||
237 | [[CCTextureCache sharedTextureCache] removeUnusedTextures]; | ||
238 | } | ||
239 | |||
240 | #pragma mark Director - Scene OpenGL Helper | ||
241 | |||
242 | -(ccDirectorProjection) projection | ||
243 | { | ||
244 | return projection_; | ||
245 | } | ||
246 | |||
247 | -(float) getZEye | ||
248 | { | ||
249 | return ( winSizeInPixels_.height / 1.1566f ); | ||
250 | } | ||
251 | |||
252 | -(void) setProjection:(ccDirectorProjection)projection | ||
253 | { | ||
254 | CCLOG(@"cocos2d: override me"); | ||
255 | } | ||
256 | |||
257 | - (void) setAlphaBlending: (BOOL) on | ||
258 | { | ||
259 | if (on) { | ||
260 | glEnable(GL_BLEND); | ||
261 | glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); | ||
262 | |||
263 | } else | ||
264 | glDisable(GL_BLEND); | ||
265 | } | ||
266 | |||
267 | - (void) setDepthTest: (BOOL) on | ||
268 | { | ||
269 | if (on) { | ||
270 | ccglClearDepth(1.0f); | ||
271 | glEnable(GL_DEPTH_TEST); | ||
272 | glDepthFunc(GL_LEQUAL); | ||
273 | // glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); | ||
274 | } else | ||
275 | glDisable( GL_DEPTH_TEST ); | ||
276 | } | ||
277 | |||
278 | #pragma mark Director Integration with a UIKit view | ||
279 | |||
280 | -(CC_GLVIEW*) openGLView | ||
281 | { | ||
282 | return openGLView_; | ||
283 | } | ||
284 | |||
285 | -(void) setOpenGLView:(CC_GLVIEW *)view | ||
286 | { | ||
287 | NSAssert( view, @"OpenGLView must be non-nil"); | ||
288 | |||
289 | if( view != openGLView_ ) { | ||
290 | [openGLView_ release]; | ||
291 | openGLView_ = [view retain]; | ||
292 | |||
293 | // set size | ||
294 | winSizeInPixels_ = winSizeInPoints_ = CCNSSizeToCGSize( [view bounds].size ); | ||
295 | |||
296 | [self setGLDefaultValues]; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | #pragma mark Director Scene Landscape | ||
301 | |||
302 | -(CGPoint)convertToGL:(CGPoint)uiPoint | ||
303 | { | ||
304 | CCLOG(@"CCDirector#convertToGL: OVERRIDE ME."); | ||
305 | return CGPointZero; | ||
306 | } | ||
307 | |||
308 | -(CGPoint)convertToUI:(CGPoint)glPoint | ||
309 | { | ||
310 | CCLOG(@"CCDirector#convertToUI: OVERRIDE ME."); | ||
311 | return CGPointZero; | ||
312 | } | ||
313 | |||
314 | -(CGSize)winSize | ||
315 | { | ||
316 | return winSizeInPoints_; | ||
317 | } | ||
318 | |||
319 | -(CGSize)winSizeInPixels | ||
320 | { | ||
321 | return winSizeInPixels_; | ||
322 | } | ||
323 | |||
324 | -(CGSize)displaySizeInPixels | ||
325 | { | ||
326 | return winSizeInPixels_; | ||
327 | } | ||
328 | |||
329 | -(void) reshapeProjection:(CGSize)newWindowSize | ||
330 | { | ||
331 | winSizeInPixels_ = winSizeInPoints_ = newWindowSize; | ||
332 | [self setProjection:projection_]; | ||
333 | } | ||
334 | |||
335 | #pragma mark Director Scene Management | ||
336 | |||
337 | - (void)runWithScene:(CCScene*) scene | ||
338 | { | ||
339 | NSAssert( scene != nil, @"Argument must be non-nil"); | ||
340 | NSAssert( runningScene_ == nil, @"You can't run an scene if another Scene is running. Use replaceScene or pushScene instead"); | ||
341 | |||
342 | [self pushScene:scene]; | ||
343 | [self startAnimation]; | ||
344 | } | ||
345 | |||
346 | -(void) replaceScene: (CCScene*) scene | ||
347 | { | ||
348 | NSAssert( scene != nil, @"Argument must be non-nil"); | ||
349 | |||
350 | NSUInteger index = [scenesStack_ count]; | ||
351 | |||
352 | sendCleanupToScene_ = YES; | ||
353 | [scenesStack_ replaceObjectAtIndex:index-1 withObject:scene]; | ||
354 | nextScene_ = scene; // nextScene_ is a weak ref | ||
355 | } | ||
356 | |||
357 | - (void) pushScene: (CCScene*) scene | ||
358 | { | ||
359 | NSAssert( scene != nil, @"Argument must be non-nil"); | ||
360 | |||
361 | sendCleanupToScene_ = NO; | ||
362 | |||
363 | [scenesStack_ addObject: scene]; | ||
364 | nextScene_ = scene; // nextScene_ is a weak ref | ||
365 | } | ||
366 | |||
367 | -(void) popScene | ||
368 | { | ||
369 | NSAssert( runningScene_ != nil, @"A running Scene is needed"); | ||
370 | |||
371 | [scenesStack_ removeLastObject]; | ||
372 | NSUInteger c = [scenesStack_ count]; | ||
373 | |||
374 | if( c == 0 ) | ||
375 | [self end]; | ||
376 | else { | ||
377 | sendCleanupToScene_ = YES; | ||
378 | nextScene_ = [scenesStack_ objectAtIndex:c-1]; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | -(void) end | ||
383 | { | ||
384 | [runningScene_ onExit]; | ||
385 | [runningScene_ cleanup]; | ||
386 | [runningScene_ release]; | ||
387 | |||
388 | runningScene_ = nil; | ||
389 | nextScene_ = nil; | ||
390 | |||
391 | // remove all objects, but don't release it. | ||
392 | // runWithScene might be executed after 'end'. | ||
393 | [scenesStack_ removeAllObjects]; | ||
394 | |||
395 | [self stopAnimation]; | ||
396 | |||
397 | #if CC_DIRECTOR_FAST_FPS | ||
398 | [FPSLabel_ release]; | ||
399 | FPSLabel_ = nil; | ||
400 | #endif | ||
401 | |||
402 | [projectionDelegate_ release]; | ||
403 | projectionDelegate_ = nil; | ||
404 | |||
405 | // Purge bitmap cache | ||
406 | [CCLabelBMFont purgeCachedData]; | ||
407 | |||
408 | // Purge all managers | ||
409 | [CCAnimationCache purgeSharedAnimationCache]; | ||
410 | [CCSpriteFrameCache purgeSharedSpriteFrameCache]; | ||
411 | [CCScheduler purgeSharedScheduler]; | ||
412 | [CCActionManager purgeSharedManager]; | ||
413 | [CCTextureCache purgeSharedTextureCache]; | ||
414 | |||
415 | |||
416 | // OpenGL view | ||
417 | |||
418 | // Since the director doesn't attach the openglview to the window | ||
419 | // it shouldn't remove it from the window too. | ||
420 | // [openGLView_ removeFromSuperview]; | ||
421 | |||
422 | [openGLView_ release]; | ||
423 | openGLView_ = nil; | ||
424 | } | ||
425 | |||
426 | -(void) setNextScene | ||
427 | { | ||
428 | Class transClass = [CCTransitionScene class]; | ||
429 | BOOL runningIsTransition = [runningScene_ isKindOfClass:transClass]; | ||
430 | BOOL newIsTransition = [nextScene_ isKindOfClass:transClass]; | ||
431 | |||
432 | // If it is not a transition, call onExit/cleanup | ||
433 | if( ! newIsTransition ) { | ||
434 | [runningScene_ onExit]; | ||
435 | |||
436 | // issue #709. the root node (scene) should receive the cleanup message too | ||
437 | // otherwise it might be leaked. | ||
438 | if( sendCleanupToScene_) | ||
439 | [runningScene_ cleanup]; | ||
440 | } | ||
441 | |||
442 | [runningScene_ release]; | ||
443 | |||
444 | runningScene_ = [nextScene_ retain]; | ||
445 | nextScene_ = nil; | ||
446 | |||
447 | if( ! runningIsTransition ) { | ||
448 | [runningScene_ onEnter]; | ||
449 | [runningScene_ onEnterTransitionDidFinish]; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | -(void) pause | ||
454 | { | ||
455 | if( isPaused_ ) | ||
456 | return; | ||
457 | |||
458 | oldAnimationInterval_ = animationInterval_; | ||
459 | |||
460 | // when paused, don't consume CPU | ||
461 | [self setAnimationInterval:1/4.0]; | ||
462 | isPaused_ = YES; | ||
463 | } | ||
464 | |||
465 | -(void) resume | ||
466 | { | ||
467 | if( ! isPaused_ ) | ||
468 | return; | ||
469 | |||
470 | [self setAnimationInterval: oldAnimationInterval_]; | ||
471 | |||
472 | if( gettimeofday( &lastUpdate_, NULL) != 0 ) { | ||
473 | CCLOG(@"cocos2d: Director: Error in gettimeofday"); | ||
474 | } | ||
475 | |||
476 | isPaused_ = NO; | ||
477 | dt = 0; | ||
478 | } | ||
479 | |||
480 | - (void)startAnimation | ||
481 | { | ||
482 | CCLOG(@"cocos2d: Director#startAnimation. Override me"); | ||
483 | } | ||
484 | |||
485 | - (void)stopAnimation | ||
486 | { | ||
487 | CCLOG(@"cocos2d: Director#stopAnimation. Override me"); | ||
488 | } | ||
489 | |||
490 | - (void)setAnimationInterval:(NSTimeInterval)interval | ||
491 | { | ||
492 | CCLOG(@"cocos2d: Director#setAnimationInterval. Override me"); | ||
493 | } | ||
494 | |||
495 | #if CC_DIRECTOR_FAST_FPS | ||
496 | |||
497 | // display the FPS using a LabelAtlas | ||
498 | // updates the FPS every frame | ||
499 | -(void) showFPS | ||
500 | { | ||
501 | frames_++; | ||
502 | accumDt_ += dt; | ||
503 | |||
504 | if ( accumDt_ > CC_DIRECTOR_FPS_INTERVAL) { | ||
505 | frameRate_ = frames_/accumDt_; | ||
506 | frames_ = 0; | ||
507 | accumDt_ = 0; | ||
508 | |||
509 | // sprintf(format,"%.1f",frameRate); | ||
510 | // [FPSLabel setCString:format]; | ||
511 | |||
512 | NSString *str = [[NSString alloc] initWithFormat:@"%.1f", frameRate_]; | ||
513 | [FPSLabel_ setString:str]; | ||
514 | [str release]; | ||
515 | } | ||
516 | |||
517 | [FPSLabel_ draw]; | ||
518 | } | ||
519 | #else | ||
520 | // display the FPS using a manually generated Texture (very slow) | ||
521 | // updates the FPS 3 times per second aprox. | ||
522 | -(void) showFPS | ||
523 | { | ||
524 | frames_++; | ||
525 | accumDt_ += dt; | ||
526 | |||
527 | if ( accumDt_ > CC_DIRECTOR_FPS_INTERVAL) { | ||
528 | frameRate_ = frames_/accumDt_; | ||
529 | frames_ = 0; | ||
530 | accumDt_ = 0; | ||
531 | } | ||
532 | |||
533 | NSString *str = [NSString stringWithFormat:@"%.2f",frameRate_]; | ||
534 | CCTexture2D *texture = [[CCTexture2D alloc] initWithString:str dimensions:CGSizeMake(100,30) alignment:CCTextAlignmentLeft fontName:@"Arial" fontSize:24]; | ||
535 | |||
536 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
537 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
538 | // Unneeded states: GL_COLOR_ARRAY | ||
539 | glDisableClientState(GL_COLOR_ARRAY); | ||
540 | |||
541 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
542 | |||
543 | glColor4ub(224,224,244,200); | ||
544 | [texture drawAtPoint: ccp(5,2)]; | ||
545 | [texture release]; | ||
546 | |||
547 | glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); | ||
548 | |||
549 | // restore default GL state | ||
550 | glEnableClientState(GL_COLOR_ARRAY); | ||
551 | } | ||
552 | #endif | ||
553 | |||
554 | - (void) showProfilers { | ||
555 | #if CC_ENABLE_PROFILERS | ||
556 | accumDtForProfiler_ += dt; | ||
557 | if (accumDtForProfiler_ > 1.0f) { | ||
558 | accumDtForProfiler_ = 0; | ||
559 | [[CCProfiler sharedProfiler] displayTimers]; | ||
560 | } | ||
561 | #endif // CC_ENABLE_PROFILERS | ||
562 | } | ||
563 | |||
564 | @end | ||
565 | |||
diff --git a/libs/cocos2d/CCDrawingPrimitives.h b/libs/cocos2d/CCDrawingPrimitives.h new file mode 100755 index 0000000..8d1dbe5 --- /dev/null +++ b/libs/cocos2d/CCDrawingPrimitives.h | |||
@@ -0,0 +1,92 @@ | |||
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 | #ifndef __CC_DRAWING_PRIMITIVES_H | ||
28 | #define __CC_DRAWING_PRIMITIVES_H | ||
29 | |||
30 | #import <Availability.h> | ||
31 | #import <Foundation/Foundation.h> | ||
32 | |||
33 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
34 | #import <CoreGraphics/CGGeometry.h> // for CGPoint | ||
35 | #endif | ||
36 | |||
37 | |||
38 | #ifdef __cplusplus | ||
39 | extern "C" { | ||
40 | #endif | ||
41 | |||
42 | /** | ||
43 | @file | ||
44 | Drawing OpenGL ES primitives. | ||
45 | - ccDrawPoint | ||
46 | - ccDrawLine | ||
47 | - ccDrawPoly | ||
48 | - ccDrawCircle | ||
49 | - ccDrawQuadBezier | ||
50 | - ccDrawCubicBezier | ||
51 | |||
52 | You can change the color, width and other property by calling the | ||
53 | glColor4ub(), glLineWidth(), glPointSize(). | ||
54 | |||
55 | @warning These functions draws the Line, Point, Polygon, immediately. They aren't batched. If you are going to make a game that depends on these primitives, I suggest creating a batch. | ||
56 | */ | ||
57 | |||
58 | |||
59 | /** draws a point given x and y coordinate measured in points. */ | ||
60 | void ccDrawPoint( CGPoint point ); | ||
61 | |||
62 | /** draws an array of points. | ||
63 | @since v0.7.2 | ||
64 | */ | ||
65 | void ccDrawPoints( const CGPoint *points, NSUInteger numberOfPoints ); | ||
66 | |||
67 | /** draws a line given the origin and destination point measured in points. */ | ||
68 | void ccDrawLine( CGPoint origin, CGPoint destination ); | ||
69 | |||
70 | /** draws a poligon given a pointer to CGPoint coordiantes and the number of vertices measured in points. | ||
71 | The polygon can be closed or open | ||
72 | */ | ||
73 | void ccDrawPoly( const CGPoint *vertices, NSUInteger numOfVertices, BOOL closePolygon ); | ||
74 | |||
75 | /** draws a circle given the center, radius and number of segments measured in points */ | ||
76 | void ccDrawCircle( CGPoint center, float radius, float angle, NSUInteger segments, BOOL drawLineToCenter); | ||
77 | |||
78 | /** draws a quad bezier path measured in points. | ||
79 | @since v0.8 | ||
80 | */ | ||
81 | void ccDrawQuadBezier(CGPoint origin, CGPoint control, CGPoint destination, NSUInteger segments); | ||
82 | |||
83 | /** draws a cubic bezier path measured in points. | ||
84 | @since v0.8 | ||
85 | */ | ||
86 | void ccDrawCubicBezier(CGPoint origin, CGPoint control1, CGPoint control2, CGPoint destination, NSUInteger segments); | ||
87 | |||
88 | #ifdef __cplusplus | ||
89 | } | ||
90 | #endif | ||
91 | |||
92 | #endif // __CC_DRAWING_PRIMITIVES_H | ||
diff --git a/libs/cocos2d/CCDrawingPrimitives.m b/libs/cocos2d/CCDrawingPrimitives.m new file mode 100755 index 0000000..f7df2b6 --- /dev/null +++ b/libs/cocos2d/CCDrawingPrimitives.m | |||
@@ -0,0 +1,272 @@ | |||
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 | #import <math.h> | ||
27 | #import <stdlib.h> | ||
28 | #import <string.h> | ||
29 | |||
30 | #import "CCDrawingPrimitives.h" | ||
31 | #import "ccTypes.h" | ||
32 | #import "ccMacros.h" | ||
33 | #import "Platforms/CCGL.h" | ||
34 | |||
35 | void ccDrawPoint( CGPoint point ) | ||
36 | { | ||
37 | ccVertex2F p = (ccVertex2F) {point.x * CC_CONTENT_SCALE_FACTOR(), point.y * CC_CONTENT_SCALE_FACTOR() }; | ||
38 | |||
39 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
40 | // Needed states: GL_VERTEX_ARRAY, | ||
41 | // Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY | ||
42 | glDisable(GL_TEXTURE_2D); | ||
43 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
44 | glDisableClientState(GL_COLOR_ARRAY); | ||
45 | |||
46 | glVertexPointer(2, GL_FLOAT, 0, &p); | ||
47 | glDrawArrays(GL_POINTS, 0, 1); | ||
48 | |||
49 | // restore default state | ||
50 | glEnableClientState(GL_COLOR_ARRAY); | ||
51 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
52 | glEnable(GL_TEXTURE_2D); | ||
53 | } | ||
54 | |||
55 | void ccDrawPoints( const CGPoint *points, NSUInteger numberOfPoints ) | ||
56 | { | ||
57 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
58 | // Needed states: GL_VERTEX_ARRAY, | ||
59 | // Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY | ||
60 | glDisable(GL_TEXTURE_2D); | ||
61 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
62 | glDisableClientState(GL_COLOR_ARRAY); | ||
63 | |||
64 | ccVertex2F newPoints[numberOfPoints]; | ||
65 | |||
66 | // iPhone and 32-bit machines optimization | ||
67 | if( sizeof(CGPoint) == sizeof(ccVertex2F) ) { | ||
68 | |||
69 | // points ? | ||
70 | if( CC_CONTENT_SCALE_FACTOR() != 1 ) { | ||
71 | for( NSUInteger i=0; i<numberOfPoints;i++) | ||
72 | newPoints[i] = (ccVertex2F){ points[i].x * CC_CONTENT_SCALE_FACTOR(), points[i].y * CC_CONTENT_SCALE_FACTOR() }; | ||
73 | |||
74 | glVertexPointer(2, GL_FLOAT, 0, newPoints); | ||
75 | |||
76 | } else | ||
77 | glVertexPointer(2, GL_FLOAT, 0, points); | ||
78 | |||
79 | glDrawArrays(GL_POINTS, 0, (GLsizei) numberOfPoints); | ||
80 | |||
81 | } else { | ||
82 | |||
83 | // Mac on 64-bit | ||
84 | for( NSUInteger i=0; i<numberOfPoints;i++) | ||
85 | newPoints[i] = (ccVertex2F) { points[i].x, points[i].y }; | ||
86 | |||
87 | glVertexPointer(2, GL_FLOAT, 0, newPoints); | ||
88 | glDrawArrays(GL_POINTS, 0, (GLsizei) numberOfPoints); | ||
89 | |||
90 | } | ||
91 | |||
92 | |||
93 | // restore default state | ||
94 | glEnableClientState(GL_COLOR_ARRAY); | ||
95 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
96 | glEnable(GL_TEXTURE_2D); | ||
97 | } | ||
98 | |||
99 | |||
100 | void ccDrawLine( CGPoint origin, CGPoint destination ) | ||
101 | { | ||
102 | ccVertex2F vertices[2] = { | ||
103 | {origin.x * CC_CONTENT_SCALE_FACTOR(), origin.y * CC_CONTENT_SCALE_FACTOR() }, | ||
104 | {destination.x * CC_CONTENT_SCALE_FACTOR(), destination.y * CC_CONTENT_SCALE_FACTOR() } | ||
105 | }; | ||
106 | |||
107 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
108 | // Needed states: GL_VERTEX_ARRAY, | ||
109 | // Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY | ||
110 | glDisable(GL_TEXTURE_2D); | ||
111 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
112 | glDisableClientState(GL_COLOR_ARRAY); | ||
113 | |||
114 | glVertexPointer(2, GL_FLOAT, 0, vertices); | ||
115 | glDrawArrays(GL_LINES, 0, 2); | ||
116 | |||
117 | // restore default state | ||
118 | glEnableClientState(GL_COLOR_ARRAY); | ||
119 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
120 | glEnable(GL_TEXTURE_2D); | ||
121 | } | ||
122 | |||
123 | |||
124 | void ccDrawPoly( const CGPoint *poli, NSUInteger numberOfPoints, BOOL closePolygon ) | ||
125 | { | ||
126 | ccVertex2F newPoint[numberOfPoints]; | ||
127 | |||
128 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
129 | // Needed states: GL_VERTEX_ARRAY, | ||
130 | // Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY | ||
131 | glDisable(GL_TEXTURE_2D); | ||
132 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
133 | glDisableClientState(GL_COLOR_ARRAY); | ||
134 | |||
135 | |||
136 | // iPhone and 32-bit machines | ||
137 | if( sizeof(CGPoint) == sizeof(ccVertex2F) ) { | ||
138 | |||
139 | // convert to pixels ? | ||
140 | if( CC_CONTENT_SCALE_FACTOR() != 1 ) { | ||
141 | memcpy( newPoint, poli, numberOfPoints * sizeof(ccVertex2F) ); | ||
142 | for( NSUInteger i=0; i<numberOfPoints;i++) | ||
143 | newPoint[i] = (ccVertex2F) { poli[i].x * CC_CONTENT_SCALE_FACTOR(), poli[i].y * CC_CONTENT_SCALE_FACTOR() }; | ||
144 | |||
145 | glVertexPointer(2, GL_FLOAT, 0, newPoint); | ||
146 | |||
147 | } else | ||
148 | glVertexPointer(2, GL_FLOAT, 0, poli); | ||
149 | |||
150 | |||
151 | } else { | ||
152 | // 64-bit machines (Mac) | ||
153 | |||
154 | for( NSUInteger i=0; i<numberOfPoints;i++) | ||
155 | newPoint[i] = (ccVertex2F) { poli[i].x, poli[i].y }; | ||
156 | |||
157 | glVertexPointer(2, GL_FLOAT, 0, newPoint ); | ||
158 | |||
159 | } | ||
160 | |||
161 | if( closePolygon ) | ||
162 | glDrawArrays(GL_LINE_LOOP, 0, (GLsizei) numberOfPoints); | ||
163 | else | ||
164 | glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) numberOfPoints); | ||
165 | |||
166 | // restore default state | ||
167 | glEnableClientState(GL_COLOR_ARRAY); | ||
168 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
169 | glEnable(GL_TEXTURE_2D); | ||
170 | } | ||
171 | |||
172 | void ccDrawCircle( CGPoint center, float r, float a, NSUInteger segs, BOOL drawLineToCenter) | ||
173 | { | ||
174 | int additionalSegment = 1; | ||
175 | if (drawLineToCenter) | ||
176 | additionalSegment++; | ||
177 | |||
178 | const float coef = 2.0f * (float)M_PI/segs; | ||
179 | |||
180 | GLfloat *vertices = calloc( sizeof(GLfloat)*2*(segs+2), 1); | ||
181 | if( ! vertices ) | ||
182 | return; | ||
183 | |||
184 | for(NSUInteger i=0;i<=segs;i++) | ||
185 | { | ||
186 | float rads = i*coef; | ||
187 | GLfloat j = r * cosf(rads + a) + center.x; | ||
188 | GLfloat k = r * sinf(rads + a) + center.y; | ||
189 | |||
190 | vertices[i*2] = j * CC_CONTENT_SCALE_FACTOR(); | ||
191 | vertices[i*2+1] =k * CC_CONTENT_SCALE_FACTOR(); | ||
192 | } | ||
193 | vertices[(segs+1)*2] = center.x * CC_CONTENT_SCALE_FACTOR(); | ||
194 | vertices[(segs+1)*2+1] = center.y * CC_CONTENT_SCALE_FACTOR(); | ||
195 | |||
196 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
197 | // Needed states: GL_VERTEX_ARRAY, | ||
198 | // Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY | ||
199 | glDisable(GL_TEXTURE_2D); | ||
200 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
201 | glDisableClientState(GL_COLOR_ARRAY); | ||
202 | |||
203 | glVertexPointer(2, GL_FLOAT, 0, vertices); | ||
204 | glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) segs+additionalSegment); | ||
205 | |||
206 | // restore default state | ||
207 | glEnableClientState(GL_COLOR_ARRAY); | ||
208 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
209 | glEnable(GL_TEXTURE_2D); | ||
210 | |||
211 | free( vertices ); | ||
212 | } | ||
213 | |||
214 | void ccDrawQuadBezier(CGPoint origin, CGPoint control, CGPoint destination, NSUInteger segments) | ||
215 | { | ||
216 | ccVertex2F vertices[segments + 1]; | ||
217 | |||
218 | float t = 0.0f; | ||
219 | for(NSUInteger i = 0; i < segments; i++) | ||
220 | { | ||
221 | GLfloat x = powf(1 - t, 2) * origin.x + 2.0f * (1 - t) * t * control.x + t * t * destination.x; | ||
222 | GLfloat y = powf(1 - t, 2) * origin.y + 2.0f * (1 - t) * t * control.y + t * t * destination.y; | ||
223 | vertices[i] = (ccVertex2F) {x * CC_CONTENT_SCALE_FACTOR(), y * CC_CONTENT_SCALE_FACTOR() }; | ||
224 | t += 1.0f / segments; | ||
225 | } | ||
226 | vertices[segments] = (ccVertex2F) {destination.x * CC_CONTENT_SCALE_FACTOR(), destination.y * CC_CONTENT_SCALE_FACTOR() }; | ||
227 | |||
228 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
229 | // Needed states: GL_VERTEX_ARRAY, | ||
230 | // Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY | ||
231 | glDisable(GL_TEXTURE_2D); | ||
232 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
233 | glDisableClientState(GL_COLOR_ARRAY); | ||
234 | |||
235 | glVertexPointer(2, GL_FLOAT, 0, vertices); | ||
236 | glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) segments + 1); | ||
237 | |||
238 | // restore default state | ||
239 | glEnableClientState(GL_COLOR_ARRAY); | ||
240 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
241 | glEnable(GL_TEXTURE_2D); | ||
242 | } | ||
243 | |||
244 | void ccDrawCubicBezier(CGPoint origin, CGPoint control1, CGPoint control2, CGPoint destination, NSUInteger segments) | ||
245 | { | ||
246 | ccVertex2F vertices[segments + 1]; | ||
247 | |||
248 | float t = 0; | ||
249 | for(NSUInteger i = 0; i < segments; i++) | ||
250 | { | ||
251 | GLfloat x = powf(1 - t, 3) * origin.x + 3.0f * powf(1 - t, 2) * t * control1.x + 3.0f * (1 - t) * t * t * control2.x + t * t * t * destination.x; | ||
252 | GLfloat y = powf(1 - t, 3) * origin.y + 3.0f * powf(1 - t, 2) * t * control1.y + 3.0f * (1 - t) * t * t * control2.y + t * t * t * destination.y; | ||
253 | vertices[i] = (ccVertex2F) {x * CC_CONTENT_SCALE_FACTOR(), y * CC_CONTENT_SCALE_FACTOR() }; | ||
254 | t += 1.0f / segments; | ||
255 | } | ||
256 | vertices[segments] = (ccVertex2F) {destination.x * CC_CONTENT_SCALE_FACTOR(), destination.y * CC_CONTENT_SCALE_FACTOR() }; | ||
257 | |||
258 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
259 | // Needed states: GL_VERTEX_ARRAY, | ||
260 | // Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY | ||
261 | glDisable(GL_TEXTURE_2D); | ||
262 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
263 | glDisableClientState(GL_COLOR_ARRAY); | ||
264 | |||
265 | glVertexPointer(2, GL_FLOAT, 0, vertices); | ||
266 | glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) segments + 1); | ||
267 | |||
268 | // restore default state | ||
269 | glEnableClientState(GL_COLOR_ARRAY); | ||
270 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
271 | glEnable(GL_TEXTURE_2D); | ||
272 | } | ||
diff --git a/libs/cocos2d/CCGrabber.h b/libs/cocos2d/CCGrabber.h new file mode 100755 index 0000000..f1ce6cb --- /dev/null +++ b/libs/cocos2d/CCGrabber.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 On-Core | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "Platforms/CCGL.h" | ||
28 | #import <Foundation/Foundation.h> | ||
29 | |||
30 | @class CCTexture2D; | ||
31 | |||
32 | /** FBO class that grabs the the contents of the screen */ | ||
33 | @interface CCGrabber : NSObject | ||
34 | { | ||
35 | GLuint fbo; | ||
36 | GLint oldFBO; | ||
37 | } | ||
38 | |||
39 | -(void)grab:(CCTexture2D*)texture; | ||
40 | -(void)beforeRender:(CCTexture2D*)texture; | ||
41 | -(void)afterRender:(CCTexture2D*)texture; | ||
42 | |||
43 | @end | ||
diff --git a/libs/cocos2d/CCGrabber.m b/libs/cocos2d/CCGrabber.m new file mode 100755 index 0000000..a259091 --- /dev/null +++ b/libs/cocos2d/CCGrabber.m | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 On-Core | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "Platforms/CCGL.h" | ||
28 | #import "CCGrabber.h" | ||
29 | #import "ccMacros.h" | ||
30 | #import "CCTexture2D.h" | ||
31 | #import "Support/OpenGL_Internal.h" | ||
32 | |||
33 | @implementation CCGrabber | ||
34 | |||
35 | -(id) init | ||
36 | { | ||
37 | if(( self = [super init] )) { | ||
38 | // generate FBO | ||
39 | ccglGenFramebuffers(1, &fbo); | ||
40 | } | ||
41 | return self; | ||
42 | } | ||
43 | |||
44 | -(void)grab:(CCTexture2D*)texture | ||
45 | { | ||
46 | glGetIntegerv(CC_GL_FRAMEBUFFER_BINDING, &oldFBO); | ||
47 | |||
48 | // bind | ||
49 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, fbo); | ||
50 | |||
51 | // associate texture with FBO | ||
52 | ccglFramebufferTexture2D(CC_GL_FRAMEBUFFER, CC_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.name, 0); | ||
53 | |||
54 | // check if it worked (probably worth doing :) ) | ||
55 | GLuint status = ccglCheckFramebufferStatus(CC_GL_FRAMEBUFFER); | ||
56 | if (status != CC_GL_FRAMEBUFFER_COMPLETE) | ||
57 | [NSException raise:@"Frame Grabber" format:@"Could not attach texture to framebuffer"]; | ||
58 | |||
59 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, oldFBO); | ||
60 | } | ||
61 | |||
62 | -(void)beforeRender:(CCTexture2D*)texture | ||
63 | { | ||
64 | glGetIntegerv(CC_GL_FRAMEBUFFER_BINDING, &oldFBO); | ||
65 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, fbo); | ||
66 | |||
67 | // BUG XXX: doesn't work with RGB565. | ||
68 | |||
69 | |||
70 | glClearColor(0,0,0,0); | ||
71 | |||
72 | // BUG #631: To fix #631, uncomment the lines with #631 | ||
73 | // Warning: But it CCGrabber won't work with 2 effects at the same time | ||
74 | // glClearColor(0.0f,0.0f,0.0f,1.0f); // #631 | ||
75 | |||
76 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||
77 | |||
78 | // glColorMask(TRUE, TRUE, TRUE, FALSE); // #631 | ||
79 | |||
80 | } | ||
81 | |||
82 | -(void)afterRender:(CCTexture2D*)texture | ||
83 | { | ||
84 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, oldFBO); | ||
85 | // glColorMask(TRUE, TRUE, TRUE, TRUE); // #631 | ||
86 | } | ||
87 | |||
88 | - (void) dealloc | ||
89 | { | ||
90 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
91 | ccglDeleteFramebuffers(1, &fbo); | ||
92 | [super dealloc]; | ||
93 | } | ||
94 | |||
95 | @end | ||
diff --git a/libs/cocos2d/CCGrid.h b/libs/cocos2d/CCGrid.h new file mode 100755 index 0000000..e5e77e8 --- /dev/null +++ b/libs/cocos2d/CCGrid.h | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 On-Core | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import <Foundation/Foundation.h> | ||
28 | |||
29 | #import "CCNode.h" | ||
30 | #import "CCCamera.h" | ||
31 | #import "ccTypes.h" | ||
32 | |||
33 | @class CCTexture2D; | ||
34 | @class CCGrabber; | ||
35 | |||
36 | /** Base class for other | ||
37 | */ | ||
38 | @interface CCGridBase : NSObject | ||
39 | { | ||
40 | BOOL active_; | ||
41 | int reuseGrid_; | ||
42 | ccGridSize gridSize_; | ||
43 | CCTexture2D *texture_; | ||
44 | CGPoint step_; | ||
45 | CCGrabber *grabber_; | ||
46 | BOOL isTextureFlipped_; | ||
47 | } | ||
48 | |||
49 | /** wheter or not the grid is active */ | ||
50 | @property (nonatomic,readwrite) BOOL active; | ||
51 | /** number of times that the grid will be reused */ | ||
52 | @property (nonatomic,readwrite) int reuseGrid; | ||
53 | /** size of the grid */ | ||
54 | @property (nonatomic,readonly) ccGridSize gridSize; | ||
55 | /** pixels between the grids */ | ||
56 | @property (nonatomic,readwrite) CGPoint step; | ||
57 | /** texture used */ | ||
58 | @property (nonatomic, retain) CCTexture2D *texture; | ||
59 | /** grabber used */ | ||
60 | @property (nonatomic, retain) CCGrabber *grabber; | ||
61 | /** is texture flipped */ | ||
62 | @property (nonatomic, readwrite) BOOL isTextureFlipped; | ||
63 | |||
64 | +(id) gridWithSize:(ccGridSize)gridSize texture:(CCTexture2D*)texture flippedTexture:(BOOL)flipped; | ||
65 | +(id) gridWithSize:(ccGridSize)gridSize; | ||
66 | |||
67 | -(id) initWithSize:(ccGridSize)gridSize texture:(CCTexture2D*)texture flippedTexture:(BOOL)flipped; | ||
68 | -(id)initWithSize:(ccGridSize)gridSize; | ||
69 | -(void)beforeDraw; | ||
70 | -(void)afterDraw:(CCNode*)target; | ||
71 | -(void)blit; | ||
72 | -(void)reuse; | ||
73 | |||
74 | -(void)calculateVertexPoints; | ||
75 | |||
76 | @end | ||
77 | |||
78 | //////////////////////////////////////////////////////////// | ||
79 | |||
80 | /** | ||
81 | CCGrid3D is a 3D grid implementation. Each vertex has 3 dimensions: x,y,z | ||
82 | */ | ||
83 | @interface CCGrid3D : CCGridBase | ||
84 | { | ||
85 | GLvoid *texCoordinates; | ||
86 | GLvoid *vertices; | ||
87 | GLvoid *originalVertices; | ||
88 | GLushort *indices; | ||
89 | } | ||
90 | |||
91 | /** returns the vertex at a given position */ | ||
92 | -(ccVertex3F)vertex:(ccGridSize)pos; | ||
93 | /** returns the original (non-transformed) vertex at a given position */ | ||
94 | -(ccVertex3F)originalVertex:(ccGridSize)pos; | ||
95 | /** sets a new vertex at a given position */ | ||
96 | -(void)setVertex:(ccGridSize)pos vertex:(ccVertex3F)vertex; | ||
97 | |||
98 | @end | ||
99 | |||
100 | //////////////////////////////////////////////////////////// | ||
101 | |||
102 | /** | ||
103 | CCTiledGrid3D is a 3D grid implementation. It differs from Grid3D in that | ||
104 | the tiles can be separated from the grid. | ||
105 | */ | ||
106 | @interface CCTiledGrid3D : CCGridBase | ||
107 | { | ||
108 | GLvoid *texCoordinates; | ||
109 | GLvoid *vertices; | ||
110 | GLvoid *originalVertices; | ||
111 | GLushort *indices; | ||
112 | } | ||
113 | |||
114 | /** returns the tile at the given position */ | ||
115 | -(ccQuad3)tile:(ccGridSize)pos; | ||
116 | /** returns the original tile (untransformed) at the given position */ | ||
117 | -(ccQuad3)originalTile:(ccGridSize)pos; | ||
118 | /** sets a new tile */ | ||
119 | -(void)setTile:(ccGridSize)pos coords:(ccQuad3)coords; | ||
120 | |||
121 | @end | ||
diff --git a/libs/cocos2d/CCGrid.m b/libs/cocos2d/CCGrid.m new file mode 100755 index 0000000..c2ed19d --- /dev/null +++ b/libs/cocos2d/CCGrid.m | |||
@@ -0,0 +1,571 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 On-Core | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import <Availability.h> | ||
28 | |||
29 | #import "ccMacros.h" | ||
30 | #import "CCGrid.h" | ||
31 | #import "CCTexture2D.h" | ||
32 | #import "CCDirector.h" | ||
33 | #import "CCGrabber.h" | ||
34 | |||
35 | #import "Platforms/CCGL.h" | ||
36 | #import "Support/CGPointExtension.h" | ||
37 | #import "Support/ccUtils.h" | ||
38 | |||
39 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
40 | #import "Platforms/iOS/CCDirectorIOS.h" | ||
41 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
42 | |||
43 | #pragma mark - | ||
44 | #pragma mark CCGridBase | ||
45 | |||
46 | @implementation CCGridBase | ||
47 | |||
48 | @synthesize reuseGrid = reuseGrid_; | ||
49 | @synthesize texture = texture_; | ||
50 | @synthesize grabber = grabber_; | ||
51 | @synthesize gridSize = gridSize_; | ||
52 | @synthesize step = step_; | ||
53 | |||
54 | +(id) gridWithSize:(ccGridSize)gridSize texture:(CCTexture2D*)texture flippedTexture:(BOOL)flipped | ||
55 | { | ||
56 | return [[[self alloc] initWithSize:gridSize texture:texture flippedTexture:flipped] autorelease]; | ||
57 | } | ||
58 | |||
59 | +(id) gridWithSize:(ccGridSize)gridSize | ||
60 | { | ||
61 | return [[(CCGridBase*)[self alloc] initWithSize:gridSize] autorelease]; | ||
62 | } | ||
63 | |||
64 | -(id) initWithSize:(ccGridSize)gridSize texture:(CCTexture2D*)texture flippedTexture:(BOOL)flipped | ||
65 | { | ||
66 | if( (self=[super init]) ) { | ||
67 | |||
68 | active_ = NO; | ||
69 | reuseGrid_ = 0; | ||
70 | gridSize_ = gridSize; | ||
71 | |||
72 | self.texture = texture; | ||
73 | isTextureFlipped_ = flipped; | ||
74 | |||
75 | CGSize texSize = [texture_ contentSizeInPixels]; | ||
76 | step_.x = texSize.width / gridSize_.x; | ||
77 | step_.y = texSize.height / gridSize_.y; | ||
78 | |||
79 | grabber_ = [[CCGrabber alloc] init]; | ||
80 | [grabber_ grab:texture_]; | ||
81 | |||
82 | [self calculateVertexPoints]; | ||
83 | } | ||
84 | return self; | ||
85 | } | ||
86 | |||
87 | -(id)initWithSize:(ccGridSize)gSize | ||
88 | { | ||
89 | CCDirector *director = [CCDirector sharedDirector]; | ||
90 | CGSize s = [director winSizeInPixels]; | ||
91 | |||
92 | unsigned long POTWide = ccNextPOT(s.width); | ||
93 | unsigned long POTHigh = ccNextPOT(s.height); | ||
94 | |||
95 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
96 | EAGLView *glview = [[CCDirector sharedDirector] openGLView]; | ||
97 | NSString *pixelFormat = [glview pixelFormat]; | ||
98 | |||
99 | CCTexture2DPixelFormat format = [pixelFormat isEqualToString: kEAGLColorFormatRGB565] ? kCCTexture2DPixelFormat_RGB565 : kCCTexture2DPixelFormat_RGBA8888; | ||
100 | #else | ||
101 | CCTexture2DPixelFormat format = kCCTexture2DPixelFormat_RGBA8888; | ||
102 | #endif | ||
103 | |||
104 | void *data = calloc((int)(POTWide * POTHigh * 4), 1); | ||
105 | if( ! data ) { | ||
106 | CCLOG(@"cocos2d: CCGrid: not enough memory"); | ||
107 | [self release]; | ||
108 | return nil; | ||
109 | } | ||
110 | |||
111 | CCTexture2D *texture = [[CCTexture2D alloc] initWithData:data pixelFormat:format pixelsWide:POTWide pixelsHigh:POTHigh contentSize:s]; | ||
112 | free( data ); | ||
113 | |||
114 | if( ! texture ) { | ||
115 | CCLOG(@"cocos2d: CCGrid: error creating texture"); | ||
116 | [self release]; | ||
117 | return nil; | ||
118 | } | ||
119 | |||
120 | self = [self initWithSize:gSize texture:texture flippedTexture:NO]; | ||
121 | |||
122 | [texture release]; | ||
123 | |||
124 | return self; | ||
125 | } | ||
126 | - (NSString*) description | ||
127 | { | ||
128 | return [NSString stringWithFormat:@"<%@ = %08X | Dimensions = %ix%i>", [self class], self, gridSize_.x, gridSize_.y]; | ||
129 | } | ||
130 | |||
131 | - (void) dealloc | ||
132 | { | ||
133 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
134 | |||
135 | [self setActive: NO]; | ||
136 | |||
137 | [texture_ release]; | ||
138 | [grabber_ release]; | ||
139 | [super dealloc]; | ||
140 | } | ||
141 | |||
142 | // properties | ||
143 | -(BOOL) active | ||
144 | { | ||
145 | return active_; | ||
146 | } | ||
147 | |||
148 | -(void) setActive:(BOOL)active | ||
149 | { | ||
150 | active_ = active; | ||
151 | if( ! active ) { | ||
152 | CCDirector *director = [CCDirector sharedDirector]; | ||
153 | ccDirectorProjection proj = [director projection]; | ||
154 | [director setProjection:proj]; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | -(BOOL) isTextureFlipped | ||
159 | { | ||
160 | return isTextureFlipped_; | ||
161 | } | ||
162 | |||
163 | -(void) setIsTextureFlipped:(BOOL)flipped | ||
164 | { | ||
165 | if( isTextureFlipped_ != flipped ) { | ||
166 | isTextureFlipped_ = flipped; | ||
167 | [self calculateVertexPoints]; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | // This routine can be merged with Director | ||
172 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
173 | -(void)applyLandscape | ||
174 | { | ||
175 | CCDirector *director = [CCDirector sharedDirector]; | ||
176 | |||
177 | CGSize winSize = [director displaySizeInPixels]; | ||
178 | float w = winSize.width / 2; | ||
179 | float h = winSize.height / 2; | ||
180 | |||
181 | ccDeviceOrientation orientation = [director deviceOrientation]; | ||
182 | |||
183 | switch (orientation) { | ||
184 | case CCDeviceOrientationLandscapeLeft: | ||
185 | glTranslatef(w,h,0); | ||
186 | glRotatef(-90,0,0,1); | ||
187 | glTranslatef(-h,-w,0); | ||
188 | break; | ||
189 | case CCDeviceOrientationLandscapeRight: | ||
190 | glTranslatef(w,h,0); | ||
191 | glRotatef(90,0,0,1); | ||
192 | glTranslatef(-h,-w,0); | ||
193 | break; | ||
194 | case CCDeviceOrientationPortraitUpsideDown: | ||
195 | glTranslatef(w,h,0); | ||
196 | glRotatef(180,0,0,1); | ||
197 | glTranslatef(-w,-h,0); | ||
198 | break; | ||
199 | default: | ||
200 | break; | ||
201 | } | ||
202 | } | ||
203 | #endif | ||
204 | |||
205 | -(void)set2DProjection | ||
206 | { | ||
207 | CGSize winSize = [[CCDirector sharedDirector] winSizeInPixels]; | ||
208 | |||
209 | glLoadIdentity(); | ||
210 | glViewport(0, 0, winSize.width, winSize.height); | ||
211 | glMatrixMode(GL_PROJECTION); | ||
212 | glLoadIdentity(); | ||
213 | ccglOrtho(0, winSize.width, 0, winSize.height, -1024, 1024); | ||
214 | glMatrixMode(GL_MODELVIEW); | ||
215 | } | ||
216 | |||
217 | // This routine can be merged with Director | ||
218 | -(void)set3DProjection | ||
219 | { | ||
220 | CCDirector *director = [CCDirector sharedDirector]; | ||
221 | |||
222 | CGSize winSize = [director displaySizeInPixels]; | ||
223 | |||
224 | glViewport(0, 0, winSize.width, winSize.height); | ||
225 | glMatrixMode(GL_PROJECTION); | ||
226 | glLoadIdentity(); | ||
227 | gluPerspective(60, (GLfloat)winSize.width/winSize.height, 0.5f, 1500.0f); | ||
228 | |||
229 | glMatrixMode(GL_MODELVIEW); | ||
230 | glLoadIdentity(); | ||
231 | gluLookAt( winSize.width/2, winSize.height/2, [director getZEye], | ||
232 | winSize.width/2, winSize.height/2, 0, | ||
233 | 0.0f, 1.0f, 0.0f | ||
234 | ); | ||
235 | } | ||
236 | |||
237 | -(void)beforeDraw | ||
238 | { | ||
239 | [self set2DProjection]; | ||
240 | [grabber_ beforeRender:texture_]; | ||
241 | } | ||
242 | |||
243 | -(void)afterDraw:(CCNode *)target | ||
244 | { | ||
245 | [grabber_ afterRender:texture_]; | ||
246 | |||
247 | [self set3DProjection]; | ||
248 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
249 | [self applyLandscape]; | ||
250 | #endif | ||
251 | |||
252 | if( target.camera.dirty ) { | ||
253 | |||
254 | CGPoint offset = [target anchorPointInPixels]; | ||
255 | |||
256 | // | ||
257 | // XXX: Camera should be applied in the AnchorPoint | ||
258 | // | ||
259 | ccglTranslate(offset.x, offset.y, 0); | ||
260 | [target.camera locate]; | ||
261 | ccglTranslate(-offset.x, -offset.y, 0); | ||
262 | } | ||
263 | |||
264 | glBindTexture(GL_TEXTURE_2D, texture_.name); | ||
265 | |||
266 | [self blit]; | ||
267 | } | ||
268 | |||
269 | -(void)blit | ||
270 | { | ||
271 | [NSException raise:@"GridBase" format:@"Abstract class needs implementation"]; | ||
272 | } | ||
273 | |||
274 | -(void)reuse | ||
275 | { | ||
276 | [NSException raise:@"GridBase" format:@"Abstract class needs implementation"]; | ||
277 | } | ||
278 | |||
279 | -(void)calculateVertexPoints | ||
280 | { | ||
281 | [NSException raise:@"GridBase" format:@"Abstract class needs implementation"]; | ||
282 | } | ||
283 | |||
284 | @end | ||
285 | |||
286 | //////////////////////////////////////////////////////////// | ||
287 | |||
288 | #pragma mark - | ||
289 | #pragma mark CCGrid3D | ||
290 | @implementation CCGrid3D | ||
291 | |||
292 | -(void)dealloc | ||
293 | { | ||
294 | free(texCoordinates); | ||
295 | free(vertices); | ||
296 | free(indices); | ||
297 | free(originalVertices); | ||
298 | [super dealloc]; | ||
299 | } | ||
300 | |||
301 | -(void)blit | ||
302 | { | ||
303 | NSInteger n = gridSize_.x * gridSize_.y; | ||
304 | |||
305 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
306 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
307 | // Unneeded states: GL_COLOR_ARRAY | ||
308 | glDisableClientState(GL_COLOR_ARRAY); | ||
309 | |||
310 | glVertexPointer(3, GL_FLOAT, 0, vertices); | ||
311 | glTexCoordPointer(2, GL_FLOAT, 0, texCoordinates); | ||
312 | glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, indices); | ||
313 | |||
314 | // restore GL default state | ||
315 | glEnableClientState(GL_COLOR_ARRAY); | ||
316 | } | ||
317 | |||
318 | -(void)calculateVertexPoints | ||
319 | { | ||
320 | float width = (float)texture_.pixelsWide; | ||
321 | float height = (float)texture_.pixelsHigh; | ||
322 | float imageH = texture_.contentSizeInPixels.height; | ||
323 | |||
324 | int x, y, i; | ||
325 | |||
326 | vertices = malloc((gridSize_.x+1)*(gridSize_.y+1)*sizeof(ccVertex3F)); | ||
327 | originalVertices = malloc((gridSize_.x+1)*(gridSize_.y+1)*sizeof(ccVertex3F)); | ||
328 | texCoordinates = malloc((gridSize_.x+1)*(gridSize_.y+1)*sizeof(CGPoint)); | ||
329 | indices = malloc(gridSize_.x*gridSize_.y*sizeof(GLushort)*6); | ||
330 | |||
331 | float *vertArray = (float*)vertices; | ||
332 | float *texArray = (float*)texCoordinates; | ||
333 | GLushort *idxArray = (GLushort *)indices; | ||
334 | |||
335 | for( x = 0; x < gridSize_.x; x++ ) | ||
336 | { | ||
337 | for( y = 0; y < gridSize_.y; y++ ) | ||
338 | { | ||
339 | NSInteger idx = (y * gridSize_.x) + x; | ||
340 | |||
341 | float x1 = x * step_.x; | ||
342 | float x2 = x1 + step_.x; | ||
343 | float y1 = y * step_.y; | ||
344 | float y2 = y1 + step_.y; | ||
345 | |||
346 | GLushort a = x * (gridSize_.y+1) + y; | ||
347 | GLushort b = (x+1) * (gridSize_.y+1) + y; | ||
348 | GLushort c = (x+1) * (gridSize_.y+1) + (y+1); | ||
349 | GLushort d = x * (gridSize_.y+1) + (y+1); | ||
350 | |||
351 | GLushort tempidx[6] = { a, b, d, b, c, d }; | ||
352 | |||
353 | memcpy(&idxArray[6*idx], tempidx, 6*sizeof(GLushort)); | ||
354 | |||
355 | int l1[4] = { a*3, b*3, c*3, d*3 }; | ||
356 | ccVertex3F e = {x1,y1,0}; | ||
357 | ccVertex3F f = {x2,y1,0}; | ||
358 | ccVertex3F g = {x2,y2,0}; | ||
359 | ccVertex3F h = {x1,y2,0}; | ||
360 | |||
361 | ccVertex3F l2[4] = { e, f, g, h }; | ||
362 | |||
363 | int tex1[4] = { a*2, b*2, c*2, d*2 }; | ||
364 | CGPoint tex2[4] = { ccp(x1, y1), ccp(x2, y1), ccp(x2, y2), ccp(x1, y2) }; | ||
365 | |||
366 | for( i = 0; i < 4; i++ ) | ||
367 | { | ||
368 | vertArray[ l1[i] ] = l2[i].x; | ||
369 | vertArray[ l1[i] + 1 ] = l2[i].y; | ||
370 | vertArray[ l1[i] + 2 ] = l2[i].z; | ||
371 | |||
372 | texArray[ tex1[i] ] = tex2[i].x / width; | ||
373 | if( isTextureFlipped_ ) | ||
374 | texArray[ tex1[i] + 1 ] = (imageH - tex2[i].y) / height; | ||
375 | else | ||
376 | texArray[ tex1[i] + 1 ] = tex2[i].y / height; | ||
377 | } | ||
378 | } | ||
379 | } | ||
380 | |||
381 | memcpy(originalVertices, vertices, (gridSize_.x+1)*(gridSize_.y+1)*sizeof(ccVertex3F)); | ||
382 | } | ||
383 | |||
384 | -(ccVertex3F)vertex:(ccGridSize)pos | ||
385 | { | ||
386 | NSInteger index = (pos.x * (gridSize_.y+1) + pos.y) * 3; | ||
387 | float *vertArray = (float *)vertices; | ||
388 | |||
389 | ccVertex3F vert = { vertArray[index], vertArray[index+1], vertArray[index+2] }; | ||
390 | |||
391 | return vert; | ||
392 | } | ||
393 | |||
394 | -(ccVertex3F)originalVertex:(ccGridSize)pos | ||
395 | { | ||
396 | NSInteger index = (pos.x * (gridSize_.y+1) + pos.y) * 3; | ||
397 | float *vertArray = (float *)originalVertices; | ||
398 | |||
399 | ccVertex3F vert = { vertArray[index], vertArray[index+1], vertArray[index+2] }; | ||
400 | |||
401 | return vert; | ||
402 | } | ||
403 | |||
404 | -(void)setVertex:(ccGridSize)pos vertex:(ccVertex3F)vertex | ||
405 | { | ||
406 | NSInteger index = (pos.x * (gridSize_.y+1) + pos.y) * 3; | ||
407 | float *vertArray = (float *)vertices; | ||
408 | vertArray[index] = vertex.x; | ||
409 | vertArray[index+1] = vertex.y; | ||
410 | vertArray[index+2] = vertex.z; | ||
411 | } | ||
412 | |||
413 | -(void)reuse | ||
414 | { | ||
415 | if ( reuseGrid_ > 0 ) | ||
416 | { | ||
417 | memcpy(originalVertices, vertices, (gridSize_.x+1)*(gridSize_.y+1)*sizeof(ccVertex3F)); | ||
418 | reuseGrid_--; | ||
419 | } | ||
420 | } | ||
421 | |||
422 | @end | ||
423 | |||
424 | //////////////////////////////////////////////////////////// | ||
425 | |||
426 | #pragma mark - | ||
427 | #pragma mark CCTiledGrid3D | ||
428 | |||
429 | @implementation CCTiledGrid3D | ||
430 | |||
431 | -(void)dealloc | ||
432 | { | ||
433 | free(texCoordinates); | ||
434 | free(vertices); | ||
435 | free(indices); | ||
436 | free(originalVertices); | ||
437 | [super dealloc]; | ||
438 | } | ||
439 | |||
440 | -(void)blit | ||
441 | { | ||
442 | NSInteger n = gridSize_.x * gridSize_.y; | ||
443 | |||
444 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
445 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
446 | // Unneeded states: GL_COLOR_ARRAY | ||
447 | glDisableClientState(GL_COLOR_ARRAY); | ||
448 | |||
449 | glVertexPointer(3, GL_FLOAT, 0, vertices); | ||
450 | glTexCoordPointer(2, GL_FLOAT, 0, texCoordinates); | ||
451 | glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, indices); | ||
452 | |||
453 | // restore default GL state | ||
454 | glEnableClientState(GL_COLOR_ARRAY); | ||
455 | } | ||
456 | |||
457 | -(void)calculateVertexPoints | ||
458 | { | ||
459 | float width = (float)texture_.pixelsWide; | ||
460 | float height = (float)texture_.pixelsHigh; | ||
461 | float imageH = texture_.contentSizeInPixels.height; | ||
462 | |||
463 | NSInteger numQuads = gridSize_.x * gridSize_.y; | ||
464 | |||
465 | vertices = malloc(numQuads*12*sizeof(GLfloat)); | ||
466 | originalVertices = malloc(numQuads*12*sizeof(GLfloat)); | ||
467 | texCoordinates = malloc(numQuads*8*sizeof(GLfloat)); | ||
468 | indices = malloc(numQuads*6*sizeof(GLushort)); | ||
469 | |||
470 | float *vertArray = (float*)vertices; | ||
471 | float *texArray = (float*)texCoordinates; | ||
472 | GLushort *idxArray = (GLushort *)indices; | ||
473 | |||
474 | int x, y; | ||
475 | |||
476 | for( x = 0; x < gridSize_.x; x++ ) | ||
477 | { | ||
478 | for( y = 0; y < gridSize_.y; y++ ) | ||
479 | { | ||
480 | float x1 = x * step_.x; | ||
481 | float x2 = x1 + step_.x; | ||
482 | float y1 = y * step_.y; | ||
483 | float y2 = y1 + step_.y; | ||
484 | |||
485 | *vertArray++ = x1; | ||
486 | *vertArray++ = y1; | ||
487 | *vertArray++ = 0; | ||
488 | *vertArray++ = x2; | ||
489 | *vertArray++ = y1; | ||
490 | *vertArray++ = 0; | ||
491 | *vertArray++ = x1; | ||
492 | *vertArray++ = y2; | ||
493 | *vertArray++ = 0; | ||
494 | *vertArray++ = x2; | ||
495 | *vertArray++ = y2; | ||
496 | *vertArray++ = 0; | ||
497 | |||
498 | float newY1 = y1; | ||
499 | float newY2 = y2; | ||
500 | |||
501 | if( isTextureFlipped_ ) { | ||
502 | newY1 = imageH - y1; | ||
503 | newY2 = imageH - y2; | ||
504 | } | ||
505 | |||
506 | *texArray++ = x1 / width; | ||
507 | *texArray++ = newY1 / height; | ||
508 | *texArray++ = x2 / width; | ||
509 | *texArray++ = newY1 / height; | ||
510 | *texArray++ = x1 / width; | ||
511 | *texArray++ = newY2 / height; | ||
512 | *texArray++ = x2 / width; | ||
513 | *texArray++ = newY2 / height; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | for( x = 0; x < numQuads; x++) | ||
518 | { | ||
519 | idxArray[x*6+0] = x*4+0; | ||
520 | idxArray[x*6+1] = x*4+1; | ||
521 | idxArray[x*6+2] = x*4+2; | ||
522 | |||
523 | idxArray[x*6+3] = x*4+1; | ||
524 | idxArray[x*6+4] = x*4+2; | ||
525 | idxArray[x*6+5] = x*4+3; | ||
526 | } | ||
527 | |||
528 | memcpy(originalVertices, vertices, numQuads*12*sizeof(GLfloat)); | ||
529 | } | ||
530 | |||
531 | -(void)setTile:(ccGridSize)pos coords:(ccQuad3)coords | ||
532 | { | ||
533 | NSInteger idx = (gridSize_.y * pos.x + pos.y) * 4 * 3; | ||
534 | float *vertArray = (float*)vertices; | ||
535 | memcpy(&vertArray[idx], &coords, sizeof(ccQuad3)); | ||
536 | } | ||
537 | |||
538 | -(ccQuad3)originalTile:(ccGridSize)pos | ||
539 | { | ||
540 | NSInteger idx = (gridSize_.y * pos.x + pos.y) * 4 * 3; | ||
541 | float *vertArray = (float*)originalVertices; | ||
542 | |||
543 | ccQuad3 ret; | ||
544 | memcpy(&ret, &vertArray[idx], sizeof(ccQuad3)); | ||
545 | |||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | -(ccQuad3)tile:(ccGridSize)pos | ||
550 | { | ||
551 | NSInteger idx = (gridSize_.y * pos.x + pos.y) * 4 * 3; | ||
552 | float *vertArray = (float*)vertices; | ||
553 | |||
554 | ccQuad3 ret; | ||
555 | memcpy(&ret, &vertArray[idx], sizeof(ccQuad3)); | ||
556 | |||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | -(void)reuse | ||
561 | { | ||
562 | if ( reuseGrid_ > 0 ) | ||
563 | { | ||
564 | NSInteger numQuads = gridSize_.x * gridSize_.y; | ||
565 | |||
566 | memcpy(originalVertices, vertices, numQuads*12*sizeof(GLfloat)); | ||
567 | reuseGrid_--; | ||
568 | } | ||
569 | } | ||
570 | |||
571 | @end | ||
diff --git a/libs/cocos2d/CCLabelAtlas.h b/libs/cocos2d/CCLabelAtlas.h new file mode 100755 index 0000000..f7781a4 --- /dev/null +++ b/libs/cocos2d/CCLabelAtlas.h | |||
@@ -0,0 +1,62 @@ | |||
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 | #import "CCAtlasNode.h" | ||
29 | #import "CCTextureAtlas.h" | ||
30 | |||
31 | /** CCLabelAtlas is a subclass of CCAtlasNode. | ||
32 | |||
33 | It can be as a replacement of CCLabel since it is MUCH faster. | ||
34 | |||
35 | CCLabelAtlas versus CCLabel: | ||
36 | - CCLabelAtlas is MUCH faster than CCLabel | ||
37 | - CCLabelAtlas "characters" have a fixed height and width | ||
38 | - CCLabelAtlas "characters" can be anything you want since they are taken from an image file | ||
39 | |||
40 | A more flexible class is CCLabelBMFont. It supports variable width characters and it also has a nice editor. | ||
41 | */ | ||
42 | @interface CCLabelAtlas : CCAtlasNode <CCLabelProtocol> | ||
43 | { | ||
44 | // string to render | ||
45 | NSString *string_; | ||
46 | |||
47 | // the first char in the charmap | ||
48 | unsigned char mapStartChar_; | ||
49 | } | ||
50 | |||
51 | |||
52 | /** creates the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element in points and the starting char of the atlas */ | ||
53 | +(id) labelWithString:(NSString*) string charMapFile: (NSString*) charmapfile itemWidth:(NSUInteger)w itemHeight:(NSUInteger)h startCharMap:(unsigned char)c; | ||
54 | |||
55 | /** creates the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element in points and the starting char of the atlas. | ||
56 | @deprecated Will be removed in 1.0.1. Use "labelWithString:" instead | ||
57 | */ | ||
58 | +(id) labelAtlasWithString:(NSString*) string charMapFile: (NSString*) charmapfile itemWidth:(NSUInteger)w itemHeight:(NSUInteger)h startCharMap:(unsigned char)c DEPRECATED_ATTRIBUTE; | ||
59 | |||
60 | /** initializes the CCLabelAtlas with a string, a char map file(the atlas), the width and height in points of each element and the starting char of the atlas */ | ||
61 | -(id) initWithString:(NSString*) string charMapFile: (NSString*) charmapfile itemWidth:(NSUInteger)w itemHeight:(NSUInteger)h startCharMap:(unsigned char)c; | ||
62 | @end | ||
diff --git a/libs/cocos2d/CCLabelAtlas.m b/libs/cocos2d/CCLabelAtlas.m new file mode 100755 index 0000000..386f8c3 --- /dev/null +++ b/libs/cocos2d/CCLabelAtlas.m | |||
@@ -0,0 +1,170 @@ | |||
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 | #import "ccConfig.h" | ||
29 | #import "ccMacros.h" | ||
30 | #import "CCDrawingPrimitives.h" | ||
31 | #import "CCLabelAtlas.h" | ||
32 | #import "Support/CGPointExtension.h" | ||
33 | |||
34 | |||
35 | |||
36 | @implementation CCLabelAtlas | ||
37 | |||
38 | #pragma mark CCLabelAtlas - Creation & Init | ||
39 | +(id) labelWithString:(NSString*)string charMapFile:(NSString*)charmapfile itemWidth:(NSUInteger)w itemHeight:(NSUInteger)h startCharMap:(unsigned char)c | ||
40 | { | ||
41 | return [[[self alloc] initWithString:string charMapFile:charmapfile itemWidth:w itemHeight:h startCharMap:c] autorelease]; | ||
42 | } | ||
43 | |||
44 | // XXX DEPRECATED. Remove it in 1.0.1 | ||
45 | +(id) labelAtlasWithString:(NSString*) string charMapFile: (NSString*) charmapfile itemWidth:(NSUInteger)w itemHeight:(NSUInteger)h startCharMap:(unsigned char)c | ||
46 | { | ||
47 | return [self labelWithString:string charMapFile:charmapfile itemWidth:w itemHeight:h startCharMap:c]; | ||
48 | } | ||
49 | |||
50 | |||
51 | -(id) initWithString:(NSString*) theString charMapFile: (NSString*) charmapfile itemWidth:(NSUInteger)w itemHeight:(NSUInteger)h startCharMap:(unsigned char)c | ||
52 | { | ||
53 | |||
54 | if ((self=[super initWithTileFile:charmapfile tileWidth:w tileHeight:h itemsToRender:[theString length] ]) ) { | ||
55 | |||
56 | mapStartChar_ = c; | ||
57 | [self setString: theString]; | ||
58 | } | ||
59 | |||
60 | return self; | ||
61 | } | ||
62 | |||
63 | -(void) dealloc | ||
64 | { | ||
65 | [string_ release]; | ||
66 | |||
67 | [super dealloc]; | ||
68 | } | ||
69 | |||
70 | #pragma mark CCLabelAtlas - Atlas generation | ||
71 | |||
72 | -(void) updateAtlasValues | ||
73 | { | ||
74 | NSUInteger n = [string_ length]; | ||
75 | |||
76 | ccV3F_C4B_T2F_Quad quad; | ||
77 | |||
78 | const unsigned char *s = (unsigned char*) [string_ UTF8String]; | ||
79 | |||
80 | CCTexture2D *texture = [textureAtlas_ texture]; | ||
81 | float textureWide = [texture pixelsWide]; | ||
82 | float textureHigh = [texture pixelsHigh]; | ||
83 | |||
84 | for( NSUInteger i=0; i<n; i++) { | ||
85 | unsigned char a = s[i] - mapStartChar_; | ||
86 | float row = (a % itemsPerRow_); | ||
87 | float col = (a / itemsPerRow_); | ||
88 | |||
89 | #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
90 | // Issue #938. Don't use texStepX & texStepY | ||
91 | float left = (2*row*itemWidth_+1)/(2*textureWide); | ||
92 | float right = left+(itemWidth_*2-2)/(2*textureWide); | ||
93 | float top = (2*col*itemHeight_+1)/(2*textureHigh); | ||
94 | float bottom = top+(itemHeight_*2-2)/(2*textureHigh); | ||
95 | #else | ||
96 | float left = row*itemWidth_/textureWide; | ||
97 | float right = left+itemWidth_/textureWide; | ||
98 | float top = col*itemHeight_/textureHigh; | ||
99 | float bottom = top+itemHeight_/textureHigh; | ||
100 | #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
101 | |||
102 | quad.tl.texCoords.u = left; | ||
103 | quad.tl.texCoords.v = top; | ||
104 | quad.tr.texCoords.u = right; | ||
105 | quad.tr.texCoords.v = top; | ||
106 | quad.bl.texCoords.u = left; | ||
107 | quad.bl.texCoords.v = bottom; | ||
108 | quad.br.texCoords.u = right; | ||
109 | quad.br.texCoords.v = bottom; | ||
110 | |||
111 | quad.bl.vertices.x = (int) (i * itemWidth_); | ||
112 | quad.bl.vertices.y = 0; | ||
113 | quad.bl.vertices.z = 0.0f; | ||
114 | quad.br.vertices.x = (int)(i * itemWidth_ + itemWidth_); | ||
115 | quad.br.vertices.y = 0; | ||
116 | quad.br.vertices.z = 0.0f; | ||
117 | quad.tl.vertices.x = (int)(i * itemWidth_); | ||
118 | quad.tl.vertices.y = (int)(itemHeight_); | ||
119 | quad.tl.vertices.z = 0.0f; | ||
120 | quad.tr.vertices.x = (int)(i * itemWidth_ + itemWidth_); | ||
121 | quad.tr.vertices.y = (int)(itemHeight_); | ||
122 | quad.tr.vertices.z = 0.0f; | ||
123 | |||
124 | [textureAtlas_ updateQuad:&quad atIndex:i]; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | #pragma mark CCLabelAtlas - CCLabelProtocol | ||
129 | |||
130 | - (void) setString:(NSString*) newString | ||
131 | { | ||
132 | NSUInteger len = [newString length]; | ||
133 | if( len > textureAtlas_.capacity ) | ||
134 | [textureAtlas_ resizeCapacity:len]; | ||
135 | |||
136 | [string_ release]; | ||
137 | string_ = [newString copy]; | ||
138 | [self updateAtlasValues]; | ||
139 | |||
140 | CGSize s; | ||
141 | s.width = len * itemWidth_; | ||
142 | s.height = itemHeight_; | ||
143 | [self setContentSizeInPixels:s]; | ||
144 | |||
145 | self.quadsToDraw = len; | ||
146 | } | ||
147 | |||
148 | -(NSString*) string | ||
149 | { | ||
150 | return string_; | ||
151 | } | ||
152 | |||
153 | #pragma mark CCLabelAtlas - DebugDraw | ||
154 | |||
155 | #if CC_LABELATLAS_DEBUG_DRAW | ||
156 | - (void) draw | ||
157 | { | ||
158 | [super draw]; | ||
159 | |||
160 | CGSize s = [self contentSize]; | ||
161 | CGPoint vertices[4]={ | ||
162 | ccp(0,0),ccp(s.width,0), | ||
163 | ccp(s.width,s.height),ccp(0,s.height), | ||
164 | }; | ||
165 | ccDrawPoly(vertices, 4, YES); | ||
166 | |||
167 | } | ||
168 | #endif // CC_LABELATLAS_DEBUG_DRAW | ||
169 | |||
170 | @end | ||
diff --git a/libs/cocos2d/CCLabelBMFont.h b/libs/cocos2d/CCLabelBMFont.h new file mode 100755 index 0000000..c839ad1 --- /dev/null +++ b/libs/cocos2d/CCLabelBMFont.h | |||
@@ -0,0 +1,190 @@ | |||
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 | * Use any of these editors to generate BMFonts: | ||
30 | * http://glyphdesigner.71squared.com/ (Commercial, Mac OS X) | ||
31 | * http://www.n4te.com/hiero/hiero.jnlp (Free, Java) | ||
32 | * http://slick.cokeandcode.com/demos/hiero.jnlp (Free, Java) | ||
33 | * http://www.angelcode.com/products/bmfont/ (Free, Windows only) | ||
34 | */ | ||
35 | |||
36 | #import "CCSpriteBatchNode.h" | ||
37 | #import "Support/uthash.h" | ||
38 | |||
39 | struct _KerningHashElement; | ||
40 | |||
41 | /** @struct ccBMFontDef | ||
42 | BMFont definition | ||
43 | */ | ||
44 | typedef struct _BMFontDef { | ||
45 | //! ID of the character | ||
46 | unsigned int charID; | ||
47 | //! origin and size of the font | ||
48 | CGRect rect; | ||
49 | //! The X amount the image should be offset when drawing the image (in pixels) | ||
50 | int xOffset; | ||
51 | //! The Y amount the image should be offset when drawing the image (in pixels) | ||
52 | int yOffset; | ||
53 | //! The amount to move the current position after drawing the character (in pixels) | ||
54 | int xAdvance; | ||
55 | } ccBMFontDef; | ||
56 | |||
57 | /** @struct ccBMFontPadding | ||
58 | BMFont padding | ||
59 | @since v0.8.2 | ||
60 | */ | ||
61 | typedef struct _BMFontPadding { | ||
62 | /// padding left | ||
63 | int left; | ||
64 | /// padding top | ||
65 | int top; | ||
66 | /// padding right | ||
67 | int right; | ||
68 | /// padding bottom | ||
69 | int bottom; | ||
70 | } ccBMFontPadding; | ||
71 | |||
72 | enum { | ||
73 | // how many characters are supported | ||
74 | kCCBMFontMaxChars = 2048, //256, | ||
75 | }; | ||
76 | |||
77 | /** CCBMFontConfiguration has parsed configuration of the the .fnt file | ||
78 | @since v0.8 | ||
79 | */ | ||
80 | @interface CCBMFontConfiguration : NSObject | ||
81 | { | ||
82 | // XXX: Creating a public interface so that the bitmapFontArray[] is accesible | ||
83 | @public | ||
84 | // The characters building up the font | ||
85 | ccBMFontDef BMFontArray_[kCCBMFontMaxChars]; | ||
86 | |||
87 | // FNTConfig: Common Height | ||
88 | NSUInteger commonHeight_; | ||
89 | |||
90 | // Padding | ||
91 | ccBMFontPadding padding_; | ||
92 | |||
93 | // atlas name | ||
94 | NSString *atlasName_; | ||
95 | |||
96 | // values for kerning | ||
97 | struct _KerningHashElement *kerningDictionary_; | ||
98 | } | ||
99 | |||
100 | /** allocates a CCBMFontConfiguration with a FNT file */ | ||
101 | +(id) configurationWithFNTFile:(NSString*)FNTfile; | ||
102 | /** initializes a CCBMFontConfiguration with a FNT file */ | ||
103 | -(id) initWithFNTfile:(NSString*)FNTfile; | ||
104 | @end | ||
105 | |||
106 | |||
107 | /** CCLabelBMFont is a subclass of CCSpriteBatchNode | ||
108 | |||
109 | Features: | ||
110 | - Treats each character like a CCSprite. This means that each individual character can be: | ||
111 | - rotated | ||
112 | - scaled | ||
113 | - translated | ||
114 | - tinted | ||
115 | - chage the opacity | ||
116 | - It can be used as part of a menu item. | ||
117 | - anchorPoint can be used to align the "label" | ||
118 | - Supports AngelCode text format | ||
119 | |||
120 | Limitations: | ||
121 | - All inner characters are using an anchorPoint of (0.5f, 0.5f) and it is not recommend to change it | ||
122 | because it might affect the rendering | ||
123 | |||
124 | CCLabelBMFont implements the protocol CCLabelProtocol, like CCLabel and CCLabelAtlas. | ||
125 | CCLabelBMFont has the flexibility of CCLabel, the speed of CCLabelAtlas and all the features of CCSprite. | ||
126 | If in doubt, use CCLabelBMFont instead of CCLabelAtlas / CCLabel. | ||
127 | |||
128 | Supported editors: | ||
129 | - http://www.n4te.com/hiero/hiero.jnlp | ||
130 | - http://slick.cokeandcode.com/demos/hiero.jnlp | ||
131 | - http://www.angelcode.com/products/bmfont/ | ||
132 | |||
133 | @since v0.8 | ||
134 | */ | ||
135 | |||
136 | @interface CCLabelBMFont : CCSpriteBatchNode <CCLabelProtocol, CCRGBAProtocol> | ||
137 | { | ||
138 | // string to render | ||
139 | NSString *string_; | ||
140 | |||
141 | CCBMFontConfiguration *configuration_; | ||
142 | |||
143 | // texture RGBA | ||
144 | GLubyte opacity_; | ||
145 | ccColor3B color_; | ||
146 | BOOL opacityModifyRGB_; | ||
147 | } | ||
148 | |||
149 | /** Purges the cached data. | ||
150 | Removes from memory the cached configurations and the atlas name dictionary. | ||
151 | @since v0.99.3 | ||
152 | */ | ||
153 | +(void) purgeCachedData; | ||
154 | |||
155 | /** conforms to CCRGBAProtocol protocol */ | ||
156 | @property (nonatomic,readwrite) GLubyte opacity; | ||
157 | /** conforms to CCRGBAProtocol protocol */ | ||
158 | @property (nonatomic,readwrite) ccColor3B color; | ||
159 | |||
160 | |||
161 | /** creates a BMFont label with an initial string and the FNT file */ | ||
162 | +(id) labelWithString:(NSString*)string fntFile:(NSString*)fntFile; | ||
163 | |||
164 | /** creates a BMFont label with an initial string and the FNT file | ||
165 | @deprecated Will be removed in 1.0.1. Use "labelWithString" instead. | ||
166 | */ | ||
167 | +(id) bitmapFontAtlasWithString:(NSString*)string fntFile:(NSString*)fntFile DEPRECATED_ATTRIBUTE; | ||
168 | |||
169 | /** init a BMFont label with an initial string and the FNT file */ | ||
170 | -(id) initWithString:(NSString*)string fntFile:(NSString*)fntFile; | ||
171 | |||
172 | /** updates the font chars based on the string to render */ | ||
173 | -(void) createFontChars; | ||
174 | @end | ||
175 | |||
176 | /** Free function that parses a FNT file a place it on the cache | ||
177 | */ | ||
178 | CCBMFontConfiguration * FNTConfigLoadFile( NSString *file ); | ||
179 | /** Purges the FNT config cache | ||
180 | */ | ||
181 | void FNTConfigRemoveCache( void ); | ||
182 | |||
183 | |||
184 | |||
185 | /** CCBitmapFontAtlas | ||
186 | @deprecated Use CCLabelBMFont instead. Will be removed 1.0.1 | ||
187 | */ | ||
188 | DEPRECATED_ATTRIBUTE @interface CCBitmapFontAtlas : CCLabelBMFont | ||
189 | @end | ||
190 | |||
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 | ||
diff --git a/libs/cocos2d/CCLabelTTF.h b/libs/cocos2d/CCLabelTTF.h new file mode 100755 index 0000000..8e48ce1 --- /dev/null +++ b/libs/cocos2d/CCLabelTTF.h | |||
@@ -0,0 +1,78 @@ | |||
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 | #import "CCTexture2D.h" | ||
29 | #import "CCSprite.h" | ||
30 | #import "Platforms/CCNS.h" | ||
31 | |||
32 | |||
33 | /** CCLabel is a subclass of CCTextureNode that knows how to render text labels | ||
34 | * | ||
35 | * All features from CCTextureNode are valid in CCLabel | ||
36 | * | ||
37 | * CCLabel objects are slow. Consider using CCLabelAtlas or CCLabelBMFont instead. | ||
38 | */ | ||
39 | |||
40 | @interface CCLabelTTF : CCSprite <CCLabelProtocol> | ||
41 | { | ||
42 | CGSize dimensions_; | ||
43 | CCTextAlignment alignment_; | ||
44 | NSString * fontName_; | ||
45 | CGFloat fontSize_; | ||
46 | CCLineBreakMode lineBreakMode_; | ||
47 | NSString *string_; | ||
48 | } | ||
49 | |||
50 | /** creates a CCLabel from a fontname, alignment, dimension in points, line break mode, and font size in points. | ||
51 | Supported lineBreakModes: | ||
52 | - iOS: all UILineBreakMode supported modes | ||
53 | - Mac: Only NSLineBreakByWordWrapping is supported. | ||
54 | @since v1.0 | ||
55 | */ | ||
56 | + (id) labelWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment lineBreakMode:(CCLineBreakMode)lineBreakMode fontName:(NSString*)name fontSize:(CGFloat)size; | ||
57 | /** creates a CCLabel from a fontname, alignment, dimension in points and font size in points*/ | ||
58 | + (id) labelWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment fontName:(NSString*)name fontSize:(CGFloat)size; | ||
59 | /** creates a CCLabel from a fontname and font size in points*/ | ||
60 | + (id) labelWithString:(NSString*)string fontName:(NSString*)name fontSize:(CGFloat)size; | ||
61 | /** initializes the CCLabel with a font name, alignment, dimension in points, line brea mode and font size in points. | ||
62 | Supported lineBreakModes: | ||
63 | - iOS: all UILineBreakMode supported modes | ||
64 | - Mac: Only NSLineBreakByWordWrapping is supported. | ||
65 | @since v1.0 | ||
66 | */ | ||
67 | - (id) initWithString:(NSString*)str dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment lineBreakMode:(CCLineBreakMode)lineBreakMode fontName:(NSString*)name fontSize:(CGFloat)size; | ||
68 | /** initializes the CCLabel with a font name, alignment, dimension in points and font size in points */ | ||
69 | - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment fontName:(NSString*)name fontSize:(CGFloat)size; | ||
70 | /** initializes the CCLabel with a font name and font size in points */ | ||
71 | - (id) initWithString:(NSString*)string fontName:(NSString*)name fontSize:(CGFloat)size; | ||
72 | |||
73 | /** changes the string to render | ||
74 | * @warning Changing the string is as expensive as creating a new CCLabel. To obtain better performance use CCLabelAtlas | ||
75 | */ | ||
76 | - (void) setString:(NSString*)str; | ||
77 | |||
78 | @end | ||
diff --git a/libs/cocos2d/CCLabelTTF.m b/libs/cocos2d/CCLabelTTF.m new file mode 100755 index 0000000..24602ec --- /dev/null +++ b/libs/cocos2d/CCLabelTTF.m | |||
@@ -0,0 +1,138 @@ | |||
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 | #import <Availability.h> | ||
29 | |||
30 | #import "CCLabelTTF.h" | ||
31 | #import "Support/CGPointExtension.h" | ||
32 | #import "ccMacros.h" | ||
33 | |||
34 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
35 | #import "Platforms/iOS/CCDirectorIOS.h" | ||
36 | #endif | ||
37 | |||
38 | @implementation CCLabelTTF | ||
39 | |||
40 | - (id) init | ||
41 | { | ||
42 | NSAssert(NO, @"CCLabelTTF: Init not supported. Use initWithString"); | ||
43 | [self release]; | ||
44 | return nil; | ||
45 | } | ||
46 | |||
47 | + (id) labelWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment lineBreakMode:(CCLineBreakMode)lineBreakMode fontName:(NSString*)name fontSize:(CGFloat)size; | ||
48 | { | ||
49 | return [[[self alloc] initWithString: string dimensions:dimensions alignment:alignment lineBreakMode:lineBreakMode fontName:name fontSize:size]autorelease]; | ||
50 | } | ||
51 | |||
52 | + (id) labelWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment fontName:(NSString*)name fontSize:(CGFloat)size | ||
53 | { | ||
54 | return [[[self alloc] initWithString: string dimensions:dimensions alignment:alignment fontName:name fontSize:size]autorelease]; | ||
55 | } | ||
56 | |||
57 | + (id) labelWithString:(NSString*)string fontName:(NSString*)name fontSize:(CGFloat)size | ||
58 | { | ||
59 | return [[[self alloc] initWithString: string fontName:name fontSize:size]autorelease]; | ||
60 | } | ||
61 | |||
62 | |||
63 | - (id) initWithString:(NSString*)str dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment lineBreakMode:(CCLineBreakMode)lineBreakMode fontName:(NSString*)name fontSize:(CGFloat)size | ||
64 | { | ||
65 | if( (self=[super init]) ) { | ||
66 | |||
67 | dimensions_ = CGSizeMake( dimensions.width * CC_CONTENT_SCALE_FACTOR(), dimensions.height * CC_CONTENT_SCALE_FACTOR() ); | ||
68 | alignment_ = alignment; | ||
69 | fontName_ = [name retain]; | ||
70 | fontSize_ = size * CC_CONTENT_SCALE_FACTOR(); | ||
71 | lineBreakMode_ = lineBreakMode; | ||
72 | |||
73 | [self setString:str]; | ||
74 | } | ||
75 | return self; | ||
76 | } | ||
77 | |||
78 | - (id) initWithString:(NSString*)str dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment fontName:(NSString*)name fontSize:(CGFloat)size | ||
79 | { | ||
80 | return [self initWithString:str dimensions:dimensions alignment:alignment lineBreakMode:CCLineBreakModeWordWrap fontName:name fontSize:size]; | ||
81 | } | ||
82 | |||
83 | - (id) initWithString:(NSString*)str fontName:(NSString*)name fontSize:(CGFloat)size | ||
84 | { | ||
85 | if( (self=[super init]) ) { | ||
86 | |||
87 | dimensions_ = CGSizeZero; | ||
88 | fontName_ = [name retain]; | ||
89 | fontSize_ = size * CC_CONTENT_SCALE_FACTOR(); | ||
90 | |||
91 | [self setString:str]; | ||
92 | } | ||
93 | return self; | ||
94 | } | ||
95 | |||
96 | - (void) setString:(NSString*)str | ||
97 | { | ||
98 | [string_ release]; | ||
99 | string_ = [str copy]; | ||
100 | |||
101 | CCTexture2D *tex; | ||
102 | if( CGSizeEqualToSize( dimensions_, CGSizeZero ) ) | ||
103 | tex = [[CCTexture2D alloc] initWithString:str | ||
104 | fontName:fontName_ | ||
105 | fontSize:fontSize_]; | ||
106 | else | ||
107 | tex = [[CCTexture2D alloc] initWithString:str | ||
108 | dimensions:dimensions_ | ||
109 | alignment:alignment_ | ||
110 | lineBreakMode:lineBreakMode_ | ||
111 | fontName:fontName_ | ||
112 | fontSize:fontSize_]; | ||
113 | |||
114 | [self setTexture:tex]; | ||
115 | [tex release]; | ||
116 | |||
117 | CGRect rect = CGRectZero; | ||
118 | rect.size = [texture_ contentSize]; | ||
119 | [self setTextureRect: rect]; | ||
120 | } | ||
121 | |||
122 | -(NSString*) string | ||
123 | { | ||
124 | return string_; | ||
125 | } | ||
126 | |||
127 | - (void) dealloc | ||
128 | { | ||
129 | [string_ release]; | ||
130 | [fontName_ release]; | ||
131 | [super dealloc]; | ||
132 | } | ||
133 | |||
134 | - (NSString*) description | ||
135 | { | ||
136 | return [NSString stringWithFormat:@"<%@ = %08X | Label = %@, FontName = %@, FontSize = %.1f>", [self class], self, string_, fontName_, fontSize_]; | ||
137 | } | ||
138 | @end | ||
diff --git a/libs/cocos2d/CCLayer.h b/libs/cocos2d/CCLayer.h new file mode 100755 index 0000000..f4c9860 --- /dev/null +++ b/libs/cocos2d/CCLayer.h | |||
@@ -0,0 +1,293 @@ | |||
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 | |||
29 | #import <Availability.h> | ||
30 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
31 | #import <UIKit/UIKit.h> // Needed for UIAccelerometerDelegate | ||
32 | #import "Platforms/iOS/CCTouchDelegateProtocol.h" // Touches only supported on iOS | ||
33 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
34 | #import "Platforms/Mac/CCEventDispatcher.h" | ||
35 | #endif | ||
36 | |||
37 | #import "CCProtocols.h" | ||
38 | #import "CCNode.h" | ||
39 | |||
40 | #pragma mark - | ||
41 | #pragma mark CCLayer | ||
42 | |||
43 | /** CCLayer is a subclass of CCNode that implements the TouchEventsDelegate protocol. | ||
44 | |||
45 | All features from CCNode are valid, plus the following new features: | ||
46 | - It can receive iPhone Touches | ||
47 | - It can receive Accelerometer input | ||
48 | */ | ||
49 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
50 | @interface CCLayer : CCNode <UIAccelerometerDelegate, CCStandardTouchDelegate, CCTargetedTouchDelegate> | ||
51 | { | ||
52 | BOOL isTouchEnabled_; | ||
53 | BOOL isAccelerometerEnabled_; | ||
54 | } | ||
55 | /** If isTouchEnabled, this method is called onEnter. Override it to change the | ||
56 | way CCLayer receives touch events. | ||
57 | ( Default: [[TouchDispatcher sharedDispatcher] addStandardDelegate:self priority:0] ) | ||
58 | Example: | ||
59 | -(void) registerWithTouchDispatcher | ||
60 | { | ||
61 | [[TouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN+1 swallowsTouches:YES]; | ||
62 | } | ||
63 | |||
64 | Valid only on iOS. Not valid on Mac. | ||
65 | |||
66 | @since v0.8.0 | ||
67 | */ | ||
68 | -(void) registerWithTouchDispatcher; | ||
69 | |||
70 | /** whether or not it will receive Touch events. | ||
71 | You can enable / disable touch events with this property. | ||
72 | Only the touches of this node will be affected. This "method" is not propagated to it's children. | ||
73 | |||
74 | Valid on iOS and Mac OS X v10.6 and later. | ||
75 | |||
76 | @since v0.8.1 | ||
77 | */ | ||
78 | @property(nonatomic,assign) BOOL isTouchEnabled; | ||
79 | /** whether or not it will receive Accelerometer events | ||
80 | You can enable / disable accelerometer events with this property. | ||
81 | |||
82 | Valid only on iOS. Not valid on Mac. | ||
83 | |||
84 | @since v0.8.1 | ||
85 | */ | ||
86 | @property(nonatomic,assign) BOOL isAccelerometerEnabled; | ||
87 | |||
88 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
89 | |||
90 | |||
91 | @interface CCLayer : CCNode <CCKeyboardEventDelegate, CCMouseEventDelegate, CCTouchEventDelegate> | ||
92 | { | ||
93 | BOOL isMouseEnabled_; | ||
94 | BOOL isKeyboardEnabled_; | ||
95 | BOOL isTouchEnabled_; | ||
96 | } | ||
97 | |||
98 | /** whether or not it will receive mouse events. | ||
99 | |||
100 | Valind only Mac. Not valid on iOS | ||
101 | */ | ||
102 | @property (nonatomic, readwrite) BOOL isMouseEnabled; | ||
103 | |||
104 | /** whether or not it will receive keyboard events. | ||
105 | |||
106 | Valind only Mac. Not valid on iOS | ||
107 | */ | ||
108 | @property (nonatomic, readwrite) BOOL isKeyboardEnabled; | ||
109 | |||
110 | /** whether or not it will receive touch events. | ||
111 | |||
112 | Valid on iOS and Mac OS X v10.6 and later. | ||
113 | */ | ||
114 | @property (nonatomic, readwrite) BOOL isTouchEnabled; | ||
115 | |||
116 | /** priority of the mouse event delegate. | ||
117 | Default 0. | ||
118 | Override this method to set another priority. | ||
119 | |||
120 | Valind only Mac. Not valid on iOS | ||
121 | */ | ||
122 | -(NSInteger) mouseDelegatePriority; | ||
123 | |||
124 | /** priority of the keyboard event delegate. | ||
125 | Default 0. | ||
126 | Override this method to set another priority. | ||
127 | |||
128 | Valind only Mac. Not valid on iOS | ||
129 | */ | ||
130 | -(NSInteger) keyboardDelegatePriority; | ||
131 | |||
132 | /** priority of the touch event delegate. | ||
133 | Default 0. | ||
134 | Override this method to set another priority. | ||
135 | |||
136 | Valind only Mac. Not valid on iOS | ||
137 | */ | ||
138 | -(NSInteger) touchDelegatePriority; | ||
139 | |||
140 | #endif // mac | ||
141 | |||
142 | |||
143 | @end | ||
144 | |||
145 | #pragma mark - | ||
146 | #pragma mark CCLayerColor | ||
147 | |||
148 | /** CCLayerColor is a subclass of CCLayer that implements the CCRGBAProtocol protocol. | ||
149 | |||
150 | All features from CCLayer are valid, plus the following new features: | ||
151 | - opacity | ||
152 | - RGB colors | ||
153 | */ | ||
154 | @interface CCLayerColor : CCLayer <CCRGBAProtocol, CCBlendProtocol> | ||
155 | { | ||
156 | GLubyte opacity_; | ||
157 | ccColor3B color_; | ||
158 | ccVertex2F squareVertices_[4]; | ||
159 | ccColor4B squareColors_[4]; | ||
160 | |||
161 | ccBlendFunc blendFunc_; | ||
162 | } | ||
163 | |||
164 | /** creates a CCLayer with color, width and height in Points*/ | ||
165 | + (id) layerWithColor: (ccColor4B)color width:(GLfloat)w height:(GLfloat)h; | ||
166 | /** creates a CCLayer with color. Width and height are the window size. */ | ||
167 | + (id) layerWithColor: (ccColor4B)color; | ||
168 | |||
169 | /** initializes a CCLayer with color, width and height in Points */ | ||
170 | - (id) initWithColor:(ccColor4B)color width:(GLfloat)w height:(GLfloat)h; | ||
171 | /** initializes a CCLayer with color. Width and height are the window size. */ | ||
172 | - (id) initWithColor:(ccColor4B)color; | ||
173 | |||
174 | /** change width in Points */ | ||
175 | -(void) changeWidth: (GLfloat)w; | ||
176 | /** change height in Points */ | ||
177 | -(void) changeHeight: (GLfloat)h; | ||
178 | /** change width and height in Points | ||
179 | @since v0.8 | ||
180 | */ | ||
181 | -(void) changeWidth:(GLfloat)w height:(GLfloat)h; | ||
182 | |||
183 | /** Opacity: conforms to CCRGBAProtocol protocol */ | ||
184 | @property (nonatomic,readonly) GLubyte opacity; | ||
185 | /** Opacity: conforms to CCRGBAProtocol protocol */ | ||
186 | @property (nonatomic,readonly) ccColor3B color; | ||
187 | /** BlendFunction. Conforms to CCBlendProtocol protocol */ | ||
188 | @property (nonatomic,readwrite) ccBlendFunc blendFunc; | ||
189 | @end | ||
190 | |||
191 | /** CCColorLayer | ||
192 | It is the same as CCLayerColor. | ||
193 | |||
194 | @deprecated Use CCLayerColor instead. This class will be removed in v1.0.1 | ||
195 | */ | ||
196 | DEPRECATED_ATTRIBUTE @interface CCColorLayer : CCLayerColor | ||
197 | @end | ||
198 | |||
199 | #pragma mark - | ||
200 | #pragma mark CCLayerGradient | ||
201 | |||
202 | /** CCLayerGradient is a subclass of CCLayerColor that draws gradients across | ||
203 | the background. | ||
204 | |||
205 | All features from CCLayerColor are valid, plus the following new features: | ||
206 | - direction | ||
207 | - final color | ||
208 | - interpolation mode | ||
209 | |||
210 | Color is interpolated between the startColor and endColor along the given | ||
211 | vector (starting at the origin, ending at the terminus). If no vector is | ||
212 | supplied, it defaults to (0, -1) -- a fade from top to bottom. | ||
213 | |||
214 | If 'compressedInterpolation' is disabled, you will not see either the start or end color for | ||
215 | non-cardinal vectors; a smooth gradient implying both end points will be still | ||
216 | be drawn, however. | ||
217 | |||
218 | If ' compressedInterpolation' is enabled (default mode) you will see both the start and end colors of the gradient. | ||
219 | |||
220 | @since v0.99.5 | ||
221 | */ | ||
222 | @interface CCLayerGradient : CCLayerColor | ||
223 | { | ||
224 | ccColor3B endColor_; | ||
225 | GLubyte startOpacity_; | ||
226 | GLubyte endOpacity_; | ||
227 | CGPoint vector_; | ||
228 | BOOL compressedInterpolation_; | ||
229 | } | ||
230 | |||
231 | /** Creates a full-screen CCLayer with a gradient between start and end. */ | ||
232 | + (id) layerWithColor: (ccColor4B) start fadingTo: (ccColor4B) end; | ||
233 | /** Creates a full-screen CCLayer with a gradient between start and end in the direction of v. */ | ||
234 | + (id) layerWithColor: (ccColor4B) start fadingTo: (ccColor4B) end alongVector: (CGPoint) v; | ||
235 | |||
236 | /** Initializes the CCLayer with a gradient between start and end. */ | ||
237 | - (id) initWithColor: (ccColor4B) start fadingTo: (ccColor4B) end; | ||
238 | /** Initializes the CCLayer with a gradient between start and end in the direction of v. */ | ||
239 | - (id) initWithColor: (ccColor4B) start fadingTo: (ccColor4B) end alongVector: (CGPoint) v; | ||
240 | |||
241 | /** The starting color. */ | ||
242 | @property (nonatomic, readwrite) ccColor3B startColor; | ||
243 | /** The ending color. */ | ||
244 | @property (nonatomic, readwrite) ccColor3B endColor; | ||
245 | /** The starting opacity. */ | ||
246 | @property (nonatomic, readwrite) GLubyte startOpacity; | ||
247 | /** The ending color. */ | ||
248 | @property (nonatomic, readwrite) GLubyte endOpacity; | ||
249 | /** The vector along which to fade color. */ | ||
250 | @property (nonatomic, readwrite) CGPoint vector; | ||
251 | /** Whether or not the interpolation will be compressed in order to display all the colors of the gradient both in canonical and non canonical vectors | ||
252 | Default: YES | ||
253 | */ | ||
254 | @property (nonatomic, readwrite) BOOL compressedInterpolation; | ||
255 | |||
256 | @end | ||
257 | |||
258 | #pragma mark - | ||
259 | #pragma mark CCLayerMultiplex | ||
260 | |||
261 | /** CCLayerMultiplex is a CCLayer with the ability to multiplex it's children. | ||
262 | Features: | ||
263 | - It supports one or more children | ||
264 | - Only one children will be active a time | ||
265 | */ | ||
266 | @interface CCLayerMultiplex : CCLayer | ||
267 | { | ||
268 | unsigned int enabledLayer_; | ||
269 | NSMutableArray *layers_; | ||
270 | } | ||
271 | |||
272 | /** creates a CCMultiplexLayer with one or more layers using a variable argument list. */ | ||
273 | +(id) layerWithLayers: (CCLayer*) layer, ... NS_REQUIRES_NIL_TERMINATION; | ||
274 | /** initializes a MultiplexLayer with one or more layers using a variable argument list. */ | ||
275 | -(id) initWithLayers: (CCLayer*) layer vaList:(va_list) params; | ||
276 | /** switches to a certain layer indexed by n. | ||
277 | The current (old) layer will be removed from it's parent with 'cleanup:YES'. | ||
278 | */ | ||
279 | -(void) switchTo: (unsigned int) n; | ||
280 | /** release the current layer and switches to another layer indexed by n. | ||
281 | The current (old) layer will be removed from it's parent with 'cleanup:YES'. | ||
282 | */ | ||
283 | -(void) switchToAndReleaseMe: (unsigned int) n; | ||
284 | @end | ||
285 | |||
286 | /** CCMultiplexLayer | ||
287 | It is the same as CCLayerMultiplex. | ||
288 | |||
289 | @deprecated Use CCLayerMultiplex instead. This class will be removed in v1.0.1 | ||
290 | */ | ||
291 | DEPRECATED_ATTRIBUTE @interface CCMultiplexLayer : CCLayerMultiplex | ||
292 | @end | ||
293 | |||
diff --git a/libs/cocos2d/CCLayer.m b/libs/cocos2d/CCLayer.m new file mode 100755 index 0000000..fe5a72d --- /dev/null +++ b/libs/cocos2d/CCLayer.m | |||
@@ -0,0 +1,621 @@ | |||
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 | #import <stdarg.h> | ||
29 | |||
30 | #import "Platforms/CCGL.h" | ||
31 | |||
32 | #import "CCLayer.h" | ||
33 | #import "CCDirector.h" | ||
34 | #import "ccMacros.h" | ||
35 | #import "Support/CGPointExtension.h" | ||
36 | |||
37 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
38 | #import "Platforms/iOS/CCTouchDispatcher.h" | ||
39 | #import "Platforms/iOS/CCDirectorIOS.h" | ||
40 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
41 | #import "Platforms/Mac/CCEventDispatcher.h" | ||
42 | #endif | ||
43 | |||
44 | #pragma mark - | ||
45 | #pragma mark Layer | ||
46 | |||
47 | @implementation CCLayer | ||
48 | |||
49 | #pragma mark Layer - Init | ||
50 | -(id) init | ||
51 | { | ||
52 | if( (self=[super init]) ) { | ||
53 | |||
54 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
55 | anchorPoint_ = ccp(0.5f, 0.5f); | ||
56 | [self setContentSize:s]; | ||
57 | self.isRelativeAnchorPoint = NO; | ||
58 | |||
59 | isTouchEnabled_ = NO; | ||
60 | |||
61 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
62 | isAccelerometerEnabled_ = NO; | ||
63 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
64 | isMouseEnabled_ = NO; | ||
65 | isKeyboardEnabled_ = NO; | ||
66 | #endif | ||
67 | } | ||
68 | |||
69 | return self; | ||
70 | } | ||
71 | |||
72 | #pragma mark Layer - Touch and Accelerometer related | ||
73 | |||
74 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
75 | -(void) registerWithTouchDispatcher | ||
76 | { | ||
77 | [[CCTouchDispatcher sharedDispatcher] addStandardDelegate:self priority:0]; | ||
78 | } | ||
79 | |||
80 | -(BOOL) isAccelerometerEnabled | ||
81 | { | ||
82 | return isAccelerometerEnabled_; | ||
83 | } | ||
84 | |||
85 | -(void) setIsAccelerometerEnabled:(BOOL)enabled | ||
86 | { | ||
87 | if( enabled != isAccelerometerEnabled_ ) { | ||
88 | isAccelerometerEnabled_ = enabled; | ||
89 | if( isRunning_ ) { | ||
90 | if( enabled ) | ||
91 | [[UIAccelerometer sharedAccelerometer] setDelegate:self]; | ||
92 | else | ||
93 | [[UIAccelerometer sharedAccelerometer] setDelegate:nil]; | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | |||
98 | -(BOOL) isTouchEnabled | ||
99 | { | ||
100 | return isTouchEnabled_; | ||
101 | } | ||
102 | |||
103 | -(void) setIsTouchEnabled:(BOOL)enabled | ||
104 | { | ||
105 | if( isTouchEnabled_ != enabled ) { | ||
106 | isTouchEnabled_ = enabled; | ||
107 | if( isRunning_ ) { | ||
108 | if( enabled ) | ||
109 | [self registerWithTouchDispatcher]; | ||
110 | else | ||
111 | [[CCTouchDispatcher sharedDispatcher] removeDelegate:self]; | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
117 | |||
118 | #pragma mark CCLayer - Mouse, Keyboard & Touch events | ||
119 | |||
120 | -(NSInteger) mouseDelegatePriority | ||
121 | { | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | -(BOOL) isMouseEnabled | ||
126 | { | ||
127 | return isMouseEnabled_; | ||
128 | } | ||
129 | |||
130 | -(void) setIsMouseEnabled:(BOOL)enabled | ||
131 | { | ||
132 | if( isMouseEnabled_ != enabled ) { | ||
133 | isMouseEnabled_ = enabled; | ||
134 | |||
135 | if( isRunning_ ) { | ||
136 | if( enabled ) | ||
137 | [[CCEventDispatcher sharedDispatcher] addMouseDelegate:self priority:[self mouseDelegatePriority]]; | ||
138 | else | ||
139 | [[CCEventDispatcher sharedDispatcher] removeMouseDelegate:self]; | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | -(NSInteger) keyboardDelegatePriority | ||
145 | { | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | -(BOOL) isKeyboardEnabled | ||
150 | { | ||
151 | return isKeyboardEnabled_; | ||
152 | } | ||
153 | |||
154 | -(void) setIsKeyboardEnabled:(BOOL)enabled | ||
155 | { | ||
156 | if( isKeyboardEnabled_ != enabled ) { | ||
157 | isKeyboardEnabled_ = enabled; | ||
158 | |||
159 | if( isRunning_ ) { | ||
160 | if( enabled ) | ||
161 | [[CCEventDispatcher sharedDispatcher] addKeyboardDelegate:self priority:[self keyboardDelegatePriority] ]; | ||
162 | else | ||
163 | [[CCEventDispatcher sharedDispatcher] removeKeyboardDelegate:self]; | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | -(NSInteger) touchDelegatePriority | ||
169 | { | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | -(BOOL) isTouchEnabled | ||
174 | { | ||
175 | return isTouchEnabled_; | ||
176 | } | ||
177 | |||
178 | -(void) setIsTouchEnabled:(BOOL)enabled | ||
179 | { | ||
180 | if( isTouchEnabled_ != enabled ) { | ||
181 | isTouchEnabled_ = enabled; | ||
182 | if( isRunning_ ) { | ||
183 | if( enabled ) | ||
184 | [[CCEventDispatcher sharedDispatcher] addTouchDelegate:self priority:[self touchDelegatePriority]]; | ||
185 | else | ||
186 | [[CCEventDispatcher sharedDispatcher] removeTouchDelegate:self]; | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | |||
191 | |||
192 | #endif // Mac | ||
193 | |||
194 | |||
195 | #pragma mark Layer - Callbacks | ||
196 | -(void) onEnter | ||
197 | { | ||
198 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
199 | // register 'parent' nodes first | ||
200 | // since events are propagated in reverse order | ||
201 | if (isTouchEnabled_) | ||
202 | [self registerWithTouchDispatcher]; | ||
203 | |||
204 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
205 | if( isMouseEnabled_ ) | ||
206 | [[CCEventDispatcher sharedDispatcher] addMouseDelegate:self priority:[self mouseDelegatePriority]]; | ||
207 | |||
208 | if( isKeyboardEnabled_) | ||
209 | [[CCEventDispatcher sharedDispatcher] addKeyboardDelegate:self priority:[self keyboardDelegatePriority]]; | ||
210 | |||
211 | if( isTouchEnabled_) | ||
212 | [[CCEventDispatcher sharedDispatcher] addTouchDelegate:self priority:[self touchDelegatePriority]]; | ||
213 | |||
214 | #endif | ||
215 | |||
216 | // then iterate over all the children | ||
217 | [super onEnter]; | ||
218 | } | ||
219 | |||
220 | // issue #624. | ||
221 | // Can't register mouse, touches here because of #issue #1018, and #1021 | ||
222 | -(void) onEnterTransitionDidFinish | ||
223 | { | ||
224 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
225 | if( isAccelerometerEnabled_ ) | ||
226 | [[UIAccelerometer sharedAccelerometer] setDelegate:self]; | ||
227 | #endif | ||
228 | |||
229 | [super onEnterTransitionDidFinish]; | ||
230 | } | ||
231 | |||
232 | |||
233 | -(void) onExit | ||
234 | { | ||
235 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
236 | if( isTouchEnabled_ ) | ||
237 | [[CCTouchDispatcher sharedDispatcher] removeDelegate:self]; | ||
238 | |||
239 | if( isAccelerometerEnabled_ ) | ||
240 | [[UIAccelerometer sharedAccelerometer] setDelegate:nil]; | ||
241 | |||
242 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
243 | if( isMouseEnabled_ ) | ||
244 | [[CCEventDispatcher sharedDispatcher] removeMouseDelegate:self]; | ||
245 | |||
246 | if( isKeyboardEnabled_ ) | ||
247 | [[CCEventDispatcher sharedDispatcher] removeKeyboardDelegate:self]; | ||
248 | |||
249 | if( isTouchEnabled_ ) | ||
250 | [[CCEventDispatcher sharedDispatcher] removeTouchDelegate:self]; | ||
251 | |||
252 | #endif | ||
253 | |||
254 | [super onExit]; | ||
255 | } | ||
256 | |||
257 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
258 | -(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event | ||
259 | { | ||
260 | NSAssert(NO, @"Layer#ccTouchBegan override me"); | ||
261 | return YES; | ||
262 | } | ||
263 | #endif | ||
264 | @end | ||
265 | |||
266 | #pragma mark - | ||
267 | #pragma mark LayerColor | ||
268 | |||
269 | @interface CCLayerColor (Private) | ||
270 | -(void) updateColor; | ||
271 | @end | ||
272 | |||
273 | @implementation CCLayerColor | ||
274 | |||
275 | // Opacity and RGB color protocol | ||
276 | @synthesize opacity = opacity_, color = color_; | ||
277 | @synthesize blendFunc = blendFunc_; | ||
278 | |||
279 | |||
280 | + (id) layerWithColor:(ccColor4B)color width:(GLfloat)w height:(GLfloat) h | ||
281 | { | ||
282 | return [[[self alloc] initWithColor:color width:w height:h] autorelease]; | ||
283 | } | ||
284 | |||
285 | + (id) layerWithColor:(ccColor4B)color | ||
286 | { | ||
287 | return [[(CCLayerColor*)[self alloc] initWithColor:color] autorelease]; | ||
288 | } | ||
289 | |||
290 | - (id) initWithColor:(ccColor4B)color width:(GLfloat)w height:(GLfloat) h | ||
291 | { | ||
292 | if( (self=[super init]) ) { | ||
293 | |||
294 | // default blend function | ||
295 | blendFunc_ = (ccBlendFunc) { CC_BLEND_SRC, CC_BLEND_DST }; | ||
296 | |||
297 | color_.r = color.r; | ||
298 | color_.g = color.g; | ||
299 | color_.b = color.b; | ||
300 | opacity_ = color.a; | ||
301 | |||
302 | for (NSUInteger i = 0; i<sizeof(squareVertices_) / sizeof( squareVertices_[0]); i++ ) { | ||
303 | squareVertices_[i].x = 0.0f; | ||
304 | squareVertices_[i].y = 0.0f; | ||
305 | } | ||
306 | |||
307 | [self updateColor]; | ||
308 | [self setContentSize:CGSizeMake(w, h) ]; | ||
309 | } | ||
310 | return self; | ||
311 | } | ||
312 | |||
313 | - (id) initWithColor:(ccColor4B)color | ||
314 | { | ||
315 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
316 | return [self initWithColor:color width:s.width height:s.height]; | ||
317 | } | ||
318 | |||
319 | // override contentSize | ||
320 | -(void) setContentSize: (CGSize) size | ||
321 | { | ||
322 | squareVertices_[1].x = size.width * CC_CONTENT_SCALE_FACTOR(); | ||
323 | squareVertices_[2].y = size.height * CC_CONTENT_SCALE_FACTOR(); | ||
324 | squareVertices_[3].x = size.width * CC_CONTENT_SCALE_FACTOR(); | ||
325 | squareVertices_[3].y = size.height * CC_CONTENT_SCALE_FACTOR(); | ||
326 | |||
327 | [super setContentSize:size]; | ||
328 | } | ||
329 | |||
330 | - (void) changeWidth: (GLfloat) w height:(GLfloat) h | ||
331 | { | ||
332 | [self setContentSize:CGSizeMake(w, h)]; | ||
333 | } | ||
334 | |||
335 | -(void) changeWidth: (GLfloat) w | ||
336 | { | ||
337 | [self setContentSize:CGSizeMake(w, contentSize_.height)]; | ||
338 | } | ||
339 | |||
340 | -(void) changeHeight: (GLfloat) h | ||
341 | { | ||
342 | [self setContentSize:CGSizeMake(contentSize_.width, h)]; | ||
343 | } | ||
344 | |||
345 | - (void) updateColor | ||
346 | { | ||
347 | for( NSUInteger i = 0; i < 4; i++ ) | ||
348 | { | ||
349 | squareColors_[i].r = color_.r; | ||
350 | squareColors_[i].g = color_.g; | ||
351 | squareColors_[i].b = color_.b; | ||
352 | squareColors_[i].a = opacity_; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | - (void)draw | ||
357 | { | ||
358 | [super draw]; | ||
359 | |||
360 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
361 | // Needed states: GL_VERTEX_ARRAY, GL_COLOR_ARRAY | ||
362 | // Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY | ||
363 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
364 | glDisable(GL_TEXTURE_2D); | ||
365 | |||
366 | glVertexPointer(2, GL_FLOAT, 0, squareVertices_); | ||
367 | glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors_); | ||
368 | |||
369 | |||
370 | BOOL newBlend = blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST; | ||
371 | if( newBlend ) | ||
372 | glBlendFunc( blendFunc_.src, blendFunc_.dst ); | ||
373 | |||
374 | else if( opacity_ != 255 ) { | ||
375 | newBlend = YES; | ||
376 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
377 | } | ||
378 | |||
379 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
380 | |||
381 | if( newBlend ) | ||
382 | glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); | ||
383 | |||
384 | // restore default GL state | ||
385 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
386 | glEnable(GL_TEXTURE_2D); | ||
387 | } | ||
388 | |||
389 | #pragma mark Protocols | ||
390 | // Color Protocol | ||
391 | |||
392 | -(void) setColor:(ccColor3B)color | ||
393 | { | ||
394 | color_ = color; | ||
395 | [self updateColor]; | ||
396 | } | ||
397 | |||
398 | -(void) setOpacity: (GLubyte) o | ||
399 | { | ||
400 | opacity_ = o; | ||
401 | [self updateColor]; | ||
402 | } | ||
403 | @end | ||
404 | |||
405 | // XXX Deprecated | ||
406 | @implementation CCColorLayer | ||
407 | @end | ||
408 | |||
409 | |||
410 | #pragma mark - | ||
411 | #pragma mark LayerGradient | ||
412 | |||
413 | @implementation CCLayerGradient | ||
414 | |||
415 | @synthesize startOpacity = startOpacity_; | ||
416 | @synthesize endColor = endColor_, endOpacity = endOpacity_; | ||
417 | @synthesize vector = vector_; | ||
418 | |||
419 | + (id) layerWithColor: (ccColor4B) start fadingTo: (ccColor4B) end | ||
420 | { | ||
421 | return [[[self alloc] initWithColor:start fadingTo:end] autorelease]; | ||
422 | } | ||
423 | |||
424 | + (id) layerWithColor: (ccColor4B) start fadingTo: (ccColor4B) end alongVector: (CGPoint) v | ||
425 | { | ||
426 | return [[[self alloc] initWithColor:start fadingTo:end alongVector:v] autorelease]; | ||
427 | } | ||
428 | |||
429 | - (id) initWithColor: (ccColor4B) start fadingTo: (ccColor4B) end | ||
430 | { | ||
431 | return [self initWithColor:start fadingTo:end alongVector:ccp(0, -1)]; | ||
432 | } | ||
433 | |||
434 | - (id) initWithColor: (ccColor4B) start fadingTo: (ccColor4B) end alongVector: (CGPoint) v | ||
435 | { | ||
436 | endColor_.r = end.r; | ||
437 | endColor_.g = end.g; | ||
438 | endColor_.b = end.b; | ||
439 | |||
440 | endOpacity_ = end.a; | ||
441 | startOpacity_ = start.a; | ||
442 | vector_ = v; | ||
443 | |||
444 | start.a = 255; | ||
445 | compressedInterpolation_ = YES; | ||
446 | |||
447 | return [super initWithColor:start]; | ||
448 | } | ||
449 | |||
450 | - (void) updateColor | ||
451 | { | ||
452 | [super updateColor]; | ||
453 | |||
454 | float h = ccpLength(vector_); | ||
455 | if (h == 0) | ||
456 | return; | ||
457 | |||
458 | double c = sqrt(2); | ||
459 | CGPoint u = ccp(vector_.x / h, vector_.y / h); | ||
460 | |||
461 | // Compressed Interpolation mode | ||
462 | if( compressedInterpolation_ ) { | ||
463 | float h2 = 1 / ( fabsf(u.x) + fabsf(u.y) ); | ||
464 | u = ccpMult(u, h2 * (float)c); | ||
465 | } | ||
466 | |||
467 | float opacityf = (float)opacity_/255.0f; | ||
468 | |||
469 | ccColor4B S = { | ||
470 | color_.r, | ||
471 | color_.g, | ||
472 | color_.b, | ||
473 | startOpacity_*opacityf | ||
474 | }; | ||
475 | |||
476 | ccColor4B E = { | ||
477 | endColor_.r, | ||
478 | endColor_.g, | ||
479 | endColor_.b, | ||
480 | endOpacity_*opacityf | ||
481 | }; | ||
482 | |||
483 | |||
484 | // (-1, -1) | ||
485 | squareColors_[0].r = E.r + (S.r - E.r) * ((c + u.x + u.y) / (2.0f * c)); | ||
486 | squareColors_[0].g = E.g + (S.g - E.g) * ((c + u.x + u.y) / (2.0f * c)); | ||
487 | squareColors_[0].b = E.b + (S.b - E.b) * ((c + u.x + u.y) / (2.0f * c)); | ||
488 | squareColors_[0].a = E.a + (S.a - E.a) * ((c + u.x + u.y) / (2.0f * c)); | ||
489 | // (1, -1) | ||
490 | squareColors_[1].r = E.r + (S.r - E.r) * ((c - u.x + u.y) / (2.0f * c)); | ||
491 | squareColors_[1].g = E.g + (S.g - E.g) * ((c - u.x + u.y) / (2.0f * c)); | ||
492 | squareColors_[1].b = E.b + (S.b - E.b) * ((c - u.x + u.y) / (2.0f * c)); | ||
493 | squareColors_[1].a = E.a + (S.a - E.a) * ((c - u.x + u.y) / (2.0f * c)); | ||
494 | // (-1, 1) | ||
495 | squareColors_[2].r = E.r + (S.r - E.r) * ((c + u.x - u.y) / (2.0f * c)); | ||
496 | squareColors_[2].g = E.g + (S.g - E.g) * ((c + u.x - u.y) / (2.0f * c)); | ||
497 | squareColors_[2].b = E.b + (S.b - E.b) * ((c + u.x - u.y) / (2.0f * c)); | ||
498 | squareColors_[2].a = E.a + (S.a - E.a) * ((c + u.x - u.y) / (2.0f * c)); | ||
499 | // (1, 1) | ||
500 | squareColors_[3].r = E.r + (S.r - E.r) * ((c - u.x - u.y) / (2.0f * c)); | ||
501 | squareColors_[3].g = E.g + (S.g - E.g) * ((c - u.x - u.y) / (2.0f * c)); | ||
502 | squareColors_[3].b = E.b + (S.b - E.b) * ((c - u.x - u.y) / (2.0f * c)); | ||
503 | squareColors_[3].a = E.a + (S.a - E.a) * ((c - u.x - u.y) / (2.0f * c)); | ||
504 | } | ||
505 | |||
506 | -(ccColor3B) startColor | ||
507 | { | ||
508 | return color_; | ||
509 | } | ||
510 | |||
511 | -(void) setStartColor:(ccColor3B)colors | ||
512 | { | ||
513 | [self setColor:colors]; | ||
514 | } | ||
515 | |||
516 | -(void) setEndColor:(ccColor3B)colors | ||
517 | { | ||
518 | endColor_ = colors; | ||
519 | [self updateColor]; | ||
520 | } | ||
521 | |||
522 | -(void) setStartOpacity: (GLubyte) o | ||
523 | { | ||
524 | startOpacity_ = o; | ||
525 | [self updateColor]; | ||
526 | } | ||
527 | |||
528 | -(void) setEndOpacity: (GLubyte) o | ||
529 | { | ||
530 | endOpacity_ = o; | ||
531 | [self updateColor]; | ||
532 | } | ||
533 | |||
534 | -(void) setVector: (CGPoint) v | ||
535 | { | ||
536 | vector_ = v; | ||
537 | [self updateColor]; | ||
538 | } | ||
539 | |||
540 | -(BOOL) compressedInterpolation | ||
541 | { | ||
542 | return compressedInterpolation_; | ||
543 | } | ||
544 | |||
545 | -(void) setCompressedInterpolation:(BOOL)compress | ||
546 | { | ||
547 | compressedInterpolation_ = compress; | ||
548 | [self updateColor]; | ||
549 | } | ||
550 | @end | ||
551 | |||
552 | #pragma mark - | ||
553 | #pragma mark MultiplexLayer | ||
554 | |||
555 | @implementation CCLayerMultiplex | ||
556 | +(id) layerWithLayers: (CCLayer*) layer, ... | ||
557 | { | ||
558 | va_list args; | ||
559 | va_start(args,layer); | ||
560 | |||
561 | id s = [[[self alloc] initWithLayers: layer vaList:args] autorelease]; | ||
562 | |||
563 | va_end(args); | ||
564 | return s; | ||
565 | } | ||
566 | |||
567 | -(id) initWithLayers: (CCLayer*) layer vaList:(va_list) params | ||
568 | { | ||
569 | if( (self=[super init]) ) { | ||
570 | |||
571 | layers_ = [[NSMutableArray arrayWithCapacity:5] retain]; | ||
572 | |||
573 | [layers_ addObject: layer]; | ||
574 | |||
575 | CCLayer *l = va_arg(params,CCLayer*); | ||
576 | while( l ) { | ||
577 | [layers_ addObject: l]; | ||
578 | l = va_arg(params,CCLayer*); | ||
579 | } | ||
580 | |||
581 | enabledLayer_ = 0; | ||
582 | [self addChild: [layers_ objectAtIndex: enabledLayer_]]; | ||
583 | } | ||
584 | |||
585 | return self; | ||
586 | } | ||
587 | |||
588 | -(void) dealloc | ||
589 | { | ||
590 | [layers_ release]; | ||
591 | [super dealloc]; | ||
592 | } | ||
593 | |||
594 | -(void) switchTo: (unsigned int) n | ||
595 | { | ||
596 | NSAssert( n < [layers_ count], @"Invalid index in MultiplexLayer switchTo message" ); | ||
597 | |||
598 | [self removeChild: [layers_ objectAtIndex:enabledLayer_] cleanup:YES]; | ||
599 | |||
600 | enabledLayer_ = n; | ||
601 | |||
602 | [self addChild: [layers_ objectAtIndex:n]]; | ||
603 | } | ||
604 | |||
605 | -(void) switchToAndReleaseMe: (unsigned int) n | ||
606 | { | ||
607 | NSAssert( n < [layers_ count], @"Invalid index in MultiplexLayer switchTo message" ); | ||
608 | |||
609 | [self removeChild: [layers_ objectAtIndex:enabledLayer_] cleanup:YES]; | ||
610 | |||
611 | [layers_ replaceObjectAtIndex:enabledLayer_ withObject:[NSNull null]]; | ||
612 | |||
613 | enabledLayer_ = n; | ||
614 | |||
615 | [self addChild: [layers_ objectAtIndex:n]]; | ||
616 | } | ||
617 | @end | ||
618 | |||
619 | // XXX Deprecated | ||
620 | @implementation CCMultiplexLayer | ||
621 | @end | ||
diff --git a/libs/cocos2d/CCMenu.h b/libs/cocos2d/CCMenu.h new file mode 100755 index 0000000..ef22343 --- /dev/null +++ b/libs/cocos2d/CCMenu.h | |||
@@ -0,0 +1,93 @@ | |||
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 | #import "CCMenuItem.h" | ||
29 | #import "CCLayer.h" | ||
30 | |||
31 | typedef enum { | ||
32 | kCCMenuStateWaiting, | ||
33 | kCCMenuStateTrackingTouch | ||
34 | } tCCMenuState; | ||
35 | |||
36 | enum { | ||
37 | //* priority used by the menu for the touches | ||
38 | kCCMenuTouchPriority = -128, | ||
39 | |||
40 | //* priority used by the menu for the mouse | ||
41 | kCCMenuMousePriority = -128, | ||
42 | }; | ||
43 | |||
44 | /** A CCMenu | ||
45 | * | ||
46 | * Features and Limitation: | ||
47 | * - You can add MenuItem objects in runtime using addChild: | ||
48 | * - But the only accecpted children are MenuItem objects | ||
49 | */ | ||
50 | @interface CCMenu : CCLayer <CCRGBAProtocol> | ||
51 | { | ||
52 | tCCMenuState state_; | ||
53 | CCMenuItem *selectedItem_; | ||
54 | GLubyte opacity_; | ||
55 | ccColor3B color_; | ||
56 | } | ||
57 | |||
58 | /** creates a CCMenu with it's items */ | ||
59 | + (id) menuWithItems: (CCMenuItem*) item, ... NS_REQUIRES_NIL_TERMINATION; | ||
60 | |||
61 | /** initializes a CCMenu with it's items */ | ||
62 | - (id) initWithItems: (CCMenuItem*) item vaList: (va_list) args; | ||
63 | |||
64 | /** align items vertically */ | ||
65 | -(void) alignItemsVertically; | ||
66 | /** align items vertically with padding | ||
67 | @since v0.7.2 | ||
68 | */ | ||
69 | -(void) alignItemsVerticallyWithPadding:(float) padding; | ||
70 | |||
71 | /** align items horizontally */ | ||
72 | -(void) alignItemsHorizontally; | ||
73 | /** align items horizontally with padding | ||
74 | @since v0.7.2 | ||
75 | */ | ||
76 | -(void) alignItemsHorizontallyWithPadding: (float) padding; | ||
77 | |||
78 | |||
79 | /** align items in rows of columns */ | ||
80 | -(void) alignItemsInColumns: (NSNumber *) columns, ... NS_REQUIRES_NIL_TERMINATION; | ||
81 | -(void) alignItemsInColumns: (NSNumber *) columns vaList: (va_list) args; | ||
82 | |||
83 | /** align items in columns of rows */ | ||
84 | -(void) alignItemsInRows: (NSNumber *) rows, ... NS_REQUIRES_NIL_TERMINATION; | ||
85 | -(void) alignItemsInRows: (NSNumber *) rows vaList: (va_list) args; | ||
86 | |||
87 | |||
88 | /** conforms to CCRGBAProtocol protocol */ | ||
89 | @property (nonatomic,readonly) GLubyte opacity; | ||
90 | /** conforms to CCRGBAProtocol protocol */ | ||
91 | @property (nonatomic,readonly) ccColor3B color; | ||
92 | |||
93 | @end | ||
diff --git a/libs/cocos2d/CCMenu.m b/libs/cocos2d/CCMenu.m new file mode 100755 index 0000000..c3cb8f2 --- /dev/null +++ b/libs/cocos2d/CCMenu.m | |||
@@ -0,0 +1,523 @@ | |||
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 | |||
29 | #import "CCMenu.h" | ||
30 | #import "CCDirector.h" | ||
31 | #import "Support/CGPointExtension.h" | ||
32 | #import "ccMacros.h" | ||
33 | |||
34 | #import <Availability.h> | ||
35 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
36 | #import "Platforms/iOS/CCDirectorIOS.h" | ||
37 | #import "Platforms/iOS/CCTouchDispatcher.h" | ||
38 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
39 | #import "Platforms/Mac/MacGLView.h" | ||
40 | #import "Platforms/Mac/CCDirectorMac.h" | ||
41 | #endif | ||
42 | |||
43 | enum { | ||
44 | kDefaultPadding = 5, | ||
45 | }; | ||
46 | |||
47 | @implementation CCMenu | ||
48 | |||
49 | @synthesize opacity = opacity_, color = color_; | ||
50 | |||
51 | - (id) init | ||
52 | { | ||
53 | NSAssert(NO, @"CCMenu: Init not supported."); | ||
54 | [self release]; | ||
55 | return nil; | ||
56 | } | ||
57 | |||
58 | +(id) menuWithItems: (CCMenuItem*) item, ... | ||
59 | { | ||
60 | va_list args; | ||
61 | va_start(args,item); | ||
62 | |||
63 | id s = [[[self alloc] initWithItems: item vaList:args] autorelease]; | ||
64 | |||
65 | va_end(args); | ||
66 | return s; | ||
67 | } | ||
68 | |||
69 | -(id) initWithItems: (CCMenuItem*) item vaList: (va_list) args | ||
70 | { | ||
71 | if( (self=[super init]) ) { | ||
72 | |||
73 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
74 | self.isTouchEnabled = YES; | ||
75 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
76 | self.isMouseEnabled = YES; | ||
77 | #endif | ||
78 | |||
79 | // menu in the center of the screen | ||
80 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
81 | |||
82 | self.isRelativeAnchorPoint = NO; | ||
83 | anchorPoint_ = ccp(0.5f, 0.5f); | ||
84 | [self setContentSize:s]; | ||
85 | |||
86 | // XXX: in v0.7, winSize should return the visible size | ||
87 | // XXX: so the bar calculation should be done there | ||
88 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
89 | CGRect r = [[UIApplication sharedApplication] statusBarFrame]; | ||
90 | ccDeviceOrientation orientation = [[CCDirector sharedDirector] deviceOrientation]; | ||
91 | if( orientation == CCDeviceOrientationLandscapeLeft || orientation == CCDeviceOrientationLandscapeRight ) | ||
92 | s.height -= r.size.width; | ||
93 | else | ||
94 | s.height -= r.size.height; | ||
95 | #endif | ||
96 | self.position = ccp(s.width/2, s.height/2); | ||
97 | |||
98 | int z=0; | ||
99 | |||
100 | if (item) { | ||
101 | [self addChild: item z:z]; | ||
102 | CCMenuItem *i = va_arg(args, CCMenuItem*); | ||
103 | while(i) { | ||
104 | z++; | ||
105 | [self addChild: i z:z]; | ||
106 | i = va_arg(args, CCMenuItem*); | ||
107 | } | ||
108 | } | ||
109 | // [self alignItemsVertically]; | ||
110 | |||
111 | selectedItem_ = nil; | ||
112 | state_ = kCCMenuStateWaiting; | ||
113 | } | ||
114 | |||
115 | return self; | ||
116 | } | ||
117 | |||
118 | -(void) dealloc | ||
119 | { | ||
120 | [super dealloc]; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * override add: | ||
125 | */ | ||
126 | -(void) addChild:(CCMenuItem*)child z:(NSInteger)z tag:(NSInteger) aTag | ||
127 | { | ||
128 | NSAssert( [child isKindOfClass:[CCMenuItem class]], @"Menu only supports MenuItem objects as children"); | ||
129 | [super addChild:child z:z tag:aTag]; | ||
130 | } | ||
131 | |||
132 | - (void) onExit | ||
133 | { | ||
134 | if(state_ == kCCMenuStateTrackingTouch) | ||
135 | { | ||
136 | [selectedItem_ unselected]; | ||
137 | state_ = kCCMenuStateWaiting; | ||
138 | selectedItem_ = nil; | ||
139 | } | ||
140 | [super onExit]; | ||
141 | } | ||
142 | |||
143 | #pragma mark Menu - Touches | ||
144 | |||
145 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
146 | -(void) registerWithTouchDispatcher | ||
147 | { | ||
148 | [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:kCCMenuTouchPriority swallowsTouches:YES]; | ||
149 | } | ||
150 | |||
151 | -(CCMenuItem *) itemForTouch: (UITouch *) touch | ||
152 | { | ||
153 | CGPoint touchLocation = [touch locationInView: [touch view]]; | ||
154 | touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation]; | ||
155 | |||
156 | CCMenuItem* item; | ||
157 | CCARRAY_FOREACH(children_, item){ | ||
158 | // ignore invisible and disabled items: issue #779, #866 | ||
159 | if ( [item visible] && [item isEnabled] ) { | ||
160 | |||
161 | CGPoint local = [item convertToNodeSpace:touchLocation]; | ||
162 | CGRect r = [item rect]; | ||
163 | r.origin = CGPointZero; | ||
164 | |||
165 | if( CGRectContainsPoint( r, local ) ) | ||
166 | return item; | ||
167 | } | ||
168 | } | ||
169 | return nil; | ||
170 | } | ||
171 | |||
172 | -(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event | ||
173 | { | ||
174 | if( state_ != kCCMenuStateWaiting || !visible_ ) | ||
175 | return NO; | ||
176 | |||
177 | selectedItem_ = [self itemForTouch:touch]; | ||
178 | [selectedItem_ selected]; | ||
179 | |||
180 | if( selectedItem_ ) { | ||
181 | state_ = kCCMenuStateTrackingTouch; | ||
182 | return YES; | ||
183 | } | ||
184 | return NO; | ||
185 | } | ||
186 | |||
187 | -(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event | ||
188 | { | ||
189 | NSAssert(state_ == kCCMenuStateTrackingTouch, @"[Menu ccTouchEnded] -- invalid state"); | ||
190 | |||
191 | [selectedItem_ unselected]; | ||
192 | [selectedItem_ activate]; | ||
193 | |||
194 | state_ = kCCMenuStateWaiting; | ||
195 | } | ||
196 | |||
197 | -(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event | ||
198 | { | ||
199 | NSAssert(state_ == kCCMenuStateTrackingTouch, @"[Menu ccTouchCancelled] -- invalid state"); | ||
200 | |||
201 | [selectedItem_ unselected]; | ||
202 | |||
203 | state_ = kCCMenuStateWaiting; | ||
204 | } | ||
205 | |||
206 | -(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event | ||
207 | { | ||
208 | NSAssert(state_ == kCCMenuStateTrackingTouch, @"[Menu ccTouchMoved] -- invalid state"); | ||
209 | |||
210 | CCMenuItem *currentItem = [self itemForTouch:touch]; | ||
211 | |||
212 | if (currentItem != selectedItem_) { | ||
213 | [selectedItem_ unselected]; | ||
214 | selectedItem_ = currentItem; | ||
215 | [selectedItem_ selected]; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | #pragma mark Menu - Mouse | ||
220 | |||
221 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
222 | |||
223 | -(NSInteger) mouseDelegatePriority | ||
224 | { | ||
225 | return kCCMenuMousePriority+1; | ||
226 | } | ||
227 | |||
228 | -(CCMenuItem *) itemForMouseEvent: (NSEvent *) event | ||
229 | { | ||
230 | CGPoint location = [(CCDirectorMac*)[CCDirector sharedDirector] convertEventToGL:event]; | ||
231 | |||
232 | CCMenuItem* item; | ||
233 | CCARRAY_FOREACH(children_, item){ | ||
234 | // ignore invisible and disabled items: issue #779, #866 | ||
235 | if ( [item visible] && [item isEnabled] ) { | ||
236 | |||
237 | CGPoint local = [item convertToNodeSpace:location]; | ||
238 | |||
239 | CGRect r = [item rect]; | ||
240 | r.origin = CGPointZero; | ||
241 | |||
242 | if( CGRectContainsPoint( r, local ) ) | ||
243 | return item; | ||
244 | } | ||
245 | } | ||
246 | return nil; | ||
247 | } | ||
248 | |||
249 | -(BOOL) ccMouseUp:(NSEvent *)event | ||
250 | { | ||
251 | if( ! visible_ ) | ||
252 | return NO; | ||
253 | |||
254 | if(state_ == kCCMenuStateTrackingTouch) { | ||
255 | if( selectedItem_ ) { | ||
256 | [selectedItem_ unselected]; | ||
257 | [selectedItem_ activate]; | ||
258 | } | ||
259 | state_ = kCCMenuStateWaiting; | ||
260 | |||
261 | return YES; | ||
262 | } | ||
263 | return NO; | ||
264 | } | ||
265 | |||
266 | -(BOOL) ccMouseDown:(NSEvent *)event | ||
267 | { | ||
268 | if( ! visible_ ) | ||
269 | return NO; | ||
270 | |||
271 | selectedItem_ = [self itemForMouseEvent:event]; | ||
272 | [selectedItem_ selected]; | ||
273 | |||
274 | if( selectedItem_ ) { | ||
275 | state_ = kCCMenuStateTrackingTouch; | ||
276 | return YES; | ||
277 | } | ||
278 | |||
279 | return NO; | ||
280 | } | ||
281 | |||
282 | -(BOOL) ccMouseDragged:(NSEvent *)event | ||
283 | { | ||
284 | if( ! visible_ ) | ||
285 | return NO; | ||
286 | |||
287 | if(state_ == kCCMenuStateTrackingTouch) { | ||
288 | CCMenuItem *currentItem = [self itemForMouseEvent:event]; | ||
289 | |||
290 | if (currentItem != selectedItem_) { | ||
291 | [selectedItem_ unselected]; | ||
292 | selectedItem_ = currentItem; | ||
293 | [selectedItem_ selected]; | ||
294 | } | ||
295 | |||
296 | return YES; | ||
297 | } | ||
298 | return NO; | ||
299 | } | ||
300 | |||
301 | #endif // Mac Mouse support | ||
302 | |||
303 | #pragma mark Menu - Alignment | ||
304 | -(void) alignItemsVertically | ||
305 | { | ||
306 | [self alignItemsVerticallyWithPadding:kDefaultPadding]; | ||
307 | } | ||
308 | -(void) alignItemsVerticallyWithPadding:(float)padding | ||
309 | { | ||
310 | float height = -padding; | ||
311 | |||
312 | CCMenuItem *item; | ||
313 | CCARRAY_FOREACH(children_, item) | ||
314 | height += item.contentSize.height * item.scaleY + padding; | ||
315 | |||
316 | float y = height / 2.0f; | ||
317 | |||
318 | CCARRAY_FOREACH(children_, item) { | ||
319 | CGSize itemSize = item.contentSize; | ||
320 | [item setPosition:ccp(0, y - itemSize.height * item.scaleY / 2.0f)]; | ||
321 | y -= itemSize.height * item.scaleY + padding; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | -(void) alignItemsHorizontally | ||
326 | { | ||
327 | [self alignItemsHorizontallyWithPadding:kDefaultPadding]; | ||
328 | } | ||
329 | |||
330 | -(void) alignItemsHorizontallyWithPadding:(float)padding | ||
331 | { | ||
332 | |||
333 | float width = -padding; | ||
334 | CCMenuItem *item; | ||
335 | CCARRAY_FOREACH(children_, item) | ||
336 | width += item.contentSize.width * item.scaleX + padding; | ||
337 | |||
338 | float x = -width / 2.0f; | ||
339 | |||
340 | CCARRAY_FOREACH(children_, item){ | ||
341 | CGSize itemSize = item.contentSize; | ||
342 | [item setPosition:ccp(x + itemSize.width * item.scaleX / 2.0f, 0)]; | ||
343 | x += itemSize.width * item.scaleX + padding; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | -(void) alignItemsInColumns: (NSNumber *) columns, ... | ||
348 | { | ||
349 | va_list args; | ||
350 | va_start(args, columns); | ||
351 | |||
352 | [self alignItemsInColumns:columns vaList:args]; | ||
353 | |||
354 | va_end(args); | ||
355 | } | ||
356 | |||
357 | -(void) alignItemsInColumns: (NSNumber *) columns vaList: (va_list) args | ||
358 | { | ||
359 | NSMutableArray *rows = [[NSMutableArray alloc] initWithObjects:columns, nil]; | ||
360 | columns = va_arg(args, NSNumber*); | ||
361 | while(columns) { | ||
362 | [rows addObject:columns]; | ||
363 | columns = va_arg(args, NSNumber*); | ||
364 | } | ||
365 | |||
366 | int height = -5; | ||
367 | NSUInteger row = 0, rowHeight = 0, columnsOccupied = 0, rowColumns; | ||
368 | CCMenuItem *item; | ||
369 | CCARRAY_FOREACH(children_, item){ | ||
370 | NSAssert( row < [rows count], @"Too many menu items for the amount of rows/columns."); | ||
371 | |||
372 | rowColumns = [(NSNumber *) [rows objectAtIndex:row] unsignedIntegerValue]; | ||
373 | NSAssert( rowColumns, @"Can't have zero columns on a row"); | ||
374 | |||
375 | rowHeight = fmaxf(rowHeight, item.contentSize.height); | ||
376 | ++columnsOccupied; | ||
377 | |||
378 | if(columnsOccupied >= rowColumns) { | ||
379 | height += rowHeight + 5; | ||
380 | |||
381 | columnsOccupied = 0; | ||
382 | rowHeight = 0; | ||
383 | ++row; | ||
384 | } | ||
385 | } | ||
386 | NSAssert( !columnsOccupied, @"Too many rows/columns for available menu items." ); | ||
387 | |||
388 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
389 | |||
390 | row = 0; rowHeight = 0; rowColumns = 0; | ||
391 | float w, x, y = height / 2; | ||
392 | CCARRAY_FOREACH(children_, item) { | ||
393 | if(rowColumns == 0) { | ||
394 | rowColumns = [(NSNumber *) [rows objectAtIndex:row] unsignedIntegerValue]; | ||
395 | w = winSize.width / (1 + rowColumns); | ||
396 | x = w; | ||
397 | } | ||
398 | |||
399 | CGSize itemSize = item.contentSize; | ||
400 | rowHeight = fmaxf(rowHeight, itemSize.height); | ||
401 | [item setPosition:ccp(x - winSize.width / 2, | ||
402 | y - itemSize.height / 2)]; | ||
403 | |||
404 | x += w; | ||
405 | ++columnsOccupied; | ||
406 | |||
407 | if(columnsOccupied >= rowColumns) { | ||
408 | y -= rowHeight + 5; | ||
409 | |||
410 | columnsOccupied = 0; | ||
411 | rowColumns = 0; | ||
412 | rowHeight = 0; | ||
413 | ++row; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | [rows release]; | ||
418 | } | ||
419 | |||
420 | -(void) alignItemsInRows: (NSNumber *) rows, ... | ||
421 | { | ||
422 | va_list args; | ||
423 | va_start(args, rows); | ||
424 | |||
425 | [self alignItemsInRows:rows vaList:args]; | ||
426 | |||
427 | va_end(args); | ||
428 | } | ||
429 | |||
430 | -(void) alignItemsInRows: (NSNumber *) rows vaList: (va_list) args | ||
431 | { | ||
432 | NSMutableArray *columns = [[NSMutableArray alloc] initWithObjects:rows, nil]; | ||
433 | rows = va_arg(args, NSNumber*); | ||
434 | while(rows) { | ||
435 | [columns addObject:rows]; | ||
436 | rows = va_arg(args, NSNumber*); | ||
437 | } | ||
438 | |||
439 | NSMutableArray *columnWidths = [[NSMutableArray alloc] init]; | ||
440 | NSMutableArray *columnHeights = [[NSMutableArray alloc] init]; | ||
441 | |||
442 | int width = -10, columnHeight = -5; | ||
443 | NSUInteger column = 0, columnWidth = 0, rowsOccupied = 0, columnRows; | ||
444 | CCMenuItem *item; | ||
445 | CCARRAY_FOREACH(children_, item){ | ||
446 | NSAssert( column < [columns count], @"Too many menu items for the amount of rows/columns."); | ||
447 | |||
448 | columnRows = [(NSNumber *) [columns objectAtIndex:column] unsignedIntegerValue]; | ||
449 | NSAssert( columnRows, @"Can't have zero rows on a column"); | ||
450 | |||
451 | CGSize itemSize = item.contentSize; | ||
452 | columnWidth = fmaxf(columnWidth, itemSize.width); | ||
453 | columnHeight += itemSize.height + 5; | ||
454 | ++rowsOccupied; | ||
455 | |||
456 | if(rowsOccupied >= columnRows) { | ||
457 | [columnWidths addObject:[NSNumber numberWithUnsignedInteger:columnWidth]]; | ||
458 | [columnHeights addObject:[NSNumber numberWithUnsignedInteger:columnHeight]]; | ||
459 | width += columnWidth + 10; | ||
460 | |||
461 | rowsOccupied = 0; | ||
462 | columnWidth = 0; | ||
463 | columnHeight = -5; | ||
464 | ++column; | ||
465 | } | ||
466 | } | ||
467 | NSAssert( !rowsOccupied, @"Too many rows/columns for available menu items."); | ||
468 | |||
469 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
470 | |||
471 | column = 0; columnWidth = 0; columnRows = 0; | ||
472 | float x = -width / 2, y; | ||
473 | |||
474 | CCARRAY_FOREACH(children_, item){ | ||
475 | if(columnRows == 0) { | ||
476 | columnRows = [(NSNumber *) [columns objectAtIndex:column] unsignedIntegerValue]; | ||
477 | y = ([(NSNumber *) [columnHeights objectAtIndex:column] intValue] + winSize.height) / 2; | ||
478 | } | ||
479 | |||
480 | CGSize itemSize = item.contentSize; | ||
481 | columnWidth = fmaxf(columnWidth, itemSize.width); | ||
482 | [item setPosition:ccp(x + [(NSNumber *) [columnWidths objectAtIndex:column] unsignedIntegerValue] / 2, | ||
483 | y - winSize.height / 2)]; | ||
484 | |||
485 | y -= itemSize.height + 10; | ||
486 | ++rowsOccupied; | ||
487 | |||
488 | if(rowsOccupied >= columnRows) { | ||
489 | x += columnWidth + 5; | ||
490 | |||
491 | rowsOccupied = 0; | ||
492 | columnRows = 0; | ||
493 | columnWidth = 0; | ||
494 | ++column; | ||
495 | } | ||
496 | } | ||
497 | |||
498 | [columns release]; | ||
499 | [columnWidths release]; | ||
500 | [columnHeights release]; | ||
501 | } | ||
502 | |||
503 | #pragma mark Menu - Opacity Protocol | ||
504 | |||
505 | /** Override synthesized setOpacity to recurse items */ | ||
506 | - (void) setOpacity:(GLubyte)newOpacity | ||
507 | { | ||
508 | opacity_ = newOpacity; | ||
509 | |||
510 | id<CCRGBAProtocol> item; | ||
511 | CCARRAY_FOREACH(children_, item) | ||
512 | [item setOpacity:opacity_]; | ||
513 | } | ||
514 | |||
515 | -(void) setColor:(ccColor3B)color | ||
516 | { | ||
517 | color_ = color; | ||
518 | |||
519 | id<CCRGBAProtocol> item; | ||
520 | CCARRAY_FOREACH(children_, item) | ||
521 | [item setColor:color_]; | ||
522 | } | ||
523 | @end | ||
diff --git a/libs/cocos2d/CCMenuItem.h b/libs/cocos2d/CCMenuItem.h new file mode 100755 index 0000000..2437394 --- /dev/null +++ b/libs/cocos2d/CCMenuItem.h | |||
@@ -0,0 +1,377 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2011 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 | #import "CCBlockSupport.h" | ||
28 | |||
29 | #import "CCNode.h" | ||
30 | #import "CCProtocols.h" | ||
31 | |||
32 | @class CCSprite; | ||
33 | |||
34 | #define kCCItemSize 32 | ||
35 | |||
36 | #pragma mark - | ||
37 | #pragma mark CCMenuItem | ||
38 | /** CCMenuItem base class | ||
39 | * | ||
40 | * Subclass CCMenuItem (or any subclass) to create your custom CCMenuItem objects. | ||
41 | */ | ||
42 | @interface CCMenuItem : CCNode | ||
43 | { | ||
44 | NSInvocation *invocation_; | ||
45 | #if NS_BLOCKS_AVAILABLE | ||
46 | // used for menu items using a block | ||
47 | void (^block_)(id sender); | ||
48 | #endif | ||
49 | |||
50 | BOOL isEnabled_; | ||
51 | BOOL isSelected_; | ||
52 | } | ||
53 | |||
54 | /** returns whether or not the item is selected | ||
55 | @since v0.8.2 | ||
56 | */ | ||
57 | @property (nonatomic,readonly) BOOL isSelected; | ||
58 | |||
59 | /** Creates a CCMenuItem with a target/selector */ | ||
60 | +(id) itemWithTarget:(id)target selector:(SEL)selector; | ||
61 | |||
62 | /** Initializes a CCMenuItem with a target/selector */ | ||
63 | -(id) initWithTarget:(id)target selector:(SEL)selector; | ||
64 | |||
65 | #if NS_BLOCKS_AVAILABLE | ||
66 | /** Creates a CCMenuItem with the specified block. | ||
67 | The block will be "copied". | ||
68 | */ | ||
69 | +(id) itemWithBlock:(void(^)(id sender))block; | ||
70 | |||
71 | /** Initializes a CCMenuItem with the specified block. | ||
72 | The block will be "copied". | ||
73 | */ | ||
74 | -(id) initWithBlock:(void(^)(id sender))block; | ||
75 | #endif | ||
76 | |||
77 | /** Returns the outside box in points */ | ||
78 | -(CGRect) rect; | ||
79 | |||
80 | /** Activate the item */ | ||
81 | -(void) activate; | ||
82 | |||
83 | /** The item was selected (not activated), similar to "mouse-over" */ | ||
84 | -(void) selected; | ||
85 | |||
86 | /** The item was unselected */ | ||
87 | -(void) unselected; | ||
88 | |||
89 | /** Enable or disabled the CCMenuItem */ | ||
90 | -(void) setIsEnabled:(BOOL)enabled; | ||
91 | /** Returns whether or not the CCMenuItem is enabled */ | ||
92 | -(BOOL) isEnabled; | ||
93 | @end | ||
94 | |||
95 | #pragma mark - | ||
96 | #pragma mark CCMenuItemLabel | ||
97 | |||
98 | /** An abstract class for "label" CCMenuItemLabel items | ||
99 | Any CCNode that supports the CCLabelProtocol protocol can be added. | ||
100 | Supported nodes: | ||
101 | - CCLabelBMFont | ||
102 | - CCLabelAtlas | ||
103 | - CCLabelTTF | ||
104 | */ | ||
105 | @interface CCMenuItemLabel : CCMenuItem <CCRGBAProtocol> | ||
106 | { | ||
107 | CCNode<CCLabelProtocol, CCRGBAProtocol> *label_; | ||
108 | ccColor3B colorBackup; | ||
109 | ccColor3B disabledColor_; | ||
110 | float originalScale_; | ||
111 | } | ||
112 | |||
113 | /** the color that will be used to disable the item */ | ||
114 | @property (nonatomic,readwrite) ccColor3B disabledColor; | ||
115 | |||
116 | /** Label that is rendered. It can be any CCNode that implements the CCLabelProtocol */ | ||
117 | @property (nonatomic,readwrite,assign) CCNode<CCLabelProtocol, CCRGBAProtocol>* label; | ||
118 | |||
119 | /** creates a CCMenuItemLabel with a Label. Target and selector will be nill */ | ||
120 | +(id) itemWithLabel:(CCNode<CCLabelProtocol,CCRGBAProtocol>*)label; | ||
121 | |||
122 | /** creates a CCMenuItemLabel with a Label, target and selector */ | ||
123 | +(id) itemWithLabel:(CCNode<CCLabelProtocol,CCRGBAProtocol>*)label target:(id)target selector:(SEL)selector; | ||
124 | |||
125 | /** initializes a CCMenuItemLabel with a Label, target and selector */ | ||
126 | -(id) initWithLabel:(CCNode<CCLabelProtocol,CCRGBAProtocol>*)label target:(id)target selector:(SEL)selector; | ||
127 | |||
128 | #if NS_BLOCKS_AVAILABLE | ||
129 | /** creates a CCMenuItemLabel with a Label and a block to execute. | ||
130 | The block will be "copied". | ||
131 | */ | ||
132 | +(id) itemWithLabel:(CCNode<CCLabelProtocol,CCRGBAProtocol>*)label block:(void(^)(id sender))block; | ||
133 | |||
134 | /** initializes a CCMenuItemLabel with a Label and a block to execute. | ||
135 | The block will be "copied". | ||
136 | */ | ||
137 | -(id) initWithLabel:(CCNode<CCLabelProtocol,CCRGBAProtocol>*)label block:(void(^)(id sender))block; | ||
138 | #endif | ||
139 | |||
140 | /** sets a new string to the inner label */ | ||
141 | -(void) setString:(NSString*)label; | ||
142 | |||
143 | /** Enable or disabled the CCMenuItemFont | ||
144 | @warning setIsEnabled changes the RGB color of the font | ||
145 | */ | ||
146 | -(void) setIsEnabled: (BOOL)enabled; | ||
147 | @end | ||
148 | |||
149 | #pragma mark - | ||
150 | #pragma mark CCMenuItemAtlasFont | ||
151 | |||
152 | /** A CCMenuItemAtlasFont | ||
153 | Helper class that creates a MenuItemLabel class with a LabelAtlas | ||
154 | */ | ||
155 | @interface CCMenuItemAtlasFont : CCMenuItemLabel | ||
156 | { | ||
157 | } | ||
158 | |||
159 | /** creates a menu item from a string and atlas with a target/selector */ | ||
160 | +(id) itemFromString: (NSString*) value charMapFile:(NSString*) charMapFile itemWidth:(int)itemWidth itemHeight:(int)itemHeight startCharMap:(char)startCharMap; | ||
161 | |||
162 | /** creates a menu item from a string and atlas. Use it with MenuItemToggle */ | ||
163 | +(id) itemFromString: (NSString*) value charMapFile:(NSString*) charMapFile itemWidth:(int)itemWidth itemHeight:(int)itemHeight startCharMap:(char)startCharMap target:(id) rec selector:(SEL) cb; | ||
164 | |||
165 | /** initializes a menu item from a string and atlas with a target/selector */ | ||
166 | -(id) initFromString: (NSString*) value charMapFile:(NSString*) charMapFile itemWidth:(int)itemWidth itemHeight:(int)itemHeight startCharMap:(char)startCharMap target:(id) rec selector:(SEL) cb; | ||
167 | |||
168 | #if NS_BLOCKS_AVAILABLE | ||
169 | /** creates a menu item from a string and atlas. Use it with MenuItemToggle. | ||
170 | The block will be "copied". | ||
171 | */ | ||
172 | +(id) itemFromString: (NSString*) value charMapFile:(NSString*) charMapFile itemWidth:(int)itemWidth itemHeight:(int)itemHeight startCharMap:(char)startCharMap block:(void(^)(id sender))block; | ||
173 | |||
174 | /** initializes a menu item from a string and atlas with a block. | ||
175 | The block will be "copied". | ||
176 | */ | ||
177 | -(id) initFromString: (NSString*) value charMapFile:(NSString*) charMapFile itemWidth:(int)itemWidth itemHeight:(int)itemHeight startCharMap:(char)startCharMap block:(void(^)(id sender))block; | ||
178 | #endif | ||
179 | |||
180 | @end | ||
181 | |||
182 | #pragma mark - | ||
183 | #pragma mark CCMenuItemFont | ||
184 | |||
185 | /** A CCMenuItemFont | ||
186 | Helper class that creates a CCMenuItemLabel class with a Label | ||
187 | */ | ||
188 | @interface CCMenuItemFont : CCMenuItemLabel | ||
189 | { | ||
190 | NSUInteger fontSize_; | ||
191 | NSString *fontName_; | ||
192 | } | ||
193 | /** set default font size */ | ||
194 | +(void) setFontSize: (NSUInteger) s; | ||
195 | |||
196 | /** get default font size */ | ||
197 | +(NSUInteger) fontSize; | ||
198 | |||
199 | /** set default font name */ | ||
200 | +(void) setFontName: (NSString*) n; | ||
201 | |||
202 | /** get default font name */ | ||
203 | +(NSString*) fontName; | ||
204 | |||
205 | /** creates a menu item from a string without target/selector. To be used with CCMenuItemToggle */ | ||
206 | +(id) itemFromString: (NSString*) value; | ||
207 | |||
208 | /** creates a menu item from a string with a target/selector */ | ||
209 | +(id) itemFromString: (NSString*) value target:(id) r selector:(SEL) s; | ||
210 | |||
211 | /** initializes a menu item from a string with a target/selector */ | ||
212 | -(id) initFromString: (NSString*) value target:(id) r selector:(SEL) s; | ||
213 | |||
214 | /** set font size */ | ||
215 | -(void) setFontSize: (NSUInteger) s; | ||
216 | |||
217 | /** get font size */ | ||
218 | -(NSUInteger) fontSize; | ||
219 | |||
220 | /** set the font name */ | ||
221 | -(void) setFontName: (NSString*) n; | ||
222 | |||
223 | /** get the font name */ | ||
224 | -(NSString*) fontName; | ||
225 | |||
226 | #if NS_BLOCKS_AVAILABLE | ||
227 | /** creates a menu item from a string with the specified block. | ||
228 | The block will be "copied". | ||
229 | */ | ||
230 | +(id) itemFromString: (NSString*) value block:(void(^)(id sender))block; | ||
231 | |||
232 | /** initializes a menu item from a string with the specified block. | ||
233 | The block will be "copied". | ||
234 | */ | ||
235 | -(id) initFromString: (NSString*) value block:(void(^)(id sender))block; | ||
236 | #endif | ||
237 | @end | ||
238 | |||
239 | #pragma mark - | ||
240 | #pragma mark CCMenuItemSprite | ||
241 | |||
242 | /** CCMenuItemSprite accepts CCNode<CCRGBAProtocol> objects as items. | ||
243 | The images has 3 different states: | ||
244 | - unselected image | ||
245 | - selected image | ||
246 | - disabled image | ||
247 | |||
248 | @since v0.8.0 | ||
249 | */ | ||
250 | @interface CCMenuItemSprite : CCMenuItem <CCRGBAProtocol> | ||
251 | { | ||
252 | CCNode<CCRGBAProtocol> *normalImage_, *selectedImage_, *disabledImage_; | ||
253 | } | ||
254 | |||
255 | // weak references | ||
256 | |||
257 | /** the image used when the item is not selected */ | ||
258 | @property (nonatomic,readwrite,assign) CCNode<CCRGBAProtocol> *normalImage; | ||
259 | /** the image used when the item is selected */ | ||
260 | @property (nonatomic,readwrite,assign) CCNode<CCRGBAProtocol> *selectedImage; | ||
261 | /** the image used when the item is disabled */ | ||
262 | @property (nonatomic,readwrite,assign) CCNode<CCRGBAProtocol> *disabledImage; | ||
263 | |||
264 | /** creates a menu item with a normal and selected image*/ | ||
265 | +(id) itemFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite; | ||
266 | /** creates a menu item with a normal and selected image with target/selector */ | ||
267 | +(id) itemFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite target:(id)target selector:(SEL)selector; | ||
268 | /** creates a menu item with a normal,selected and disabled image with target/selector */ | ||
269 | +(id) itemFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite disabledSprite:(CCNode<CCRGBAProtocol>*)disabledSprite target:(id)target selector:(SEL)selector; | ||
270 | /** initializes a menu item with a normal, selected and disabled image with target/selector */ | ||
271 | -(id) initFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite disabledSprite:(CCNode<CCRGBAProtocol>*)disabledSprite target:(id)target selector:(SEL)selector; | ||
272 | |||
273 | #if NS_BLOCKS_AVAILABLE | ||
274 | /** creates a menu item with a normal and selected image with a block. | ||
275 | The block will be "copied". | ||
276 | */ | ||
277 | +(id) itemFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite block:(void(^)(id sender))block; | ||
278 | /** creates a menu item with a normal,selected and disabled image with a block. | ||
279 | The block will be "copied". | ||
280 | */ | ||
281 | +(id) itemFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite disabledSprite:(CCNode<CCRGBAProtocol>*)disabledSprite block:(void(^)(id sender))block; | ||
282 | /** initializes a menu item with a normal, selected and disabled image with a block. | ||
283 | The block will be "copied". | ||
284 | */ | ||
285 | -(id) initFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite disabledSprite:(CCNode<CCRGBAProtocol>*)disabledSprite block:(void(^)(id sender))block; | ||
286 | #endif | ||
287 | |||
288 | @end | ||
289 | |||
290 | #pragma mark - | ||
291 | #pragma mark CCMenuItemImage | ||
292 | |||
293 | /** CCMenuItemImage accepts images as items. | ||
294 | The images has 3 different states: | ||
295 | - unselected image | ||
296 | - selected image | ||
297 | - disabled image | ||
298 | |||
299 | For best results try that all images are of the same size | ||
300 | */ | ||
301 | @interface CCMenuItemImage : CCMenuItemSprite | ||
302 | { | ||
303 | } | ||
304 | |||
305 | /** creates a menu item with a normal and selected image*/ | ||
306 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2; | ||
307 | /** creates a menu item with a normal and selected image with target/selector */ | ||
308 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2 target:(id) r selector:(SEL) s; | ||
309 | /** creates a menu item with a normal,selected and disabled image with target/selector */ | ||
310 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2 disabledImage:(NSString*) value3 target:(id) r selector:(SEL) s; | ||
311 | /** initializes a menu item with a normal, selected and disabled image with target/selector */ | ||
312 | -(id) initFromNormalImage: (NSString*) value selectedImage:(NSString*)value2 disabledImage:(NSString*) value3 target:(id) r selector:(SEL) s; | ||
313 | #if NS_BLOCKS_AVAILABLE | ||
314 | /** creates a menu item with a normal and selected image with a block. | ||
315 | The block will be "copied". | ||
316 | */ | ||
317 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2 block:(void(^)(id sender))block; | ||
318 | /** creates a menu item with a normal,selected and disabled image with a block. | ||
319 | The block will be "copied". | ||
320 | */ | ||
321 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2 disabledImage:(NSString*) value3 block:(void(^)(id sender))block; | ||
322 | /** initializes a menu item with a normal, selected and disabled image with a block. | ||
323 | The block will be "copied". | ||
324 | */ | ||
325 | -(id) initFromNormalImage: (NSString*) value selectedImage:(NSString*)value2 disabledImage:(NSString*) value3 block:(void(^)(id sender))block; | ||
326 | #endif | ||
327 | @end | ||
328 | |||
329 | #pragma mark - | ||
330 | #pragma mark CCMenuItemToggle | ||
331 | |||
332 | /** A CCMenuItemToggle | ||
333 | A simple container class that "toggles" it's inner items | ||
334 | The inner itmes can be any MenuItem | ||
335 | */ | ||
336 | @interface CCMenuItemToggle : CCMenuItem <CCRGBAProtocol> | ||
337 | { | ||
338 | NSUInteger selectedIndex_; | ||
339 | NSMutableArray* subItems_; | ||
340 | GLubyte opacity_; | ||
341 | ccColor3B color_; | ||
342 | } | ||
343 | |||
344 | /** conforms with CCRGBAProtocol protocol */ | ||
345 | @property (nonatomic,readonly) GLubyte opacity; | ||
346 | /** conforms with CCRGBAProtocol protocol */ | ||
347 | @property (nonatomic,readonly) ccColor3B color; | ||
348 | |||
349 | /** returns the selected item */ | ||
350 | @property (nonatomic,readwrite) NSUInteger selectedIndex; | ||
351 | /** NSMutableArray that contains the subitems. You can add/remove items in runtime, and you can replace the array with a new one. | ||
352 | @since v0.7.2 | ||
353 | */ | ||
354 | @property (nonatomic,readwrite,retain) NSMutableArray *subItems; | ||
355 | |||
356 | /** creates a menu item from a list of items with a target/selector */ | ||
357 | +(id) itemWithTarget:(id)t selector:(SEL)s items:(CCMenuItem*) item, ... NS_REQUIRES_NIL_TERMINATION; | ||
358 | |||
359 | /** initializes a menu item from a list of items with a target selector */ | ||
360 | -(id) initWithTarget:(id)t selector:(SEL)s items:(CCMenuItem*) item vaList:(va_list) args; | ||
361 | |||
362 | #if NS_BLOCKS_AVAILABLE | ||
363 | /** creates a menu item from a list of items and executes the given block when the item is selected. | ||
364 | The block will be "copied". | ||
365 | */ | ||
366 | +(id) itemWithBlock:(void(^)(id sender))block items:(CCMenuItem*)item, ... NS_REQUIRES_NIL_TERMINATION; | ||
367 | |||
368 | /** initializes a menu item from a list of items with a block. | ||
369 | The block will be "copied". | ||
370 | */ | ||
371 | -(id) initWithBlock:(void (^)(id))block items:(CCMenuItem*)item vaList:(va_list)args; | ||
372 | #endif | ||
373 | |||
374 | /** return the selected item */ | ||
375 | -(CCMenuItem*) selectedItem; | ||
376 | @end | ||
377 | |||
diff --git a/libs/cocos2d/CCMenuItem.m b/libs/cocos2d/CCMenuItem.m new file mode 100755 index 0000000..f88c0e0 --- /dev/null +++ b/libs/cocos2d/CCMenuItem.m | |||
@@ -0,0 +1,795 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2011 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 | #import "CCMenuItem.h" | ||
28 | #import "CCLabelTTF.h" | ||
29 | #import "CCLabelAtlas.h" | ||
30 | #import "CCActionInterval.h" | ||
31 | #import "CCSprite.h" | ||
32 | #import "Support/CGPointExtension.h" | ||
33 | #import "CCBlockSupport.h" | ||
34 | |||
35 | static NSUInteger _fontSize = kCCItemSize; | ||
36 | static NSString *_fontName = @"Marker Felt"; | ||
37 | static BOOL _fontNameRelease = NO; | ||
38 | |||
39 | |||
40 | const uint32_t kCurrentItem = 0xc0c05001; | ||
41 | const uint32_t kZoomActionTag = 0xc0c05002; | ||
42 | |||
43 | |||
44 | #pragma mark - | ||
45 | #pragma mark CCMenuItem | ||
46 | |||
47 | @implementation CCMenuItem | ||
48 | |||
49 | @synthesize isSelected=isSelected_; | ||
50 | -(id) init | ||
51 | { | ||
52 | NSAssert(NO, @"MenuItemInit: Init not supported."); | ||
53 | [self release]; | ||
54 | return nil; | ||
55 | } | ||
56 | |||
57 | +(id) itemWithTarget:(id) r selector:(SEL) s | ||
58 | { | ||
59 | return [[[self alloc] initWithTarget:r selector:s] autorelease]; | ||
60 | } | ||
61 | |||
62 | -(id) initWithTarget:(id) rec selector:(SEL) cb | ||
63 | { | ||
64 | if((self=[super init]) ) { | ||
65 | |||
66 | anchorPoint_ = ccp(0.5f, 0.5f); | ||
67 | NSMethodSignature * sig = nil; | ||
68 | |||
69 | if( rec && cb ) { | ||
70 | sig = [rec methodSignatureForSelector:cb]; | ||
71 | |||
72 | invocation_ = nil; | ||
73 | invocation_ = [NSInvocation invocationWithMethodSignature:sig]; | ||
74 | [invocation_ setTarget:rec]; | ||
75 | [invocation_ setSelector:cb]; | ||
76 | #if NS_BLOCKS_AVAILABLE | ||
77 | if ([sig numberOfArguments] == 3) | ||
78 | #endif | ||
79 | [invocation_ setArgument:&self atIndex:2]; | ||
80 | |||
81 | [invocation_ retain]; | ||
82 | } | ||
83 | |||
84 | isEnabled_ = YES; | ||
85 | isSelected_ = NO; | ||
86 | } | ||
87 | |||
88 | return self; | ||
89 | } | ||
90 | |||
91 | #if NS_BLOCKS_AVAILABLE | ||
92 | |||
93 | +(id) itemWithBlock:(void(^)(id sender))block { | ||
94 | return [[[self alloc] initWithBlock:block] autorelease]; | ||
95 | } | ||
96 | |||
97 | -(id) initWithBlock:(void(^)(id sender))block { | ||
98 | block_ = [block copy]; | ||
99 | return [self initWithTarget:block_ selector:@selector(ccCallbackBlockWithSender:)]; | ||
100 | } | ||
101 | |||
102 | #endif // NS_BLOCKS_AVAILABLE | ||
103 | |||
104 | -(void) dealloc | ||
105 | { | ||
106 | [invocation_ release]; | ||
107 | |||
108 | #if NS_BLOCKS_AVAILABLE | ||
109 | [block_ release]; | ||
110 | #endif | ||
111 | |||
112 | [super dealloc]; | ||
113 | } | ||
114 | |||
115 | -(void) selected | ||
116 | { | ||
117 | isSelected_ = YES; | ||
118 | } | ||
119 | |||
120 | -(void) unselected | ||
121 | { | ||
122 | isSelected_ = NO; | ||
123 | } | ||
124 | |||
125 | -(void) activate | ||
126 | { | ||
127 | if(isEnabled_) | ||
128 | [invocation_ invoke]; | ||
129 | } | ||
130 | |||
131 | -(void) setIsEnabled: (BOOL)enabled | ||
132 | { | ||
133 | isEnabled_ = enabled; | ||
134 | } | ||
135 | |||
136 | -(BOOL) isEnabled | ||
137 | { | ||
138 | return isEnabled_; | ||
139 | } | ||
140 | |||
141 | -(CGRect) rect | ||
142 | { | ||
143 | return CGRectMake( position_.x - contentSize_.width*anchorPoint_.x, | ||
144 | position_.y - contentSize_.height*anchorPoint_.y, | ||
145 | contentSize_.width, contentSize_.height); | ||
146 | } | ||
147 | |||
148 | @end | ||
149 | |||
150 | |||
151 | #pragma mark - | ||
152 | #pragma mark CCMenuItemLabel | ||
153 | |||
154 | @implementation CCMenuItemLabel | ||
155 | |||
156 | @synthesize disabledColor = disabledColor_; | ||
157 | |||
158 | +(id) itemWithLabel:(CCNode<CCLabelProtocol,CCRGBAProtocol>*)label target:(id)target selector:(SEL)selector | ||
159 | { | ||
160 | return [[[self alloc] initWithLabel:label target:target selector:selector] autorelease]; | ||
161 | } | ||
162 | |||
163 | +(id) itemWithLabel:(CCNode<CCLabelProtocol,CCRGBAProtocol>*)label | ||
164 | { | ||
165 | return [[[self alloc] initWithLabel:label target:nil selector:NULL] autorelease]; | ||
166 | } | ||
167 | |||
168 | -(id) initWithLabel:(CCNode<CCLabelProtocol,CCRGBAProtocol>*)label target:(id)target selector:(SEL)selector | ||
169 | { | ||
170 | if( (self=[super initWithTarget:target selector:selector]) ) { | ||
171 | originalScale_ = 1; | ||
172 | colorBackup = ccWHITE; | ||
173 | disabledColor_ = ccc3( 126,126,126); | ||
174 | self.label = label; | ||
175 | |||
176 | } | ||
177 | return self; | ||
178 | } | ||
179 | |||
180 | #if NS_BLOCKS_AVAILABLE | ||
181 | |||
182 | +(id) itemWithLabel:(CCNode<CCLabelProtocol,CCRGBAProtocol>*)label block:(void(^)(id sender))block { | ||
183 | return [[[self alloc] initWithLabel:label block:block] autorelease]; | ||
184 | } | ||
185 | |||
186 | -(id) initWithLabel:(CCNode<CCLabelProtocol,CCRGBAProtocol>*)label block:(void(^)(id sender))block { | ||
187 | block_ = [block copy]; | ||
188 | return [self initWithLabel:label target:block_ selector:@selector(ccCallbackBlockWithSender:)]; | ||
189 | } | ||
190 | |||
191 | #endif // NS_BLOCKS_AVAILABLE | ||
192 | |||
193 | -(CCNode<CCLabelProtocol, CCRGBAProtocol>*) label | ||
194 | { | ||
195 | return label_; | ||
196 | } | ||
197 | -(void) setLabel:(CCNode<CCLabelProtocol, CCRGBAProtocol>*) label | ||
198 | { | ||
199 | if( label != label_ ) { | ||
200 | [self removeChild:label_ cleanup:YES]; | ||
201 | [self addChild:label]; | ||
202 | |||
203 | label_ = label; | ||
204 | label_.anchorPoint = ccp(0,0); | ||
205 | |||
206 | [self setContentSize:[label_ contentSize]]; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | -(void) setString:(NSString *)string | ||
211 | { | ||
212 | [label_ setString:string]; | ||
213 | [self setContentSize: [label_ contentSize]]; | ||
214 | } | ||
215 | |||
216 | -(void) activate { | ||
217 | if(isEnabled_) { | ||
218 | [self stopAllActions]; | ||
219 | |||
220 | self.scale = originalScale_; | ||
221 | |||
222 | [super activate]; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | -(void) selected | ||
227 | { | ||
228 | // subclass to change the default action | ||
229 | if(isEnabled_) { | ||
230 | [super selected]; | ||
231 | |||
232 | CCAction *action = [self getActionByTag:kZoomActionTag]; | ||
233 | if( action ) | ||
234 | [self stopAction:action]; | ||
235 | else | ||
236 | originalScale_ = self.scale; | ||
237 | |||
238 | CCAction *zoomAction = [CCScaleTo actionWithDuration:0.1f scale:originalScale_ * 1.2f]; | ||
239 | zoomAction.tag = kZoomActionTag; | ||
240 | [self runAction:zoomAction]; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | -(void) unselected | ||
245 | { | ||
246 | // subclass to change the default action | ||
247 | if(isEnabled_) { | ||
248 | [super unselected]; | ||
249 | [self stopActionByTag:kZoomActionTag]; | ||
250 | CCAction *zoomAction = [CCScaleTo actionWithDuration:0.1f scale:originalScale_]; | ||
251 | zoomAction.tag = kZoomActionTag; | ||
252 | [self runAction:zoomAction]; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | -(void) setIsEnabled: (BOOL)enabled | ||
257 | { | ||
258 | if( isEnabled_ != enabled ) { | ||
259 | if(enabled == NO) { | ||
260 | colorBackup = [label_ color]; | ||
261 | [label_ setColor: disabledColor_]; | ||
262 | } | ||
263 | else | ||
264 | [label_ setColor:colorBackup]; | ||
265 | } | ||
266 | |||
267 | [super setIsEnabled:enabled]; | ||
268 | } | ||
269 | |||
270 | - (void) setOpacity: (GLubyte)opacity | ||
271 | { | ||
272 | [label_ setOpacity:opacity]; | ||
273 | } | ||
274 | -(GLubyte) opacity | ||
275 | { | ||
276 | return [label_ opacity]; | ||
277 | } | ||
278 | -(void) setColor:(ccColor3B)color | ||
279 | { | ||
280 | [label_ setColor:color]; | ||
281 | } | ||
282 | -(ccColor3B) color | ||
283 | { | ||
284 | return [label_ color]; | ||
285 | } | ||
286 | @end | ||
287 | |||
288 | #pragma mark - | ||
289 | #pragma mark CCMenuItemAtlasFont | ||
290 | |||
291 | @implementation CCMenuItemAtlasFont | ||
292 | |||
293 | +(id) itemFromString: (NSString*) value charMapFile:(NSString*) charMapFile itemWidth:(int)itemWidth itemHeight:(int)itemHeight startCharMap:(char)startCharMap | ||
294 | { | ||
295 | return [CCMenuItemAtlasFont itemFromString:value charMapFile:charMapFile itemWidth:itemWidth itemHeight:itemHeight startCharMap:startCharMap target:nil selector:nil]; | ||
296 | } | ||
297 | |||
298 | +(id) itemFromString: (NSString*) value charMapFile:(NSString*) charMapFile itemWidth:(int)itemWidth itemHeight:(int)itemHeight startCharMap:(char)startCharMap target:(id) rec selector:(SEL) cb | ||
299 | { | ||
300 | return [[[self alloc] initFromString:value charMapFile:charMapFile itemWidth:itemWidth itemHeight:itemHeight startCharMap:startCharMap target:rec selector:cb] autorelease]; | ||
301 | } | ||
302 | |||
303 | -(id) initFromString: (NSString*) value charMapFile:(NSString*) charMapFile itemWidth:(int)itemWidth itemHeight:(int)itemHeight startCharMap:(char)startCharMap target:(id) rec selector:(SEL) cb | ||
304 | { | ||
305 | NSAssert( [value length] != 0, @"value length must be greater than 0"); | ||
306 | |||
307 | CCLabelAtlas *label = [[CCLabelAtlas alloc] initWithString:value charMapFile:charMapFile itemWidth:itemWidth itemHeight:itemHeight startCharMap:startCharMap]; | ||
308 | [label autorelease]; | ||
309 | |||
310 | if((self=[super initWithLabel:label target:rec selector:cb]) ) { | ||
311 | // do something ? | ||
312 | } | ||
313 | |||
314 | return self; | ||
315 | } | ||
316 | |||
317 | #if NS_BLOCKS_AVAILABLE | ||
318 | +(id) itemFromString:(NSString*)value charMapFile:(NSString*)charMapFile itemWidth:(int)itemWidth itemHeight:(int)itemHeight startCharMap:(char)startCharMap block:(void(^)(id sender))block { | ||
319 | return [[[self alloc] initFromString:value charMapFile:charMapFile itemWidth:itemWidth itemHeight:itemHeight startCharMap:startCharMap block:block] autorelease]; | ||
320 | } | ||
321 | |||
322 | -(id) initFromString:(NSString*)value charMapFile:(NSString*)charMapFile itemWidth:(int)itemWidth itemHeight:(int)itemHeight startCharMap:(char)startCharMap block:(void(^)(id sender))block { | ||
323 | block_ = [block copy]; | ||
324 | return [self initFromString:value charMapFile:charMapFile itemWidth:itemWidth itemHeight:itemHeight startCharMap:startCharMap target:block_ selector:@selector(ccCallbackBlockWithSender:)]; | ||
325 | } | ||
326 | #endif // NS_BLOCKS_AVAILABLE | ||
327 | |||
328 | -(void) dealloc | ||
329 | { | ||
330 | [super dealloc]; | ||
331 | } | ||
332 | @end | ||
333 | |||
334 | |||
335 | #pragma mark - | ||
336 | #pragma mark CCMenuItemFont | ||
337 | |||
338 | @implementation CCMenuItemFont | ||
339 | |||
340 | +(void) setFontSize: (NSUInteger) s | ||
341 | { | ||
342 | _fontSize = s; | ||
343 | } | ||
344 | |||
345 | +(NSUInteger) fontSize | ||
346 | { | ||
347 | return _fontSize; | ||
348 | } | ||
349 | |||
350 | +(void) setFontName: (NSString*) n | ||
351 | { | ||
352 | if( _fontNameRelease ) | ||
353 | [_fontName release]; | ||
354 | |||
355 | _fontName = [n retain]; | ||
356 | _fontNameRelease = YES; | ||
357 | } | ||
358 | |||
359 | +(NSString*) fontName | ||
360 | { | ||
361 | return _fontName; | ||
362 | } | ||
363 | |||
364 | +(id) itemFromString: (NSString*) value target:(id) r selector:(SEL) s | ||
365 | { | ||
366 | return [[[self alloc] initFromString: value target:r selector:s] autorelease]; | ||
367 | } | ||
368 | |||
369 | +(id) itemFromString: (NSString*) value | ||
370 | { | ||
371 | return [[[self alloc] initFromString: value target:nil selector:nil] autorelease]; | ||
372 | } | ||
373 | |||
374 | -(id) initFromString: (NSString*) value target:(id) rec selector:(SEL) cb | ||
375 | { | ||
376 | NSAssert( [value length] != 0, @"Value length must be greater than 0"); | ||
377 | |||
378 | fontName_ = [_fontName copy]; | ||
379 | fontSize_ = _fontSize; | ||
380 | |||
381 | CCLabelTTF *label = [CCLabelTTF labelWithString:value fontName:fontName_ fontSize:fontSize_]; | ||
382 | |||
383 | if((self=[super initWithLabel:label target:rec selector:cb]) ) { | ||
384 | // do something ? | ||
385 | } | ||
386 | |||
387 | return self; | ||
388 | } | ||
389 | |||
390 | -(void) recreateLabel | ||
391 | { | ||
392 | CCLabelTTF *label = [CCLabelTTF labelWithString:[label_ string] fontName:fontName_ fontSize:fontSize_]; | ||
393 | self.label = label; | ||
394 | } | ||
395 | |||
396 | -(void) setFontSize: (NSUInteger) size | ||
397 | { | ||
398 | fontSize_ = size; | ||
399 | [self recreateLabel]; | ||
400 | } | ||
401 | |||
402 | -(NSUInteger) fontSize | ||
403 | { | ||
404 | return fontSize_; | ||
405 | } | ||
406 | |||
407 | -(void) setFontName: (NSString*) fontName | ||
408 | { | ||
409 | if (fontName_) | ||
410 | [fontName_ release]; | ||
411 | |||
412 | fontName_ = [fontName copy]; | ||
413 | [self recreateLabel]; | ||
414 | } | ||
415 | |||
416 | -(NSString*) fontName | ||
417 | { | ||
418 | return fontName_; | ||
419 | } | ||
420 | |||
421 | #if NS_BLOCKS_AVAILABLE | ||
422 | +(id) itemFromString: (NSString*) value block:(void(^)(id sender))block | ||
423 | { | ||
424 | return [[[self alloc] initFromString:value block:block] autorelease]; | ||
425 | } | ||
426 | |||
427 | -(id) initFromString: (NSString*) value block:(void(^)(id sender))block | ||
428 | { | ||
429 | block_ = [block copy]; | ||
430 | return [self initFromString:value target:block_ selector:@selector(ccCallbackBlockWithSender:)]; | ||
431 | } | ||
432 | #endif // NS_BLOCKS_AVAILABLE | ||
433 | |||
434 | @end | ||
435 | |||
436 | #pragma mark - | ||
437 | #pragma mark CCMenuItemSprite | ||
438 | @implementation CCMenuItemSprite | ||
439 | |||
440 | @synthesize normalImage=normalImage_, selectedImage=selectedImage_, disabledImage=disabledImage_; | ||
441 | |||
442 | +(id) itemFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite | ||
443 | { | ||
444 | return [self itemFromNormalSprite:normalSprite selectedSprite:selectedSprite disabledSprite:nil target:nil selector:nil]; | ||
445 | } | ||
446 | +(id) itemFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite target:(id)target selector:(SEL)selector | ||
447 | { | ||
448 | return [self itemFromNormalSprite:normalSprite selectedSprite:selectedSprite disabledSprite:nil target:target selector:selector]; | ||
449 | } | ||
450 | +(id) itemFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite disabledSprite:(CCNode<CCRGBAProtocol>*)disabledSprite target:(id)target selector:(SEL)selector | ||
451 | { | ||
452 | return [[[self alloc] initFromNormalSprite:normalSprite selectedSprite:selectedSprite disabledSprite:disabledSprite target:target selector:selector] autorelease]; | ||
453 | } | ||
454 | -(id) initFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite disabledSprite:(CCNode<CCRGBAProtocol>*)disabledSprite target:(id)target selector:(SEL)selector | ||
455 | { | ||
456 | if( (self=[super initWithTarget:target selector:selector]) ) { | ||
457 | |||
458 | self.normalImage = normalSprite; | ||
459 | self.selectedImage = selectedSprite; | ||
460 | self.disabledImage = disabledSprite; | ||
461 | |||
462 | [self setContentSize: [normalImage_ contentSize]]; | ||
463 | } | ||
464 | return self; | ||
465 | } | ||
466 | |||
467 | #if NS_BLOCKS_AVAILABLE | ||
468 | +(id) itemFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite block:(void(^)(id sender))block { | ||
469 | return [self itemFromNormalSprite:normalSprite selectedSprite:selectedSprite disabledSprite:nil block:block]; | ||
470 | } | ||
471 | |||
472 | +(id) itemFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite disabledSprite:(CCNode<CCRGBAProtocol>*)disabledSprite block:(void(^)(id sender))block { | ||
473 | return [[[self alloc] initFromNormalSprite:normalSprite selectedSprite:selectedSprite disabledSprite:disabledSprite block:block] autorelease]; | ||
474 | } | ||
475 | |||
476 | -(id) initFromNormalSprite:(CCNode<CCRGBAProtocol>*)normalSprite selectedSprite:(CCNode<CCRGBAProtocol>*)selectedSprite disabledSprite:(CCNode<CCRGBAProtocol>*)disabledSprite block:(void(^)(id sender))block { | ||
477 | block_ = [block copy]; | ||
478 | return [self initFromNormalSprite:normalSprite selectedSprite:selectedSprite disabledSprite:disabledSprite target:block_ selector:@selector(ccCallbackBlockWithSender:)]; | ||
479 | } | ||
480 | #endif // NS_BLOCKS_AVAILABLE | ||
481 | |||
482 | |||
483 | -(void) setNormalImage:(CCNode <CCRGBAProtocol>*)image | ||
484 | { | ||
485 | if( image != normalImage_ ) { | ||
486 | image.anchorPoint = ccp(0,0); | ||
487 | image.visible = YES; | ||
488 | |||
489 | [self removeChild:normalImage_ cleanup:YES]; | ||
490 | [self addChild:image]; | ||
491 | |||
492 | normalImage_ = image; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | -(void) setSelectedImage:(CCNode <CCRGBAProtocol>*)image | ||
497 | { | ||
498 | if( image != selectedImage_ ) { | ||
499 | image.anchorPoint = ccp(0,0); | ||
500 | image.visible = NO; | ||
501 | |||
502 | [self removeChild:selectedImage_ cleanup:YES]; | ||
503 | [self addChild:image]; | ||
504 | |||
505 | selectedImage_ = image; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | -(void) setDisabledImage:(CCNode <CCRGBAProtocol>*)image | ||
510 | { | ||
511 | if( image != disabledImage_ ) { | ||
512 | image.anchorPoint = ccp(0,0); | ||
513 | image.visible = NO; | ||
514 | |||
515 | [self removeChild:disabledImage_ cleanup:YES]; | ||
516 | [self addChild:image]; | ||
517 | |||
518 | disabledImage_ = image; | ||
519 | } | ||
520 | } | ||
521 | |||
522 | #pragma mark CCMenuItemImage - CCRGBAProtocol protocol | ||
523 | - (void) setOpacity: (GLubyte)opacity | ||
524 | { | ||
525 | [normalImage_ setOpacity:opacity]; | ||
526 | [selectedImage_ setOpacity:opacity]; | ||
527 | [disabledImage_ setOpacity:opacity]; | ||
528 | } | ||
529 | |||
530 | -(void) setColor:(ccColor3B)color | ||
531 | { | ||
532 | [normalImage_ setColor:color]; | ||
533 | [selectedImage_ setColor:color]; | ||
534 | [disabledImage_ setColor:color]; | ||
535 | } | ||
536 | |||
537 | -(GLubyte) opacity | ||
538 | { | ||
539 | return [normalImage_ opacity]; | ||
540 | } | ||
541 | |||
542 | -(ccColor3B) color | ||
543 | { | ||
544 | return [normalImage_ color]; | ||
545 | } | ||
546 | |||
547 | -(void) selected | ||
548 | { | ||
549 | [super selected]; | ||
550 | |||
551 | if( selectedImage_ ) { | ||
552 | [normalImage_ setVisible:NO]; | ||
553 | [selectedImage_ setVisible:YES]; | ||
554 | [disabledImage_ setVisible:NO]; | ||
555 | |||
556 | } else { // there is not selected image | ||
557 | |||
558 | [normalImage_ setVisible:YES]; | ||
559 | [selectedImage_ setVisible:NO]; | ||
560 | [disabledImage_ setVisible:NO]; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | -(void) unselected | ||
565 | { | ||
566 | [super unselected]; | ||
567 | [normalImage_ setVisible:YES]; | ||
568 | [selectedImage_ setVisible:NO]; | ||
569 | [disabledImage_ setVisible:NO]; | ||
570 | } | ||
571 | |||
572 | -(void) setIsEnabled:(BOOL)enabled | ||
573 | { | ||
574 | [super setIsEnabled:enabled]; | ||
575 | |||
576 | if( enabled ) { | ||
577 | [normalImage_ setVisible:YES]; | ||
578 | [selectedImage_ setVisible:NO]; | ||
579 | [disabledImage_ setVisible:NO]; | ||
580 | |||
581 | } else { | ||
582 | if( disabledImage_ ) { | ||
583 | [normalImage_ setVisible:NO]; | ||
584 | [selectedImage_ setVisible:NO]; | ||
585 | [disabledImage_ setVisible:YES]; | ||
586 | } else { | ||
587 | [normalImage_ setVisible:YES]; | ||
588 | [selectedImage_ setVisible:NO]; | ||
589 | [disabledImage_ setVisible:NO]; | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | |||
594 | @end | ||
595 | |||
596 | #pragma mark - | ||
597 | #pragma mark CCMenuItemImage | ||
598 | |||
599 | @implementation CCMenuItemImage | ||
600 | |||
601 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2 | ||
602 | { | ||
603 | return [self itemFromNormalImage:value selectedImage:value2 disabledImage: nil target:nil selector:nil]; | ||
604 | } | ||
605 | |||
606 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2 target:(id) t selector:(SEL) s | ||
607 | { | ||
608 | return [self itemFromNormalImage:value selectedImage:value2 disabledImage: nil target:t selector:s]; | ||
609 | } | ||
610 | |||
611 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2 disabledImage: (NSString*) value3 | ||
612 | { | ||
613 | return [[[self alloc] initFromNormalImage:value selectedImage:value2 disabledImage:value3 target:nil selector:nil] autorelease]; | ||
614 | } | ||
615 | |||
616 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2 disabledImage: (NSString*) value3 target:(id) t selector:(SEL) s | ||
617 | { | ||
618 | return [[[self alloc] initFromNormalImage:value selectedImage:value2 disabledImage:value3 target:t selector:s] autorelease]; | ||
619 | } | ||
620 | |||
621 | -(id) initFromNormalImage: (NSString*) normalI selectedImage:(NSString*)selectedI disabledImage: (NSString*) disabledI target:(id)t selector:(SEL)sel | ||
622 | { | ||
623 | CCNode<CCRGBAProtocol> *normalImage = [CCSprite spriteWithFile:normalI]; | ||
624 | CCNode<CCRGBAProtocol> *selectedImage = nil; | ||
625 | CCNode<CCRGBAProtocol> *disabledImage = nil; | ||
626 | |||
627 | if( selectedI ) | ||
628 | selectedImage = [CCSprite spriteWithFile:selectedI]; | ||
629 | if(disabledI) | ||
630 | disabledImage = [CCSprite spriteWithFile:disabledI]; | ||
631 | |||
632 | return [self initFromNormalSprite:normalImage selectedSprite:selectedImage disabledSprite:disabledImage target:t selector:sel]; | ||
633 | } | ||
634 | |||
635 | #if NS_BLOCKS_AVAILABLE | ||
636 | |||
637 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2 block:(void(^)(id sender))block { | ||
638 | return [self itemFromNormalImage:value selectedImage:value2 disabledImage:nil block:block]; | ||
639 | } | ||
640 | |||
641 | +(id) itemFromNormalImage: (NSString*)value selectedImage:(NSString*) value2 disabledImage:(NSString*) value3 block:(void(^)(id sender))block { | ||
642 | return [[[self alloc] initFromNormalImage:value selectedImage:value2 disabledImage:value3 block:block] autorelease]; | ||
643 | } | ||
644 | |||
645 | -(id) initFromNormalImage: (NSString*) value selectedImage:(NSString*)value2 disabledImage:(NSString*) value3 block:(void(^)(id sender))block { | ||
646 | block_ = [block copy]; | ||
647 | return [self initFromNormalImage:value selectedImage:value2 disabledImage:value3 target:block_ selector:@selector(ccCallbackBlockWithSender:)]; | ||
648 | } | ||
649 | |||
650 | #endif // NS_BLOCKS_AVAILABLE | ||
651 | |||
652 | @end | ||
653 | |||
654 | #pragma mark - | ||
655 | #pragma mark CCMenuItemToggle | ||
656 | |||
657 | // | ||
658 | // MenuItemToggle | ||
659 | // | ||
660 | @implementation CCMenuItemToggle | ||
661 | |||
662 | @synthesize subItems = subItems_; | ||
663 | @synthesize opacity = opacity_, color = color_; | ||
664 | |||
665 | +(id) itemWithTarget: (id)t selector: (SEL)sel items: (CCMenuItem*) item, ... | ||
666 | { | ||
667 | va_list args; | ||
668 | va_start(args, item); | ||
669 | |||
670 | id s = [[[self alloc] initWithTarget: t selector:sel items: item vaList:args] autorelease]; | ||
671 | |||
672 | va_end(args); | ||
673 | return s; | ||
674 | } | ||
675 | |||
676 | -(id) initWithTarget: (id)t selector: (SEL)sel items:(CCMenuItem*) item vaList: (va_list) args | ||
677 | { | ||
678 | if( (self=[super initWithTarget:t selector:sel]) ) { | ||
679 | |||
680 | self.subItems = [NSMutableArray arrayWithCapacity:2]; | ||
681 | |||
682 | int z = 0; | ||
683 | CCMenuItem *i = item; | ||
684 | while(i) { | ||
685 | z++; | ||
686 | [subItems_ addObject:i]; | ||
687 | i = va_arg(args, CCMenuItem*); | ||
688 | } | ||
689 | |||
690 | selectedIndex_ = NSUIntegerMax; | ||
691 | [self setSelectedIndex:0]; | ||
692 | } | ||
693 | |||
694 | return self; | ||
695 | } | ||
696 | |||
697 | #if NS_BLOCKS_AVAILABLE | ||
698 | |||
699 | +(id) itemWithBlock:(void(^)(id sender))block items:(CCMenuItem*)item, ... { | ||
700 | va_list args; | ||
701 | va_start(args, item); | ||
702 | |||
703 | id s = [[[self alloc] initWithBlock:block items:item vaList:args] autorelease]; | ||
704 | |||
705 | va_end(args); | ||
706 | return s; | ||
707 | } | ||
708 | |||
709 | -(id) initWithBlock:(void (^)(id))block items:(CCMenuItem*)item vaList:(va_list)args { | ||
710 | block_ = [block copy]; | ||
711 | return [self initWithTarget:block_ selector:@selector(ccCallbackBlockWithSender:) items:item vaList:args]; | ||
712 | } | ||
713 | |||
714 | #endif // NS_BLOCKS_AVAILABLE | ||
715 | |||
716 | -(void) dealloc | ||
717 | { | ||
718 | [subItems_ release]; | ||
719 | [super dealloc]; | ||
720 | } | ||
721 | |||
722 | -(void)setSelectedIndex:(NSUInteger)index | ||
723 | { | ||
724 | if( index != selectedIndex_ ) { | ||
725 | selectedIndex_=index; | ||
726 | [self removeChildByTag:kCurrentItem cleanup:NO]; | ||
727 | |||
728 | CCMenuItem *item = [subItems_ objectAtIndex:selectedIndex_]; | ||
729 | [self addChild:item z:0 tag:kCurrentItem]; | ||
730 | |||
731 | CGSize s = [item contentSize]; | ||
732 | [self setContentSize: s]; | ||
733 | item.position = ccp( s.width/2, s.height/2 ); | ||
734 | } | ||
735 | } | ||
736 | |||
737 | -(NSUInteger) selectedIndex | ||
738 | { | ||
739 | return selectedIndex_; | ||
740 | } | ||
741 | |||
742 | |||
743 | -(void) selected | ||
744 | { | ||
745 | [super selected]; | ||
746 | [[subItems_ objectAtIndex:selectedIndex_] selected]; | ||
747 | } | ||
748 | |||
749 | -(void) unselected | ||
750 | { | ||
751 | [super unselected]; | ||
752 | [[subItems_ objectAtIndex:selectedIndex_] unselected]; | ||
753 | } | ||
754 | |||
755 | -(void) activate | ||
756 | { | ||
757 | // update index | ||
758 | if( isEnabled_ ) { | ||
759 | NSUInteger newIndex = (selectedIndex_ + 1) % [subItems_ count]; | ||
760 | [self setSelectedIndex:newIndex]; | ||
761 | |||
762 | } | ||
763 | |||
764 | [super activate]; | ||
765 | } | ||
766 | |||
767 | -(void) setIsEnabled: (BOOL)enabled | ||
768 | { | ||
769 | [super setIsEnabled:enabled]; | ||
770 | for(CCMenuItem* item in subItems_) | ||
771 | [item setIsEnabled:enabled]; | ||
772 | } | ||
773 | |||
774 | -(CCMenuItem*) selectedItem | ||
775 | { | ||
776 | return [subItems_ objectAtIndex:selectedIndex_]; | ||
777 | } | ||
778 | |||
779 | #pragma mark CCMenuItemToggle - CCRGBAProtocol protocol | ||
780 | |||
781 | - (void) setOpacity: (GLubyte)opacity | ||
782 | { | ||
783 | opacity_ = opacity; | ||
784 | for(CCMenuItem<CCRGBAProtocol>* item in subItems_) | ||
785 | [item setOpacity:opacity]; | ||
786 | } | ||
787 | |||
788 | - (void) setColor:(ccColor3B)color | ||
789 | { | ||
790 | color_ = color; | ||
791 | for(CCMenuItem<CCRGBAProtocol>* item in subItems_) | ||
792 | [item setColor:color]; | ||
793 | } | ||
794 | |||
795 | @end | ||
diff --git a/libs/cocos2d/CCMotionStreak.h b/libs/cocos2d/CCMotionStreak.h new file mode 100755 index 0000000..e017124 --- /dev/null +++ b/libs/cocos2d/CCMotionStreak.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008, 2009 Jason Booth | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import <Foundation/Foundation.h> | ||
27 | #import "CCNode.h" | ||
28 | #import "CCRibbon.h" | ||
29 | |||
30 | /** | ||
31 | * CCMotionStreak manages a Ribbon based on it's motion in absolute space. | ||
32 | * You construct it with a fadeTime, minimum segment size, texture path, texture | ||
33 | * length and color. The fadeTime controls how long it takes each vertex in | ||
34 | * the streak to fade out, the minimum segment size it how many pixels the | ||
35 | * streak will move before adding a new ribbon segement, and the texture | ||
36 | * length is the how many pixels the texture is stretched across. The texture | ||
37 | * is vertically aligned along the streak segemnts. | ||
38 | * | ||
39 | * Limitations: | ||
40 | * CCMotionStreak, by default, will use the GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA blending function. | ||
41 | * This blending function might not be the correct one for certain textures. | ||
42 | * But you can change it by using: | ||
43 | * [obj setBlendFunc: (ccBlendfunc) {new_src_blend_func, new_dst_blend_func}]; | ||
44 | * | ||
45 | * @since v0.8.1 | ||
46 | */ | ||
47 | @interface CCMotionStreak : CCNode <CCTextureProtocol> | ||
48 | { | ||
49 | CCRibbon* ribbon_; | ||
50 | float segThreshold_; | ||
51 | float width_; | ||
52 | CGPoint lastLocation_; | ||
53 | } | ||
54 | |||
55 | /** Ribbon used by MotionStreak (weak reference) */ | ||
56 | @property (nonatomic,readonly) CCRibbon *ribbon; | ||
57 | |||
58 | /** creates the a MotionStreak. The image will be loaded using the TextureMgr. */ | ||
59 | +(id)streakWithFade:(float)fade minSeg:(float)seg image:(NSString*)path width:(float)width length:(float)length color:(ccColor4B)color; | ||
60 | |||
61 | /** initializes a MotionStreak. The file will be loaded using the TextureMgr. */ | ||
62 | -(id)initWithFade:(float)fade minSeg:(float)seg image:(NSString*)path width:(float)width length:(float)length color:(ccColor4B)color; | ||
63 | |||
64 | /** polling function */ | ||
65 | -(void)update:(ccTime)delta; | ||
66 | |||
67 | @end | ||
diff --git a/libs/cocos2d/CCMotionStreak.m b/libs/cocos2d/CCMotionStreak.m new file mode 100755 index 0000000..42737b9 --- /dev/null +++ b/libs/cocos2d/CCMotionStreak.m | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008, 2009 Jason Booth | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | * | ||
25 | ********************************************************* | ||
26 | * | ||
27 | * Motion Streak manages a Ribbon based on it's motion in absolute space. | ||
28 | * You construct it with a fadeTime, minimum segment size, texture path, texture | ||
29 | * length and color. The fadeTime controls how long it takes each vertex in | ||
30 | * the streak to fade out, the minimum segment size it how many pixels the | ||
31 | * streak will move before adding a new ribbon segement, and the texture | ||
32 | * length is the how many pixels the texture is stretched across. The texture | ||
33 | * is vertically aligned along the streak segemnts. | ||
34 | */ | ||
35 | |||
36 | #import "CCMotionStreak.h" | ||
37 | #import "Support/CGPointExtension.h" | ||
38 | |||
39 | @implementation CCMotionStreak | ||
40 | |||
41 | @synthesize ribbon = ribbon_; | ||
42 | |||
43 | +(id)streakWithFade:(float)fade minSeg:(float)seg image:(NSString*)path width:(float)width length:(float)length color:(ccColor4B)color | ||
44 | { | ||
45 | return [[[self alloc] initWithFade:(float)fade minSeg:seg image:path width:width length:length color:color] autorelease]; | ||
46 | } | ||
47 | |||
48 | -(id)initWithFade:(float)fade minSeg:(float)seg image:(NSString*)path width:(float)width length:(float)length color:(ccColor4B)color | ||
49 | { | ||
50 | if( (self=[super init])) { | ||
51 | segThreshold_ = seg; | ||
52 | width_ = width; | ||
53 | lastLocation_ = CGPointZero; | ||
54 | ribbon_ = [CCRibbon ribbonWithWidth:width_ image:path length:length color:color fade:fade]; | ||
55 | [self addChild:ribbon_]; | ||
56 | |||
57 | // update ribbon position. Use schedule:interval and not scheduleUpdated. issue #1075 | ||
58 | [self schedule:@selector(update:) interval:0]; | ||
59 | } | ||
60 | return self; | ||
61 | } | ||
62 | |||
63 | -(void)update:(ccTime)delta | ||
64 | { | ||
65 | CGPoint location = [self convertToWorldSpace:CGPointZero]; | ||
66 | [ribbon_ setPosition:ccp(-1*location.x, -1*location.y)]; | ||
67 | float len = ccpLength(ccpSub(lastLocation_, location)); | ||
68 | if (len > segThreshold_) | ||
69 | { | ||
70 | [ribbon_ addPointAt:location width:width_]; | ||
71 | lastLocation_ = location; | ||
72 | } | ||
73 | [ribbon_ update:delta]; | ||
74 | } | ||
75 | |||
76 | |||
77 | -(void)dealloc | ||
78 | { | ||
79 | [super dealloc]; | ||
80 | } | ||
81 | |||
82 | #pragma mark MotionStreak - CocosNodeTexture protocol | ||
83 | |||
84 | -(void) setTexture:(CCTexture2D*) texture | ||
85 | { | ||
86 | [ribbon_ setTexture: texture]; | ||
87 | } | ||
88 | |||
89 | -(CCTexture2D*) texture | ||
90 | { | ||
91 | return [ribbon_ texture]; | ||
92 | } | ||
93 | |||
94 | -(ccBlendFunc) blendFunc | ||
95 | { | ||
96 | return [ribbon_ blendFunc]; | ||
97 | } | ||
98 | |||
99 | -(void) setBlendFunc:(ccBlendFunc)blendFunc | ||
100 | { | ||
101 | [ribbon_ setBlendFunc:blendFunc]; | ||
102 | } | ||
103 | |||
104 | @end | ||
diff --git a/libs/cocos2d/CCNode.h b/libs/cocos2d/CCNode.h new file mode 100755 index 0000000..64acdc5 --- /dev/null +++ b/libs/cocos2d/CCNode.h | |||
@@ -0,0 +1,529 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
7 | * Copyright (c) 2011 Zynga Inc. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #import <Availability.h> | ||
29 | |||
30 | #import "Platforms/CCGL.h" | ||
31 | #import "CCAction.h" | ||
32 | #import "ccTypes.h" | ||
33 | #import "CCTexture2D.h" | ||
34 | #import "CCProtocols.h" | ||
35 | #import "ccConfig.h" | ||
36 | #import "Support/CCArray.h" | ||
37 | |||
38 | enum { | ||
39 | kCCNodeTagInvalid = -1, | ||
40 | }; | ||
41 | |||
42 | @class CCCamera; | ||
43 | @class CCGridBase; | ||
44 | |||
45 | /** CCNode is the main element. Anything thats gets drawn or contains things that get drawn is a CCNode. | ||
46 | The most popular CCNodes are: CCScene, CCLayer, CCSprite, CCMenu. | ||
47 | |||
48 | The main features of a CCNode are: | ||
49 | - They can contain other CCNode nodes (addChild, getChildByTag, removeChild, etc) | ||
50 | - They can schedule periodic callback (schedule, unschedule, etc) | ||
51 | - They can execute actions (runAction, stopAction, etc) | ||
52 | |||
53 | Some CCNode nodes provide extra functionality for them or their children. | ||
54 | |||
55 | Subclassing a CCNode usually means (one/all) of: | ||
56 | - overriding init to initialize resources and schedule callbacks | ||
57 | - create callbacks to handle the advancement of time | ||
58 | - overriding draw to render the node | ||
59 | |||
60 | Features of CCNode: | ||
61 | - position | ||
62 | - scale (x, y) | ||
63 | - rotation (in degrees, clockwise) | ||
64 | - CCCamera (an interface to gluLookAt ) | ||
65 | - CCGridBase (to do mesh transformations) | ||
66 | - anchor point | ||
67 | - size | ||
68 | - visible | ||
69 | - z-order | ||
70 | - openGL z position | ||
71 | |||
72 | Default values: | ||
73 | - rotation: 0 | ||
74 | - position: (x=0,y=0) | ||
75 | - scale: (x=1,y=1) | ||
76 | - contentSize: (x=0,y=0) | ||
77 | - anchorPoint: (x=0,y=0) | ||
78 | |||
79 | Limitations: | ||
80 | - A CCNode is a "void" object. It doesn't have a texture | ||
81 | |||
82 | Order in transformations with grid disabled | ||
83 | -# The node will be translated (position) | ||
84 | -# The node will be rotated (rotation) | ||
85 | -# The node will be scaled (scale) | ||
86 | -# The node will be moved according to the camera values (camera) | ||
87 | |||
88 | Order in transformations with grid enabled | ||
89 | -# The node will be translated (position) | ||
90 | -# The node will be rotated (rotation) | ||
91 | -# The node will be scaled (scale) | ||
92 | -# The grid will capture the screen | ||
93 | -# The node will be moved according to the camera values (camera) | ||
94 | -# The grid will render the captured screen | ||
95 | |||
96 | Camera: | ||
97 | - Each node has a camera. By default it points to the center of the CCNode. | ||
98 | */ | ||
99 | @interface CCNode : NSObject | ||
100 | { | ||
101 | // rotation angle | ||
102 | float rotation_; | ||
103 | |||
104 | // scaling factors | ||
105 | float scaleX_, scaleY_; | ||
106 | |||
107 | // position of the node | ||
108 | CGPoint position_; | ||
109 | CGPoint positionInPixels_; | ||
110 | |||
111 | // skew angles | ||
112 | float skewX_, skewY_; | ||
113 | |||
114 | // is visible | ||
115 | BOOL visible_; | ||
116 | |||
117 | // anchor point in pixels | ||
118 | CGPoint anchorPointInPixels_; | ||
119 | // anchor point normalized | ||
120 | CGPoint anchorPoint_; | ||
121 | // If YES the transformtions will be relative to (-transform.x, -transform.y). | ||
122 | // Sprites, Labels and any other "small" object uses it. | ||
123 | // Scenes, Layers and other "whole screen" object don't use it. | ||
124 | BOOL isRelativeAnchorPoint_; | ||
125 | |||
126 | // untransformed size of the node | ||
127 | CGSize contentSize_; | ||
128 | CGSize contentSizeInPixels_; | ||
129 | |||
130 | // transform | ||
131 | CGAffineTransform transform_, inverse_; | ||
132 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
133 | GLfloat transformGL_[16]; | ||
134 | #endif | ||
135 | |||
136 | // openGL real Z vertex | ||
137 | float vertexZ_; | ||
138 | |||
139 | // a Camera | ||
140 | CCCamera *camera_; | ||
141 | |||
142 | // a Grid | ||
143 | CCGridBase *grid_; | ||
144 | |||
145 | // z-order value | ||
146 | NSInteger zOrder_; | ||
147 | |||
148 | // array of children | ||
149 | CCArray *children_; | ||
150 | |||
151 | // weakref to parent | ||
152 | CCNode *parent_; | ||
153 | |||
154 | // a tag. any number you want to assign to the node | ||
155 | NSInteger tag_; | ||
156 | |||
157 | // user data field | ||
158 | void *userData_; | ||
159 | |||
160 | // Is running | ||
161 | BOOL isRunning_; | ||
162 | |||
163 | // To reduce memory, place BOOLs that are not properties here: | ||
164 | BOOL isTransformDirty_:1; | ||
165 | BOOL isInverseDirty_:1; | ||
166 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
167 | BOOL isTransformGLDirty_:1; | ||
168 | #endif | ||
169 | } | ||
170 | |||
171 | /** The z order of the node relative to it's "brothers": children of the same parent */ | ||
172 | @property(nonatomic,readonly) NSInteger zOrder; | ||
173 | /** The real openGL Z vertex. | ||
174 | Differences between openGL Z vertex and cocos2d Z order: | ||
175 | - OpenGL Z modifies the Z vertex, and not the Z order in the relation between parent-children | ||
176 | - OpenGL Z might require to set 2D projection | ||
177 | - cocos2d Z order works OK if all the nodes uses the same openGL Z vertex. eg: vertexZ = 0 | ||
178 | @warning: Use it at your own risk since it might break the cocos2d parent-children z order | ||
179 | @since v0.8 | ||
180 | */ | ||
181 | @property (nonatomic,readwrite) float vertexZ; | ||
182 | |||
183 | /** The X skew angle of the node in degrees. | ||
184 | This angle describes the shear distortion in the X direction. | ||
185 | Thus, it is the angle between the Y axis and the left edge of the shape | ||
186 | The default skewX angle is 0. Positive values distort the node in a CW direction. | ||
187 | */ | ||
188 | @property(nonatomic,readwrite,assign) float skewX; | ||
189 | |||
190 | /** The Y skew angle of the node in degrees. | ||
191 | This angle describes the shear distortion in the Y direction. | ||
192 | Thus, it is the angle between the X axis and the bottom edge of the shape | ||
193 | The default skewY angle is 0. Positive values distort the node in a CCW direction. | ||
194 | */ | ||
195 | @property(nonatomic,readwrite,assign) float skewY; | ||
196 | /** The rotation (angle) of the node in degrees. 0 is the default rotation angle. Positive values rotate node CW. */ | ||
197 | @property(nonatomic,readwrite,assign) float rotation; | ||
198 | /** The scale factor of the node. 1.0 is the default scale factor. It modifies the X and Y scale at the same time. */ | ||
199 | @property(nonatomic,readwrite,assign) float scale; | ||
200 | /** The scale factor of the node. 1.0 is the default scale factor. It only modifies the X scale factor. */ | ||
201 | @property(nonatomic,readwrite,assign) float scaleX; | ||
202 | /** The scale factor of the node. 1.0 is the default scale factor. It only modifies the Y scale factor. */ | ||
203 | @property(nonatomic,readwrite,assign) float scaleY; | ||
204 | /** Position (x,y) of the node in points. (0,0) is the left-bottom corner. */ | ||
205 | @property(nonatomic,readwrite,assign) CGPoint position; | ||
206 | /** Position (x,y) of the node in points. (0,0) is the left-bottom corner. */ | ||
207 | @property(nonatomic,readwrite,assign) CGPoint positionInPixels; | ||
208 | /** A CCCamera object that lets you move the node using a gluLookAt | ||
209 | */ | ||
210 | @property(nonatomic,readonly) CCCamera* camera; | ||
211 | /** Array of children */ | ||
212 | @property(nonatomic,readonly) CCArray *children; | ||
213 | /** A CCGrid object that is used when applying effects */ | ||
214 | @property(nonatomic,readwrite,retain) CCGridBase* grid; | ||
215 | /** Whether of not the node is visible. Default is YES */ | ||
216 | @property(nonatomic,readwrite,assign) BOOL visible; | ||
217 | /** anchorPoint is the point around which all transformations and positioning manipulations take place. | ||
218 | It's like a pin in the node where it is "attached" to its parent. | ||
219 | The anchorPoint is normalized, like a percentage. (0,0) means the bottom-left corner and (1,1) means the top-right corner. | ||
220 | But you can use values higher than (1,1) and lower than (0,0) too. | ||
221 | The default anchorPoint is (0,0). It starts in the bottom-left corner. CCSprite and other subclasses have a different default anchorPoint. | ||
222 | @since v0.8 | ||
223 | */ | ||
224 | @property(nonatomic,readwrite) CGPoint anchorPoint; | ||
225 | /** The anchorPoint in absolute pixels. | ||
226 | Since v0.8 you can only read it. If you wish to modify it, use anchorPoint instead | ||
227 | */ | ||
228 | @property(nonatomic,readonly) CGPoint anchorPointInPixels; | ||
229 | |||
230 | /** The untransformed size of the node in Points | ||
231 | The contentSize remains the same no matter the node is scaled or rotated. | ||
232 | All nodes has a size. Layer and Scene has the same size of the screen. | ||
233 | @since v0.8 | ||
234 | */ | ||
235 | @property (nonatomic,readwrite) CGSize contentSize; | ||
236 | |||
237 | /** The untransformed size of the node in Pixels | ||
238 | The contentSize remains the same no matter the node is scaled or rotated. | ||
239 | All nodes has a size. Layer and Scene has the same size of the screen. | ||
240 | @since v0.8 | ||
241 | */ | ||
242 | @property (nonatomic,readwrite) CGSize contentSizeInPixels; | ||
243 | |||
244 | /** whether or not the node is running */ | ||
245 | @property(nonatomic,readonly) BOOL isRunning; | ||
246 | /** A weak reference to the parent */ | ||
247 | @property(nonatomic,readwrite,assign) CCNode* parent; | ||
248 | /** If YES the transformtions will be relative to it's anchor point. | ||
249 | * Sprites, Labels and any other sizeble object use it have it enabled by default. | ||
250 | * Scenes, Layers and other "whole screen" object don't use it, have it disabled by default. | ||
251 | */ | ||
252 | @property(nonatomic,readwrite,assign) BOOL isRelativeAnchorPoint; | ||
253 | /** A tag used to identify the node easily */ | ||
254 | @property(nonatomic,readwrite,assign) NSInteger tag; | ||
255 | /** A custom user data pointer */ | ||
256 | @property(nonatomic,readwrite,assign) void *userData; | ||
257 | |||
258 | // initializators | ||
259 | /** allocates and initializes a node. | ||
260 | The node will be created as "autorelease". | ||
261 | */ | ||
262 | +(id) node; | ||
263 | /** initializes the node */ | ||
264 | -(id) init; | ||
265 | |||
266 | |||
267 | // scene managment | ||
268 | |||
269 | /** callback that is called every time the CCNode enters the 'stage'. | ||
270 | If the CCNode enters the 'stage' with a transition, this callback is called when the transition starts. | ||
271 | During onEnter you can't a "sister/brother" node. | ||
272 | */ | ||
273 | -(void) onEnter; | ||
274 | /** callback that is called when the CCNode enters in the 'stage'. | ||
275 | If the CCNode enters the 'stage' with a transition, this callback is called when the transition finishes. | ||
276 | @since v0.8 | ||
277 | */ | ||
278 | -(void) onEnterTransitionDidFinish; | ||
279 | /** callback that is called every time the CCNode leaves the 'stage'. | ||
280 | If the CCNode leaves the 'stage' with a transition, this callback is called when the transition finishes. | ||
281 | During onExit you can't access a sibling node. | ||
282 | */ | ||
283 | -(void) onExit; | ||
284 | |||
285 | |||
286 | // composition: ADD | ||
287 | |||
288 | /** Adds a child to the container with z-order as 0. | ||
289 | If the child is added to a 'running' node, then 'onEnter' and 'onEnterTransitionDidFinish' will be called immediately. | ||
290 | @since v0.7.1 | ||
291 | */ | ||
292 | -(void) addChild: (CCNode*)node; | ||
293 | |||
294 | /** Adds a child to the container with a z-order. | ||
295 | If the child is added to a 'running' node, then 'onEnter' and 'onEnterTransitionDidFinish' will be called immediately. | ||
296 | @since v0.7.1 | ||
297 | */ | ||
298 | -(void) addChild: (CCNode*)node z:(NSInteger)z; | ||
299 | |||
300 | /** Adds a child to the container with z order and tag. | ||
301 | If the child is added to a 'running' node, then 'onEnter' and 'onEnterTransitionDidFinish' will be called immediately. | ||
302 | @since v0.7.1 | ||
303 | */ | ||
304 | -(void) addChild: (CCNode*)node z:(NSInteger)z tag:(NSInteger)tag; | ||
305 | |||
306 | // composition: REMOVE | ||
307 | |||
308 | /** Remove itself from its parent node. If cleanup is YES, then also remove all actions and callbacks. | ||
309 | If the node orphan, then nothing happens. | ||
310 | @since v0.99.3 | ||
311 | */ | ||
312 | -(void) removeFromParentAndCleanup:(BOOL)cleanup; | ||
313 | |||
314 | /** Removes a child from the container. It will also cleanup all running actions depending on the cleanup parameter. | ||
315 | @since v0.7.1 | ||
316 | */ | ||
317 | -(void) removeChild: (CCNode*)node cleanup:(BOOL)cleanup; | ||
318 | |||
319 | /** Removes a child from the container by tag value. It will also cleanup all running actions depending on the cleanup parameter | ||
320 | @since v0.7.1 | ||
321 | */ | ||
322 | -(void) removeChildByTag:(NSInteger) tag cleanup:(BOOL)cleanup; | ||
323 | |||
324 | /** Removes all children from the container and do a cleanup all running actions depending on the cleanup parameter. | ||
325 | @since v0.7.1 | ||
326 | */ | ||
327 | -(void) removeAllChildrenWithCleanup:(BOOL)cleanup; | ||
328 | |||
329 | // composition: GET | ||
330 | /** Gets a child from the container given its tag | ||
331 | @return returns a CCNode object | ||
332 | @since v0.7.1 | ||
333 | */ | ||
334 | -(CCNode*) getChildByTag:(NSInteger) tag; | ||
335 | |||
336 | /** Reorders a child according to a new z value. | ||
337 | * The child MUST be already added. | ||
338 | */ | ||
339 | -(void) reorderChild:(CCNode*)child z:(NSInteger)zOrder; | ||
340 | |||
341 | /** Stops all running actions and schedulers | ||
342 | @since v0.8 | ||
343 | */ | ||
344 | -(void) cleanup; | ||
345 | |||
346 | // draw | ||
347 | |||
348 | /** Override this method to draw your own node. | ||
349 | The following GL states will be enabled by default: | ||
350 | - glEnableClientState(GL_VERTEX_ARRAY); | ||
351 | - glEnableClientState(GL_COLOR_ARRAY); | ||
352 | - glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
353 | - glEnable(GL_TEXTURE_2D); | ||
354 | |||
355 | AND YOU SHOULD NOT DISABLE THEM AFTER DRAWING YOUR NODE | ||
356 | |||
357 | But if you enable any other GL state, you should disable it after drawing your node. | ||
358 | */ | ||
359 | -(void) draw; | ||
360 | /** recursive method that visit its children and draw them */ | ||
361 | -(void) visit; | ||
362 | |||
363 | // transformations | ||
364 | |||
365 | /** performs OpenGL view-matrix transformation based on position, scale, rotation and other attributes. */ | ||
366 | -(void) transform; | ||
367 | |||
368 | /** performs OpenGL view-matrix transformation of it's ancestors. | ||
369 | Generally the ancestors are already transformed, but in certain cases (eg: attaching a FBO) | ||
370 | it's necessary to transform the ancestors again. | ||
371 | @since v0.7.2 | ||
372 | */ | ||
373 | -(void) transformAncestors; | ||
374 | |||
375 | /** returns a "local" axis aligned bounding box of the node in points. | ||
376 | The returned box is relative only to its parent. | ||
377 | The returned box is in Points. | ||
378 | |||
379 | @since v0.8.2 | ||
380 | */ | ||
381 | - (CGRect) boundingBox; | ||
382 | |||
383 | /** returns a "local" axis aligned bounding box of the node in pixels. | ||
384 | The returned box is relative only to its parent. | ||
385 | The returned box is in Points. | ||
386 | |||
387 | @since v0.99.5 | ||
388 | */ | ||
389 | - (CGRect) boundingBoxInPixels; | ||
390 | |||
391 | |||
392 | // actions | ||
393 | |||
394 | /** Executes an action, and returns the action that is executed. | ||
395 | The node becomes the action's target. | ||
396 | @warning Starting from v0.8 actions don't retain their target anymore. | ||
397 | @since v0.7.1 | ||
398 | @return An Action pointer | ||
399 | */ | ||
400 | -(CCAction*) runAction: (CCAction*) action; | ||
401 | /** Removes all actions from the running action list */ | ||
402 | -(void) stopAllActions; | ||
403 | /** Removes an action from the running action list */ | ||
404 | -(void) stopAction: (CCAction*) action; | ||
405 | /** Removes an action from the running action list given its tag | ||
406 | @since v0.7.1 | ||
407 | */ | ||
408 | -(void) stopActionByTag:(NSInteger) tag; | ||
409 | /** Gets an action from the running action list given its tag | ||
410 | @since v0.7.1 | ||
411 | @return the Action the with the given tag | ||
412 | */ | ||
413 | -(CCAction*) getActionByTag:(NSInteger) tag; | ||
414 | /** Returns the numbers of actions that are running plus the ones that are schedule to run (actions in actionsToAdd and actions arrays). | ||
415 | * Composable actions are counted as 1 action. Example: | ||
416 | * If you are running 1 Sequence of 7 actions, it will return 1. | ||
417 | * If you are running 7 Sequences of 2 actions, it will return 7. | ||
418 | */ | ||
419 | -(NSUInteger) numberOfRunningActions; | ||
420 | |||
421 | // timers | ||
422 | |||
423 | /** check whether a selector is scheduled. */ | ||
424 | //-(BOOL) isScheduled: (SEL) selector; | ||
425 | |||
426 | /** schedules the "update" method. It will use the order number 0. This method will be called every frame. | ||
427 | Scheduled methods with a lower order value will be called before the ones that have a higher order value. | ||
428 | Only one "udpate" method could be scheduled per node. | ||
429 | |||
430 | @since v0.99.3 | ||
431 | */ | ||
432 | -(void) scheduleUpdate; | ||
433 | |||
434 | /** schedules the "update" selector with a custom priority. This selector will be called every frame. | ||
435 | Scheduled selectors with a lower priority will be called before the ones that have a higher value. | ||
436 | Only one "udpate" selector could be scheduled per node (You can't have 2 'update' selectors). | ||
437 | |||
438 | @since v0.99.3 | ||
439 | */ | ||
440 | -(void) scheduleUpdateWithPriority:(NSInteger)priority; | ||
441 | |||
442 | /* unschedules the "update" method. | ||
443 | |||
444 | @since v0.99.3 | ||
445 | */ | ||
446 | -(void) unscheduleUpdate; | ||
447 | |||
448 | |||
449 | /** schedules a selector. | ||
450 | The scheduled selector will be ticked every frame | ||
451 | */ | ||
452 | -(void) schedule: (SEL) s; | ||
453 | /** schedules a custom selector with an interval time in seconds. | ||
454 | If time is 0 it will be ticked every frame. | ||
455 | If time is 0, it is recommended to use 'scheduleUpdate' instead. | ||
456 | |||
457 | If the selector is already scheduled, then the interval parameter will be updated without scheduling it again. | ||
458 | */ | ||
459 | -(void) schedule: (SEL) s interval:(ccTime)seconds; | ||
460 | /** unschedules a custom selector.*/ | ||
461 | -(void) unschedule: (SEL) s; | ||
462 | |||
463 | /** unschedule all scheduled selectors: custom selectors, and the 'update' selector. | ||
464 | Actions are not affected by this method. | ||
465 | @since v0.99.3 | ||
466 | */ | ||
467 | -(void) unscheduleAllSelectors; | ||
468 | |||
469 | /** resumes all scheduled selectors and actions. | ||
470 | Called internally by onEnter | ||
471 | */ | ||
472 | -(void) resumeSchedulerAndActions; | ||
473 | /** pauses all scheduled selectors and actions. | ||
474 | Called internally by onExit | ||
475 | */ | ||
476 | -(void) pauseSchedulerAndActions; | ||
477 | |||
478 | |||
479 | // transformation methods | ||
480 | |||
481 | /** Returns the matrix that transform the node's (local) space coordinates into the parent's space coordinates. | ||
482 | The matrix is in Pixels. | ||
483 | @since v0.7.1 | ||
484 | */ | ||
485 | - (CGAffineTransform)nodeToParentTransform; | ||
486 | /** Returns the matrix that transform parent's space coordinates to the node's (local) space coordinates. | ||
487 | The matrix is in Pixels. | ||
488 | @since v0.7.1 | ||
489 | */ | ||
490 | - (CGAffineTransform)parentToNodeTransform; | ||
491 | /** Retrusn the world affine transform matrix. The matrix is in Pixels. | ||
492 | @since v0.7.1 | ||
493 | */ | ||
494 | - (CGAffineTransform)nodeToWorldTransform; | ||
495 | /** Returns the inverse world affine transform matrix. The matrix is in Pixels. | ||
496 | @since v0.7.1 | ||
497 | */ | ||
498 | - (CGAffineTransform)worldToNodeTransform; | ||
499 | /** Converts a Point to node (local) space coordinates. The result is in Points. | ||
500 | @since v0.7.1 | ||
501 | */ | ||
502 | - (CGPoint)convertToNodeSpace:(CGPoint)worldPoint; | ||
503 | /** Converts a Point to world space coordinates. The result is in Points. | ||
504 | @since v0.7.1 | ||
505 | */ | ||
506 | - (CGPoint)convertToWorldSpace:(CGPoint)nodePoint; | ||
507 | /** Converts a Point to node (local) space coordinates. The result is in Points. | ||
508 | treating the returned/received node point as anchor relative. | ||
509 | @since v0.7.1 | ||
510 | */ | ||
511 | - (CGPoint)convertToNodeSpaceAR:(CGPoint)worldPoint; | ||
512 | /** Converts a local Point to world space coordinates.The result is in Points. | ||
513 | treating the returned/received node point as anchor relative. | ||
514 | @since v0.7.1 | ||
515 | */ | ||
516 | - (CGPoint)convertToWorldSpaceAR:(CGPoint)nodePoint; | ||
517 | |||
518 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
519 | /** Converts a UITouch to node (local) space coordinates. The result is in Points. | ||
520 | @since v0.7.1 | ||
521 | */ | ||
522 | - (CGPoint)convertTouchToNodeSpace:(UITouch *)touch; | ||
523 | /** Converts a UITouch to node (local) space coordinates. The result is in Points. | ||
524 | This method is AR (Anchor Relative).. | ||
525 | @since v0.7.1 | ||
526 | */ | ||
527 | - (CGPoint)convertTouchToNodeSpaceAR:(UITouch *)touch; | ||
528 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
529 | @end | ||
diff --git a/libs/cocos2d/CCNode.m b/libs/cocos2d/CCNode.m new file mode 100755 index 0000000..569cb22 --- /dev/null +++ b/libs/cocos2d/CCNode.m | |||
@@ -0,0 +1,921 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
7 | * Copyright (c) 2011 Zynga Inc. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | */ | ||
27 | |||
28 | #import "CCNode.h" | ||
29 | #import "CCGrid.h" | ||
30 | #import "CCDirector.h" | ||
31 | #import "CCActionManager.h" | ||
32 | #import "CCCamera.h" | ||
33 | #import "CCScheduler.h" | ||
34 | #import "ccConfig.h" | ||
35 | #import "ccMacros.h" | ||
36 | #import "Support/CGPointExtension.h" | ||
37 | #import "Support/ccCArray.h" | ||
38 | #import "Support/TransformUtils.h" | ||
39 | #import "ccMacros.h" | ||
40 | |||
41 | #import <Availability.h> | ||
42 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
43 | #import "Platforms/iOS/CCDirectorIOS.h" | ||
44 | #endif | ||
45 | |||
46 | |||
47 | #if CC_COCOSNODE_RENDER_SUBPIXEL | ||
48 | #define RENDER_IN_SUBPIXEL | ||
49 | #else | ||
50 | #define RENDER_IN_SUBPIXEL (NSInteger) | ||
51 | #endif | ||
52 | |||
53 | @interface CCNode () | ||
54 | // lazy allocs | ||
55 | -(void) childrenAlloc; | ||
56 | // helper that reorder a child | ||
57 | -(void) insertChild:(CCNode*)child z:(NSInteger)z; | ||
58 | // used internally to alter the zOrder variable. DON'T call this method manually | ||
59 | -(void) _setZOrder:(NSInteger) z; | ||
60 | -(void) detachChild:(CCNode *)child cleanup:(BOOL)doCleanup; | ||
61 | @end | ||
62 | |||
63 | @implementation CCNode | ||
64 | |||
65 | @synthesize children = children_; | ||
66 | @synthesize visible = visible_; | ||
67 | @synthesize parent = parent_; | ||
68 | @synthesize grid = grid_; | ||
69 | @synthesize zOrder = zOrder_; | ||
70 | @synthesize tag = tag_; | ||
71 | @synthesize vertexZ = vertexZ_; | ||
72 | @synthesize isRunning = isRunning_; | ||
73 | @synthesize userData = userData_; | ||
74 | |||
75 | #pragma mark CCNode - Transform related properties | ||
76 | |||
77 | @synthesize rotation = rotation_, scaleX = scaleX_, scaleY = scaleY_; | ||
78 | @synthesize skewX = skewX_, skewY = skewY_; | ||
79 | @synthesize position = position_, positionInPixels = positionInPixels_; | ||
80 | @synthesize anchorPoint = anchorPoint_, anchorPointInPixels = anchorPointInPixels_; | ||
81 | @synthesize contentSize = contentSize_, contentSizeInPixels = contentSizeInPixels_; | ||
82 | @synthesize isRelativeAnchorPoint = isRelativeAnchorPoint_; | ||
83 | |||
84 | // getters synthesized, setters explicit | ||
85 | |||
86 | -(void) setSkewX:(float)newSkewX | ||
87 | { | ||
88 | skewX_ = newSkewX; | ||
89 | isTransformDirty_ = isInverseDirty_ = YES; | ||
90 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
91 | isTransformGLDirty_ = YES; | ||
92 | #endif | ||
93 | } | ||
94 | |||
95 | -(void) setSkewY:(float)newSkewY | ||
96 | { | ||
97 | skewY_ = newSkewY; | ||
98 | isTransformDirty_ = isInverseDirty_ = YES; | ||
99 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
100 | isTransformGLDirty_ = YES; | ||
101 | #endif | ||
102 | } | ||
103 | |||
104 | -(void) setRotation: (float)newRotation | ||
105 | { | ||
106 | rotation_ = newRotation; | ||
107 | isTransformDirty_ = isInverseDirty_ = YES; | ||
108 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
109 | isTransformGLDirty_ = YES; | ||
110 | #endif | ||
111 | } | ||
112 | |||
113 | -(void) setScaleX: (float)newScaleX | ||
114 | { | ||
115 | scaleX_ = newScaleX; | ||
116 | isTransformDirty_ = isInverseDirty_ = YES; | ||
117 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
118 | isTransformGLDirty_ = YES; | ||
119 | #endif | ||
120 | } | ||
121 | |||
122 | -(void) setScaleY: (float)newScaleY | ||
123 | { | ||
124 | scaleY_ = newScaleY; | ||
125 | isTransformDirty_ = isInverseDirty_ = YES; | ||
126 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
127 | isTransformGLDirty_ = YES; | ||
128 | #endif | ||
129 | } | ||
130 | |||
131 | -(void) setPosition: (CGPoint)newPosition | ||
132 | { | ||
133 | position_ = newPosition; | ||
134 | if( CC_CONTENT_SCALE_FACTOR() == 1 ) | ||
135 | positionInPixels_ = position_; | ||
136 | else | ||
137 | positionInPixels_ = ccpMult( newPosition, CC_CONTENT_SCALE_FACTOR() ); | ||
138 | |||
139 | isTransformDirty_ = isInverseDirty_ = YES; | ||
140 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
141 | isTransformGLDirty_ = YES; | ||
142 | #endif | ||
143 | } | ||
144 | |||
145 | -(void) setPositionInPixels:(CGPoint)newPosition | ||
146 | { | ||
147 | positionInPixels_ = newPosition; | ||
148 | |||
149 | if( CC_CONTENT_SCALE_FACTOR() == 1 ) | ||
150 | position_ = positionInPixels_; | ||
151 | else | ||
152 | position_ = ccpMult( newPosition, 1/CC_CONTENT_SCALE_FACTOR() ); | ||
153 | |||
154 | isTransformDirty_ = isInverseDirty_ = YES; | ||
155 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
156 | isTransformGLDirty_ = YES; | ||
157 | #endif | ||
158 | } | ||
159 | |||
160 | -(void) setIsRelativeAnchorPoint: (BOOL)newValue | ||
161 | { | ||
162 | isRelativeAnchorPoint_ = newValue; | ||
163 | isTransformDirty_ = isInverseDirty_ = YES; | ||
164 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
165 | isTransformGLDirty_ = YES; | ||
166 | #endif | ||
167 | } | ||
168 | |||
169 | -(void) setAnchorPoint:(CGPoint)point | ||
170 | { | ||
171 | if( ! CGPointEqualToPoint(point, anchorPoint_) ) { | ||
172 | anchorPoint_ = point; | ||
173 | anchorPointInPixels_ = ccp( contentSizeInPixels_.width * anchorPoint_.x, contentSizeInPixels_.height * anchorPoint_.y ); | ||
174 | isTransformDirty_ = isInverseDirty_ = YES; | ||
175 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
176 | isTransformGLDirty_ = YES; | ||
177 | #endif | ||
178 | } | ||
179 | } | ||
180 | |||
181 | -(void) setContentSize:(CGSize)size | ||
182 | { | ||
183 | if( ! CGSizeEqualToSize(size, contentSize_) ) { | ||
184 | contentSize_ = size; | ||
185 | |||
186 | if( CC_CONTENT_SCALE_FACTOR() == 1 ) | ||
187 | contentSizeInPixels_ = contentSize_; | ||
188 | else | ||
189 | contentSizeInPixels_ = CGSizeMake( size.width * CC_CONTENT_SCALE_FACTOR(), size.height * CC_CONTENT_SCALE_FACTOR() ); | ||
190 | |||
191 | anchorPointInPixels_ = ccp( contentSizeInPixels_.width * anchorPoint_.x, contentSizeInPixels_.height * anchorPoint_.y ); | ||
192 | isTransformDirty_ = isInverseDirty_ = YES; | ||
193 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
194 | isTransformGLDirty_ = YES; | ||
195 | #endif | ||
196 | } | ||
197 | } | ||
198 | |||
199 | -(void) setContentSizeInPixels:(CGSize)size | ||
200 | { | ||
201 | if( ! CGSizeEqualToSize(size, contentSizeInPixels_) ) { | ||
202 | contentSizeInPixels_ = size; | ||
203 | |||
204 | if( CC_CONTENT_SCALE_FACTOR() == 1 ) | ||
205 | contentSize_ = contentSizeInPixels_; | ||
206 | else | ||
207 | contentSize_ = CGSizeMake( size.width / CC_CONTENT_SCALE_FACTOR(), size.height / CC_CONTENT_SCALE_FACTOR() ); | ||
208 | |||
209 | anchorPointInPixels_ = ccp( contentSizeInPixels_.width * anchorPoint_.x, contentSizeInPixels_.height * anchorPoint_.y ); | ||
210 | isTransformDirty_ = isInverseDirty_ = YES; | ||
211 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
212 | isTransformGLDirty_ = YES; | ||
213 | #endif | ||
214 | } | ||
215 | } | ||
216 | |||
217 | - (CGRect) boundingBox | ||
218 | { | ||
219 | CGRect ret = [self boundingBoxInPixels]; | ||
220 | return CC_RECT_PIXELS_TO_POINTS( ret ); | ||
221 | } | ||
222 | |||
223 | - (CGRect) boundingBoxInPixels | ||
224 | { | ||
225 | CGRect rect = CGRectMake(0, 0, contentSizeInPixels_.width, contentSizeInPixels_.height); | ||
226 | return CGRectApplyAffineTransform(rect, [self nodeToParentTransform]); | ||
227 | } | ||
228 | |||
229 | -(void) setVertexZ:(float)vertexZ | ||
230 | { | ||
231 | vertexZ_ = vertexZ * CC_CONTENT_SCALE_FACTOR(); | ||
232 | } | ||
233 | |||
234 | -(float) scale | ||
235 | { | ||
236 | NSAssert( scaleX_ == scaleY_, @"CCNode#scale. ScaleX != ScaleY. Don't know which one to return"); | ||
237 | return scaleX_; | ||
238 | } | ||
239 | |||
240 | -(void) setScale:(float) s | ||
241 | { | ||
242 | scaleX_ = scaleY_ = s; | ||
243 | isTransformDirty_ = isInverseDirty_ = YES; | ||
244 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
245 | isTransformGLDirty_ = YES; | ||
246 | #endif | ||
247 | } | ||
248 | |||
249 | #pragma mark CCNode - Init & cleanup | ||
250 | |||
251 | +(id) node | ||
252 | { | ||
253 | return [[[self alloc] init] autorelease]; | ||
254 | } | ||
255 | |||
256 | -(id) init | ||
257 | { | ||
258 | if ((self=[super init]) ) { | ||
259 | |||
260 | isRunning_ = NO; | ||
261 | |||
262 | skewX_ = skewY_ = 0.0f; | ||
263 | rotation_ = 0.0f; | ||
264 | scaleX_ = scaleY_ = 1.0f; | ||
265 | positionInPixels_ = position_ = CGPointZero; | ||
266 | anchorPointInPixels_ = anchorPoint_ = CGPointZero; | ||
267 | contentSizeInPixels_ = contentSize_ = CGSizeZero; | ||
268 | |||
269 | |||
270 | // "whole screen" objects. like Scenes and Layers, should set isRelativeAnchorPoint to NO | ||
271 | isRelativeAnchorPoint_ = YES; | ||
272 | |||
273 | isTransformDirty_ = isInverseDirty_ = YES; | ||
274 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
275 | isTransformGLDirty_ = YES; | ||
276 | #endif | ||
277 | |||
278 | vertexZ_ = 0; | ||
279 | |||
280 | grid_ = nil; | ||
281 | |||
282 | visible_ = YES; | ||
283 | |||
284 | tag_ = kCCNodeTagInvalid; | ||
285 | |||
286 | zOrder_ = 0; | ||
287 | |||
288 | // lazy alloc | ||
289 | camera_ = nil; | ||
290 | |||
291 | // children (lazy allocs) | ||
292 | children_ = nil; | ||
293 | |||
294 | // userData is always inited as nil | ||
295 | userData_ = nil; | ||
296 | |||
297 | //initialize parent to nil | ||
298 | parent_ = nil; | ||
299 | } | ||
300 | |||
301 | return self; | ||
302 | } | ||
303 | |||
304 | - (void)cleanup | ||
305 | { | ||
306 | // actions | ||
307 | [self stopAllActions]; | ||
308 | [self unscheduleAllSelectors]; | ||
309 | |||
310 | // timers | ||
311 | [children_ makeObjectsPerformSelector:@selector(cleanup)]; | ||
312 | } | ||
313 | |||
314 | - (NSString*) description | ||
315 | { | ||
316 | return [NSString stringWithFormat:@"<%@ = %08X | Tag = %i>", [self class], self, tag_]; | ||
317 | } | ||
318 | |||
319 | - (void) dealloc | ||
320 | { | ||
321 | CCLOGINFO( @"cocos2d: deallocing %@", self); | ||
322 | |||
323 | // attributes | ||
324 | [camera_ release]; | ||
325 | |||
326 | [grid_ release]; | ||
327 | |||
328 | // children | ||
329 | CCNode *child; | ||
330 | CCARRAY_FOREACH(children_, child) | ||
331 | child.parent = nil; | ||
332 | |||
333 | [children_ release]; | ||
334 | |||
335 | [super dealloc]; | ||
336 | } | ||
337 | |||
338 | #pragma mark CCNode Composition | ||
339 | |||
340 | -(void) childrenAlloc | ||
341 | { | ||
342 | children_ = [[CCArray alloc] initWithCapacity:4]; | ||
343 | } | ||
344 | |||
345 | // camera: lazy alloc | ||
346 | -(CCCamera*) camera | ||
347 | { | ||
348 | if( ! camera_ ) { | ||
349 | camera_ = [[CCCamera alloc] init]; | ||
350 | |||
351 | // by default, center camera at the Sprite's anchor point | ||
352 | // [camera_ setCenterX:anchorPointInPixels_.x centerY:anchorPointInPixels_.y centerZ:0]; | ||
353 | // [camera_ setEyeX:anchorPointInPixels_.x eyeY:anchorPointInPixels_.y eyeZ:1]; | ||
354 | |||
355 | // [camera_ setCenterX:0 centerY:0 centerZ:0]; | ||
356 | // [camera_ setEyeX:0 eyeY:0 eyeZ:1]; | ||
357 | |||
358 | } | ||
359 | |||
360 | return camera_; | ||
361 | } | ||
362 | |||
363 | -(CCNode*) getChildByTag:(NSInteger) aTag | ||
364 | { | ||
365 | NSAssert( aTag != kCCNodeTagInvalid, @"Invalid tag"); | ||
366 | |||
367 | CCNode *node; | ||
368 | CCARRAY_FOREACH(children_, node){ | ||
369 | if( node.tag == aTag ) | ||
370 | return node; | ||
371 | } | ||
372 | // not found | ||
373 | return nil; | ||
374 | } | ||
375 | |||
376 | /* "add" logic MUST only be on this method | ||
377 | * If a class want's to extend the 'addChild' behaviour it only needs | ||
378 | * to override this method | ||
379 | */ | ||
380 | -(void) addChild: (CCNode*) child z:(NSInteger)z tag:(NSInteger) aTag | ||
381 | { | ||
382 | NSAssert( child != nil, @"Argument must be non-nil"); | ||
383 | NSAssert( child.parent == nil, @"child already added. It can't be added again"); | ||
384 | |||
385 | if( ! children_ ) | ||
386 | [self childrenAlloc]; | ||
387 | |||
388 | [self insertChild:child z:z]; | ||
389 | |||
390 | child.tag = aTag; | ||
391 | |||
392 | [child setParent: self]; | ||
393 | |||
394 | if( isRunning_ ) { | ||
395 | [child onEnter]; | ||
396 | [child onEnterTransitionDidFinish]; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | -(void) addChild: (CCNode*) child z:(NSInteger)z | ||
401 | { | ||
402 | NSAssert( child != nil, @"Argument must be non-nil"); | ||
403 | [self addChild:child z:z tag:child.tag]; | ||
404 | } | ||
405 | |||
406 | -(void) addChild: (CCNode*) child | ||
407 | { | ||
408 | NSAssert( child != nil, @"Argument must be non-nil"); | ||
409 | [self addChild:child z:child.zOrder tag:child.tag]; | ||
410 | } | ||
411 | |||
412 | -(void) removeFromParentAndCleanup:(BOOL)cleanup | ||
413 | { | ||
414 | [parent_ removeChild:self cleanup:cleanup]; | ||
415 | } | ||
416 | |||
417 | /* "remove" logic MUST only be on this method | ||
418 | * If a class want's to extend the 'removeChild' behavior it only needs | ||
419 | * to override this method | ||
420 | */ | ||
421 | -(void) removeChild: (CCNode*)child cleanup:(BOOL)cleanup | ||
422 | { | ||
423 | // explicit nil handling | ||
424 | if (child == nil) | ||
425 | return; | ||
426 | |||
427 | if ( [children_ containsObject:child] ) | ||
428 | [self detachChild:child cleanup:cleanup]; | ||
429 | } | ||
430 | |||
431 | -(void) removeChildByTag:(NSInteger)aTag cleanup:(BOOL)cleanup | ||
432 | { | ||
433 | NSAssert( aTag != kCCNodeTagInvalid, @"Invalid tag"); | ||
434 | |||
435 | CCNode *child = [self getChildByTag:aTag]; | ||
436 | |||
437 | if (child == nil) | ||
438 | CCLOG(@"cocos2d: removeChildByTag: child not found!"); | ||
439 | else | ||
440 | [self removeChild:child cleanup:cleanup]; | ||
441 | } | ||
442 | |||
443 | -(void) removeAllChildrenWithCleanup:(BOOL)cleanup | ||
444 | { | ||
445 | // not using detachChild improves speed here | ||
446 | CCNode *c; | ||
447 | CCARRAY_FOREACH(children_, c) | ||
448 | { | ||
449 | // IMPORTANT: | ||
450 | // -1st do onExit | ||
451 | // -2nd cleanup | ||
452 | if (isRunning_) | ||
453 | [c onExit]; | ||
454 | |||
455 | if (cleanup) | ||
456 | [c cleanup]; | ||
457 | |||
458 | // set parent nil at the end (issue #476) | ||
459 | [c setParent:nil]; | ||
460 | } | ||
461 | |||
462 | [children_ removeAllObjects]; | ||
463 | } | ||
464 | |||
465 | -(void) detachChild:(CCNode *)child cleanup:(BOOL)doCleanup | ||
466 | { | ||
467 | // IMPORTANT: | ||
468 | // -1st do onExit | ||
469 | // -2nd cleanup | ||
470 | if (isRunning_) | ||
471 | [child onExit]; | ||
472 | |||
473 | // If you don't do cleanup, the child's actions will not get removed and the | ||
474 | // its scheduledSelectors_ dict will not get released! | ||
475 | if (doCleanup) | ||
476 | [child cleanup]; | ||
477 | |||
478 | // set parent nil at the end (issue #476) | ||
479 | [child setParent:nil]; | ||
480 | |||
481 | [children_ removeObject:child]; | ||
482 | } | ||
483 | |||
484 | // used internally to alter the zOrder variable. DON'T call this method manually | ||
485 | -(void) _setZOrder:(NSInteger) z | ||
486 | { | ||
487 | zOrder_ = z; | ||
488 | } | ||
489 | |||
490 | // helper used by reorderChild & add | ||
491 | -(void) insertChild:(CCNode*)child z:(NSInteger)z | ||
492 | { | ||
493 | NSUInteger index=0; | ||
494 | CCNode *a = [children_ lastObject]; | ||
495 | |||
496 | // quick comparison to improve performance | ||
497 | if (!a || a.zOrder <= z) | ||
498 | [children_ addObject:child]; | ||
499 | |||
500 | else | ||
501 | { | ||
502 | CCARRAY_FOREACH(children_, a) { | ||
503 | if ( a.zOrder > z ) { | ||
504 | [children_ insertObject:child atIndex:index]; | ||
505 | break; | ||
506 | } | ||
507 | index++; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | [child _setZOrder:z]; | ||
512 | } | ||
513 | |||
514 | -(void) reorderChild:(CCNode*) child z:(NSInteger)z | ||
515 | { | ||
516 | NSAssert( child != nil, @"Child must be non-nil"); | ||
517 | |||
518 | [child retain]; | ||
519 | [children_ removeObject:child]; | ||
520 | |||
521 | [self insertChild:child z:z]; | ||
522 | |||
523 | [child release]; | ||
524 | } | ||
525 | |||
526 | #pragma mark CCNode Draw | ||
527 | |||
528 | -(void) draw | ||
529 | { | ||
530 | // override me | ||
531 | // Only use this function to draw your staff. | ||
532 | // DON'T draw your stuff outside this method | ||
533 | } | ||
534 | |||
535 | -(void) visit | ||
536 | { | ||
537 | // quick return if not visible | ||
538 | if (!visible_) | ||
539 | return; | ||
540 | |||
541 | glPushMatrix(); | ||
542 | |||
543 | if ( grid_ && grid_.active) { | ||
544 | [grid_ beforeDraw]; | ||
545 | [self transformAncestors]; | ||
546 | } | ||
547 | |||
548 | [self transform]; | ||
549 | |||
550 | if(children_) { | ||
551 | ccArray *arrayData = children_->data; | ||
552 | NSUInteger i = 0; | ||
553 | |||
554 | // draw children zOrder < 0 | ||
555 | for( ; i < arrayData->num; i++ ) { | ||
556 | CCNode *child = arrayData->arr[i]; | ||
557 | if ( [child zOrder] < 0 ) | ||
558 | [child visit]; | ||
559 | else | ||
560 | break; | ||
561 | } | ||
562 | |||
563 | // self draw | ||
564 | [self draw]; | ||
565 | |||
566 | // draw children zOrder >= 0 | ||
567 | for( ; i < arrayData->num; i++ ) { | ||
568 | CCNode *child = arrayData->arr[i]; | ||
569 | [child visit]; | ||
570 | } | ||
571 | |||
572 | } else | ||
573 | [self draw]; | ||
574 | |||
575 | if ( grid_ && grid_.active) | ||
576 | [grid_ afterDraw:self]; | ||
577 | |||
578 | glPopMatrix(); | ||
579 | } | ||
580 | |||
581 | #pragma mark CCNode - Transformations | ||
582 | |||
583 | -(void) transformAncestors | ||
584 | { | ||
585 | if( parent_ ) { | ||
586 | [parent_ transformAncestors]; | ||
587 | [parent_ transform]; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | -(void) transform | ||
592 | { | ||
593 | // transformations | ||
594 | |||
595 | #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
596 | // BEGIN alternative -- using cached transform | ||
597 | // | ||
598 | if( isTransformGLDirty_ ) { | ||
599 | CGAffineTransform t = [self nodeToParentTransform]; | ||
600 | CGAffineToGL(&t, transformGL_); | ||
601 | isTransformGLDirty_ = NO; | ||
602 | } | ||
603 | |||
604 | glMultMatrixf(transformGL_); | ||
605 | if( vertexZ_ ) | ||
606 | glTranslatef(0, 0, vertexZ_); | ||
607 | |||
608 | // XXX: Expensive calls. Camera should be integrated into the cached affine matrix | ||
609 | if ( camera_ && !(grid_ && grid_.active) ) | ||
610 | { | ||
611 | BOOL translate = (anchorPointInPixels_.x != 0.0f || anchorPointInPixels_.y != 0.0f); | ||
612 | |||
613 | if( translate ) | ||
614 | ccglTranslate(RENDER_IN_SUBPIXEL(anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(anchorPointInPixels_.y), 0); | ||
615 | |||
616 | [camera_ locate]; | ||
617 | |||
618 | if( translate ) | ||
619 | ccglTranslate(RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0); | ||
620 | } | ||
621 | |||
622 | |||
623 | // END alternative | ||
624 | |||
625 | #else | ||
626 | // BEGIN original implementation | ||
627 | // | ||
628 | // translate | ||
629 | if ( isRelativeAnchorPoint_ && (anchorPointInPixels_.x != 0 || anchorPointInPixels_.y != 0 ) ) | ||
630 | glTranslatef( RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0); | ||
631 | |||
632 | if (anchorPointInPixels_.x != 0 || anchorPointInPixels_.y != 0) | ||
633 | glTranslatef( RENDER_IN_SUBPIXEL(positionInPixels_.x + anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(positionInPixels_.y + anchorPointInPixels_.y), vertexZ_); | ||
634 | else if ( positionInPixels_.x !=0 || positionInPixels_.y !=0 || vertexZ_ != 0) | ||
635 | glTranslatef( RENDER_IN_SUBPIXEL(positionInPixels_.x), RENDER_IN_SUBPIXEL(positionInPixels_.y), vertexZ_ ); | ||
636 | |||
637 | // rotate | ||
638 | if (rotation_ != 0.0f ) | ||
639 | glRotatef( -rotation_, 0.0f, 0.0f, 1.0f ); | ||
640 | |||
641 | // skew | ||
642 | if ( (skewX_ != 0.0f) || (skewY_ != 0.0f) ) { | ||
643 | CGAffineTransform skewMatrix = CGAffineTransformMake( 1.0f, tanf(CC_DEGREES_TO_RADIANS(skewY_)), tanf(CC_DEGREES_TO_RADIANS(skewX_)), 1.0f, 0.0f, 0.0f ); | ||
644 | GLfloat glMatrix[16]; | ||
645 | CGAffineToGL(&skewMatrix, glMatrix); | ||
646 | glMultMatrixf(glMatrix); | ||
647 | } | ||
648 | |||
649 | // scale | ||
650 | if (scaleX_ != 1.0f || scaleY_ != 1.0f) | ||
651 | glScalef( scaleX_, scaleY_, 1.0f ); | ||
652 | |||
653 | if ( camera_ && !(grid_ && grid_.active) ) | ||
654 | [camera_ locate]; | ||
655 | |||
656 | // restore and re-position point | ||
657 | if (anchorPointInPixels_.x != 0.0f || anchorPointInPixels_.y != 0.0f) | ||
658 | glTranslatef(RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0); | ||
659 | |||
660 | // | ||
661 | // END original implementation | ||
662 | #endif | ||
663 | |||
664 | } | ||
665 | |||
666 | #pragma mark CCNode SceneManagement | ||
667 | |||
668 | -(void) onEnter | ||
669 | { | ||
670 | [children_ makeObjectsPerformSelector:@selector(onEnter)]; | ||
671 | [self resumeSchedulerAndActions]; | ||
672 | |||
673 | isRunning_ = YES; | ||
674 | } | ||
675 | |||
676 | -(void) onEnterTransitionDidFinish | ||
677 | { | ||
678 | [children_ makeObjectsPerformSelector:@selector(onEnterTransitionDidFinish)]; | ||
679 | } | ||
680 | |||
681 | -(void) onExit | ||
682 | { | ||
683 | [self pauseSchedulerAndActions]; | ||
684 | isRunning_ = NO; | ||
685 | |||
686 | [children_ makeObjectsPerformSelector:@selector(onExit)]; | ||
687 | } | ||
688 | |||
689 | #pragma mark CCNode Actions | ||
690 | |||
691 | -(CCAction*) runAction:(CCAction*) action | ||
692 | { | ||
693 | NSAssert( action != nil, @"Argument must be non-nil"); | ||
694 | |||
695 | [[CCActionManager sharedManager] addAction:action target:self paused:!isRunning_]; | ||
696 | return action; | ||
697 | } | ||
698 | |||
699 | -(void) stopAllActions | ||
700 | { | ||
701 | [[CCActionManager sharedManager] removeAllActionsFromTarget:self]; | ||
702 | } | ||
703 | |||
704 | -(void) stopAction: (CCAction*) action | ||
705 | { | ||
706 | [[CCActionManager sharedManager] removeAction:action]; | ||
707 | } | ||
708 | |||
709 | -(void) stopActionByTag:(NSInteger)aTag | ||
710 | { | ||
711 | NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag"); | ||
712 | [[CCActionManager sharedManager] removeActionByTag:aTag target:self]; | ||
713 | } | ||
714 | |||
715 | -(CCAction*) getActionByTag:(NSInteger) aTag | ||
716 | { | ||
717 | NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag"); | ||
718 | return [[CCActionManager sharedManager] getActionByTag:aTag target:self]; | ||
719 | } | ||
720 | |||
721 | -(NSUInteger) numberOfRunningActions | ||
722 | { | ||
723 | return [[CCActionManager sharedManager] numberOfRunningActionsInTarget:self]; | ||
724 | } | ||
725 | |||
726 | #pragma mark CCNode - Scheduler | ||
727 | |||
728 | -(void) scheduleUpdate | ||
729 | { | ||
730 | [self scheduleUpdateWithPriority:0]; | ||
731 | } | ||
732 | |||
733 | -(void) scheduleUpdateWithPriority:(NSInteger)priority | ||
734 | { | ||
735 | [[CCScheduler sharedScheduler] scheduleUpdateForTarget:self priority:priority paused:!isRunning_]; | ||
736 | } | ||
737 | |||
738 | -(void) unscheduleUpdate | ||
739 | { | ||
740 | [[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self]; | ||
741 | } | ||
742 | |||
743 | -(void) schedule:(SEL)selector | ||
744 | { | ||
745 | [self schedule:selector interval:0]; | ||
746 | } | ||
747 | |||
748 | -(void) schedule:(SEL)selector interval:(ccTime)interval | ||
749 | { | ||
750 | NSAssert( selector != nil, @"Argument must be non-nil"); | ||
751 | NSAssert( interval >=0, @"Arguemnt must be positive"); | ||
752 | |||
753 | [[CCScheduler sharedScheduler] scheduleSelector:selector forTarget:self interval:interval paused:!isRunning_]; | ||
754 | } | ||
755 | |||
756 | -(void) unschedule:(SEL)selector | ||
757 | { | ||
758 | // explicit nil handling | ||
759 | if (selector == nil) | ||
760 | return; | ||
761 | |||
762 | [[CCScheduler sharedScheduler] unscheduleSelector:selector forTarget:self]; | ||
763 | } | ||
764 | |||
765 | -(void) unscheduleAllSelectors | ||
766 | { | ||
767 | [[CCScheduler sharedScheduler] unscheduleAllSelectorsForTarget:self]; | ||
768 | } | ||
769 | - (void) resumeSchedulerAndActions | ||
770 | { | ||
771 | [[CCScheduler sharedScheduler] resumeTarget:self]; | ||
772 | [[CCActionManager sharedManager] resumeTarget:self]; | ||
773 | } | ||
774 | |||
775 | - (void) pauseSchedulerAndActions | ||
776 | { | ||
777 | [[CCScheduler sharedScheduler] pauseTarget:self]; | ||
778 | [[CCActionManager sharedManager] pauseTarget:self]; | ||
779 | } | ||
780 | |||
781 | #pragma mark CCNode Transform | ||
782 | |||
783 | - (CGAffineTransform)nodeToParentTransform | ||
784 | { | ||
785 | if ( isTransformDirty_ ) { | ||
786 | |||
787 | transform_ = CGAffineTransformIdentity; | ||
788 | |||
789 | if ( !isRelativeAnchorPoint_ && !CGPointEqualToPoint(anchorPointInPixels_, CGPointZero) ) | ||
790 | transform_ = CGAffineTransformTranslate(transform_, anchorPointInPixels_.x, anchorPointInPixels_.y); | ||
791 | |||
792 | if( ! CGPointEqualToPoint(positionInPixels_, CGPointZero) ) | ||
793 | transform_ = CGAffineTransformTranslate(transform_, positionInPixels_.x, positionInPixels_.y); | ||
794 | |||
795 | if( rotation_ != 0 ) | ||
796 | transform_ = CGAffineTransformRotate(transform_, -CC_DEGREES_TO_RADIANS(rotation_)); | ||
797 | |||
798 | if( skewX_ != 0 || skewY_ != 0 ) { | ||
799 | // create a skewed coordinate system | ||
800 | CGAffineTransform skew = CGAffineTransformMake(1.0f, tanf(CC_DEGREES_TO_RADIANS(skewY_)), tanf(CC_DEGREES_TO_RADIANS(skewX_)), 1.0f, 0.0f, 0.0f); | ||
801 | // apply the skew to the transform | ||
802 | transform_ = CGAffineTransformConcat(skew, transform_); | ||
803 | } | ||
804 | |||
805 | if( ! (scaleX_ == 1 && scaleY_ == 1) ) | ||
806 | transform_ = CGAffineTransformScale(transform_, scaleX_, scaleY_); | ||
807 | |||
808 | if( ! CGPointEqualToPoint(anchorPointInPixels_, CGPointZero) ) | ||
809 | transform_ = CGAffineTransformTranslate(transform_, -anchorPointInPixels_.x, -anchorPointInPixels_.y); | ||
810 | |||
811 | isTransformDirty_ = NO; | ||
812 | } | ||
813 | |||
814 | return transform_; | ||
815 | } | ||
816 | |||
817 | - (CGAffineTransform)parentToNodeTransform | ||
818 | { | ||
819 | if ( isInverseDirty_ ) { | ||
820 | inverse_ = CGAffineTransformInvert([self nodeToParentTransform]); | ||
821 | isInverseDirty_ = NO; | ||
822 | } | ||
823 | |||
824 | return inverse_; | ||
825 | } | ||
826 | |||
827 | - (CGAffineTransform)nodeToWorldTransform | ||
828 | { | ||
829 | CGAffineTransform t = [self nodeToParentTransform]; | ||
830 | |||
831 | for (CCNode *p = parent_; p != nil; p = p.parent) | ||
832 | t = CGAffineTransformConcat(t, [p nodeToParentTransform]); | ||
833 | |||
834 | return t; | ||
835 | } | ||
836 | |||
837 | - (CGAffineTransform)worldToNodeTransform | ||
838 | { | ||
839 | return CGAffineTransformInvert([self nodeToWorldTransform]); | ||
840 | } | ||
841 | |||
842 | - (CGPoint)convertToNodeSpace:(CGPoint)worldPoint | ||
843 | { | ||
844 | CGPoint ret; | ||
845 | if( CC_CONTENT_SCALE_FACTOR() == 1 ) | ||
846 | ret = CGPointApplyAffineTransform(worldPoint, [self worldToNodeTransform]); | ||
847 | else { | ||
848 | ret = ccpMult( worldPoint, CC_CONTENT_SCALE_FACTOR() ); | ||
849 | ret = CGPointApplyAffineTransform(ret, [self worldToNodeTransform]); | ||
850 | ret = ccpMult( ret, 1/CC_CONTENT_SCALE_FACTOR() ); | ||
851 | } | ||
852 | |||
853 | return ret; | ||
854 | } | ||
855 | |||
856 | - (CGPoint)convertToWorldSpace:(CGPoint)nodePoint | ||
857 | { | ||
858 | CGPoint ret; | ||
859 | if( CC_CONTENT_SCALE_FACTOR() == 1 ) | ||
860 | ret = CGPointApplyAffineTransform(nodePoint, [self nodeToWorldTransform]); | ||
861 | else { | ||
862 | ret = ccpMult( nodePoint, CC_CONTENT_SCALE_FACTOR() ); | ||
863 | ret = CGPointApplyAffineTransform(ret, [self nodeToWorldTransform]); | ||
864 | ret = ccpMult( ret, 1/CC_CONTENT_SCALE_FACTOR() ); | ||
865 | } | ||
866 | |||
867 | return ret; | ||
868 | } | ||
869 | |||
870 | - (CGPoint)convertToNodeSpaceAR:(CGPoint)worldPoint | ||
871 | { | ||
872 | CGPoint nodePoint = [self convertToNodeSpace:worldPoint]; | ||
873 | CGPoint anchorInPoints; | ||
874 | if( CC_CONTENT_SCALE_FACTOR() == 1 ) | ||
875 | anchorInPoints = anchorPointInPixels_; | ||
876 | else | ||
877 | anchorInPoints = ccpMult( anchorPointInPixels_, 1/CC_CONTENT_SCALE_FACTOR() ); | ||
878 | |||
879 | return ccpSub(nodePoint, anchorInPoints); | ||
880 | } | ||
881 | |||
882 | - (CGPoint)convertToWorldSpaceAR:(CGPoint)nodePoint | ||
883 | { | ||
884 | CGPoint anchorInPoints; | ||
885 | if( CC_CONTENT_SCALE_FACTOR() == 1 ) | ||
886 | anchorInPoints = anchorPointInPixels_; | ||
887 | else | ||
888 | anchorInPoints = ccpMult( anchorPointInPixels_, 1/CC_CONTENT_SCALE_FACTOR() ); | ||
889 | |||
890 | nodePoint = ccpAdd(nodePoint, anchorInPoints); | ||
891 | return [self convertToWorldSpace:nodePoint]; | ||
892 | } | ||
893 | |||
894 | - (CGPoint)convertToWindowSpace:(CGPoint)nodePoint | ||
895 | { | ||
896 | CGPoint worldPoint = [self convertToWorldSpace:nodePoint]; | ||
897 | return [[CCDirector sharedDirector] convertToUI:worldPoint]; | ||
898 | } | ||
899 | |||
900 | // convenience methods which take a UITouch instead of CGPoint | ||
901 | |||
902 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
903 | |||
904 | - (CGPoint)convertTouchToNodeSpace:(UITouch *)touch | ||
905 | { | ||
906 | CGPoint point = [touch locationInView: [touch view]]; | ||
907 | point = [[CCDirector sharedDirector] convertToGL: point]; | ||
908 | return [self convertToNodeSpace:point]; | ||
909 | } | ||
910 | |||
911 | - (CGPoint)convertTouchToNodeSpaceAR:(UITouch *)touch | ||
912 | { | ||
913 | CGPoint point = [touch locationInView: [touch view]]; | ||
914 | point = [[CCDirector sharedDirector] convertToGL: point]; | ||
915 | return [self convertToNodeSpaceAR:point]; | ||
916 | } | ||
917 | |||
918 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
919 | |||
920 | |||
921 | @end | ||
diff --git a/libs/cocos2d/CCParallaxNode.h b/libs/cocos2d/CCParallaxNode.h new file mode 100755 index 0000000..5728eb1 --- /dev/null +++ b/libs/cocos2d/CCParallaxNode.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009-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 | #import "CCNode.h" | ||
28 | #import "Support/ccCArray.h" | ||
29 | |||
30 | /** CCParallaxNode: A node that simulates a parallax scroller | ||
31 | |||
32 | The children will be moved faster / slower than the parent according the the parallax ratio. | ||
33 | |||
34 | */ | ||
35 | @interface CCParallaxNode : CCNode | ||
36 | { | ||
37 | ccArray *parallaxArray_; | ||
38 | CGPoint lastPosition; | ||
39 | } | ||
40 | |||
41 | /** array that holds the offset / ratio of the children */ | ||
42 | @property (nonatomic,readwrite) ccArray * parallaxArray; | ||
43 | |||
44 | /** Adds a child to the container with a z-order, a parallax ratio and a position offset | ||
45 | It returns self, so you can chain several addChilds. | ||
46 | @since v0.8 | ||
47 | */ | ||
48 | -(void) addChild: (CCNode*)node z:(NSInteger)z parallaxRatio:(CGPoint)c positionOffset:(CGPoint)positionOffset; | ||
49 | |||
50 | @end | ||
diff --git a/libs/cocos2d/CCParallaxNode.m b/libs/cocos2d/CCParallaxNode.m new file mode 100755 index 0000000..9d39cc8 --- /dev/null +++ b/libs/cocos2d/CCParallaxNode.m | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009-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 | #import "CCParallaxNode.h" | ||
28 | #import "Support/CGPointExtension.h" | ||
29 | #import "Support/ccCArray.h" | ||
30 | |||
31 | @interface CGPointObject : NSObject | ||
32 | { | ||
33 | CGPoint ratio_; | ||
34 | CGPoint offset_; | ||
35 | CCNode *child_; // weak ref | ||
36 | } | ||
37 | @property (readwrite) CGPoint ratio; | ||
38 | @property (readwrite) CGPoint offset; | ||
39 | @property (readwrite,assign) CCNode *child; | ||
40 | +(id) pointWithCGPoint:(CGPoint)point offset:(CGPoint)offset; | ||
41 | -(id) initWithCGPoint:(CGPoint)point offset:(CGPoint)offset; | ||
42 | @end | ||
43 | @implementation CGPointObject | ||
44 | @synthesize ratio = ratio_; | ||
45 | @synthesize offset = offset_; | ||
46 | @synthesize child=child_; | ||
47 | |||
48 | +(id) pointWithCGPoint:(CGPoint)ratio offset:(CGPoint)offset | ||
49 | { | ||
50 | return [[[self alloc] initWithCGPoint:ratio offset:offset] autorelease]; | ||
51 | } | ||
52 | -(id) initWithCGPoint:(CGPoint)ratio offset:(CGPoint)offset | ||
53 | { | ||
54 | if( (self=[super init])) { | ||
55 | ratio_ = ratio; | ||
56 | offset_ = offset; | ||
57 | } | ||
58 | return self; | ||
59 | } | ||
60 | @end | ||
61 | |||
62 | @implementation CCParallaxNode | ||
63 | |||
64 | @synthesize parallaxArray = parallaxArray_; | ||
65 | |||
66 | -(id) init | ||
67 | { | ||
68 | if( (self=[super init]) ) { | ||
69 | parallaxArray_ = ccArrayNew(5); | ||
70 | lastPosition = CGPointMake(-100,-100); | ||
71 | } | ||
72 | return self; | ||
73 | } | ||
74 | |||
75 | - (void) dealloc | ||
76 | { | ||
77 | if( parallaxArray_ ) { | ||
78 | ccArrayFree(parallaxArray_); | ||
79 | parallaxArray_ = nil; | ||
80 | } | ||
81 | [super dealloc]; | ||
82 | } | ||
83 | |||
84 | -(void) addChild:(CCNode*)child z:(NSInteger)z tag:(NSInteger)tag | ||
85 | { | ||
86 | NSAssert(NO,@"ParallaxNode: use addChild:z:parallaxRatio:positionOffset instead"); | ||
87 | } | ||
88 | |||
89 | -(void) addChild: (CCNode*) child z:(NSInteger)z parallaxRatio:(CGPoint)ratio positionOffset:(CGPoint)offset | ||
90 | { | ||
91 | NSAssert( child != nil, @"Argument must be non-nil"); | ||
92 | CGPointObject *obj = [CGPointObject pointWithCGPoint:ratio offset:offset]; | ||
93 | obj.child = child; | ||
94 | ccArrayAppendObjectWithResize(parallaxArray_, obj); | ||
95 | |||
96 | CGPoint pos = self.position; | ||
97 | pos.x = pos.x * ratio.x + offset.x; | ||
98 | pos.y = pos.y * ratio.y + offset.y; | ||
99 | child.position = pos; | ||
100 | |||
101 | [super addChild: child z:z tag:child.tag]; | ||
102 | } | ||
103 | |||
104 | -(void) removeChild:(CCNode*)node cleanup:(BOOL)cleanup | ||
105 | { | ||
106 | for( unsigned int i=0;i < parallaxArray_->num;i++) { | ||
107 | CGPointObject *point = parallaxArray_->arr[i]; | ||
108 | if( [point.child isEqual:node] ) { | ||
109 | ccArrayRemoveObjectAtIndex(parallaxArray_, i); | ||
110 | break; | ||
111 | } | ||
112 | } | ||
113 | [super removeChild:node cleanup:cleanup]; | ||
114 | } | ||
115 | |||
116 | -(void) removeAllChildrenWithCleanup:(BOOL)cleanup | ||
117 | { | ||
118 | ccArrayRemoveAllObjects(parallaxArray_); | ||
119 | [super removeAllChildrenWithCleanup:cleanup]; | ||
120 | } | ||
121 | |||
122 | -(CGPoint) absolutePosition_ | ||
123 | { | ||
124 | CGPoint ret = position_; | ||
125 | |||
126 | CCNode *cn = self; | ||
127 | |||
128 | while (cn.parent != nil) { | ||
129 | cn = cn.parent; | ||
130 | ret = ccpAdd( ret, cn.position ); | ||
131 | } | ||
132 | |||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | The positions are updated at visit because: | ||
138 | - using a timer is not guaranteed that it will called after all the positions were updated | ||
139 | - overriding "draw" will only precise if the children have a z > 0 | ||
140 | */ | ||
141 | -(void) visit | ||
142 | { | ||
143 | // CGPoint pos = position_; | ||
144 | // CGPoint pos = [self convertToWorldSpace:CGPointZero]; | ||
145 | CGPoint pos = [self absolutePosition_]; | ||
146 | if( ! CGPointEqualToPoint(pos, lastPosition) ) { | ||
147 | |||
148 | for(unsigned int i=0; i < parallaxArray_->num; i++ ) { | ||
149 | |||
150 | CGPointObject *point = parallaxArray_->arr[i]; | ||
151 | float x = -pos.x + pos.x * point.ratio.x + point.offset.x; | ||
152 | float y = -pos.y + pos.y * point.ratio.y + point.offset.y; | ||
153 | point.child.position = ccp(x,y); | ||
154 | } | ||
155 | |||
156 | lastPosition = pos; | ||
157 | } | ||
158 | |||
159 | [super visit]; | ||
160 | } | ||
161 | @end | ||
diff --git a/libs/cocos2d/CCParticleExamples.h b/libs/cocos2d/CCParticleExamples.h new file mode 100755 index 0000000..cd382c4 --- /dev/null +++ b/libs/cocos2d/CCParticleExamples.h | |||
@@ -0,0 +1,111 @@ | |||
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 | #import <Availability.h> | ||
29 | |||
30 | #import "CCParticleSystemPoint.h" | ||
31 | #import "CCParticleSystemQuad.h" | ||
32 | |||
33 | // build each architecture with the optimal particle system | ||
34 | |||
35 | // ARMv7, Mac or Simulator use "Quad" particle | ||
36 | #if defined(__ARM_NEON__) || defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || TARGET_IPHONE_SIMULATOR | ||
37 | #define ARCH_OPTIMAL_PARTICLE_SYSTEM CCParticleSystemQuad | ||
38 | |||
39 | // ARMv6 use "Point" particle | ||
40 | #elif __arm__ | ||
41 | #define ARCH_OPTIMAL_PARTICLE_SYSTEM CCParticleSystemPoint | ||
42 | #else | ||
43 | #error(unknown architecture) | ||
44 | #endif | ||
45 | |||
46 | |||
47 | //! A fire particle system | ||
48 | @interface CCParticleFire: ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
49 | { | ||
50 | } | ||
51 | @end | ||
52 | |||
53 | //! A fireworks particle system | ||
54 | @interface CCParticleFireworks : ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
55 | { | ||
56 | } | ||
57 | @end | ||
58 | |||
59 | //! A sun particle system | ||
60 | @interface CCParticleSun : ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
61 | { | ||
62 | } | ||
63 | @end | ||
64 | |||
65 | //! A galaxy particle system | ||
66 | @interface CCParticleGalaxy : ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
67 | { | ||
68 | } | ||
69 | @end | ||
70 | |||
71 | //! A flower particle system | ||
72 | @interface CCParticleFlower : ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
73 | { | ||
74 | } | ||
75 | @end | ||
76 | |||
77 | //! A meteor particle system | ||
78 | @interface CCParticleMeteor : ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
79 | { | ||
80 | } | ||
81 | @end | ||
82 | |||
83 | //! An spiral particle system | ||
84 | @interface CCParticleSpiral : ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
85 | { | ||
86 | } | ||
87 | @end | ||
88 | |||
89 | //! An explosion particle system | ||
90 | @interface CCParticleExplosion : ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
91 | { | ||
92 | } | ||
93 | @end | ||
94 | |||
95 | //! An smoke particle system | ||
96 | @interface CCParticleSmoke : ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
97 | { | ||
98 | } | ||
99 | @end | ||
100 | |||
101 | //! An snow particle system | ||
102 | @interface CCParticleSnow : ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
103 | { | ||
104 | } | ||
105 | @end | ||
106 | |||
107 | //! A rain particle system | ||
108 | @interface CCParticleRain : ARCH_OPTIMAL_PARTICLE_SYSTEM | ||
109 | { | ||
110 | } | ||
111 | @end | ||
diff --git a/libs/cocos2d/CCParticleExamples.m b/libs/cocos2d/CCParticleExamples.m new file mode 100755 index 0000000..38c8b46 --- /dev/null +++ b/libs/cocos2d/CCParticleExamples.m | |||
@@ -0,0 +1,926 @@ | |||
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 "CCParticleExamples.h" | ||
30 | #import "CCTextureCache.h" | ||
31 | #import "CCDirector.h" | ||
32 | #import "Support/CGPointExtension.h" | ||
33 | |||
34 | // | ||
35 | // ParticleFireworks | ||
36 | // | ||
37 | @implementation CCParticleFireworks | ||
38 | -(id) init | ||
39 | { | ||
40 | return [self initWithTotalParticles:1500]; | ||
41 | } | ||
42 | |||
43 | -(id) initWithTotalParticles:(NSUInteger)p | ||
44 | { | ||
45 | if( (self=[super initWithTotalParticles:p]) ) { | ||
46 | // duration | ||
47 | duration = kCCParticleDurationInfinity; | ||
48 | |||
49 | // Gravity Mode | ||
50 | self.emitterMode = kCCParticleModeGravity; | ||
51 | |||
52 | // Gravity Mode: gravity | ||
53 | self.gravity = ccp(0,-90); | ||
54 | |||
55 | // Gravity Mode: radial | ||
56 | self.radialAccel = 0; | ||
57 | self.radialAccelVar = 0; | ||
58 | |||
59 | // Gravity Mode: speed of particles | ||
60 | self.speed = 180; | ||
61 | self.speedVar = 50; | ||
62 | |||
63 | // emitter position | ||
64 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
65 | self.position = ccp(winSize.width/2, winSize.height/2); | ||
66 | |||
67 | // angle | ||
68 | angle = 90; | ||
69 | angleVar = 20; | ||
70 | |||
71 | // life of particles | ||
72 | life = 3.5f; | ||
73 | lifeVar = 1; | ||
74 | |||
75 | // emits per frame | ||
76 | emissionRate = totalParticles/life; | ||
77 | |||
78 | // color of particles | ||
79 | startColor.r = 0.5f; | ||
80 | startColor.g = 0.5f; | ||
81 | startColor.b = 0.5f; | ||
82 | startColor.a = 1.0f; | ||
83 | startColorVar.r = 0.5f; | ||
84 | startColorVar.g = 0.5f; | ||
85 | startColorVar.b = 0.5f; | ||
86 | startColorVar.a = 0.1f; | ||
87 | endColor.r = 0.1f; | ||
88 | endColor.g = 0.1f; | ||
89 | endColor.b = 0.1f; | ||
90 | endColor.a = 0.2f; | ||
91 | endColorVar.r = 0.1f; | ||
92 | endColorVar.g = 0.1f; | ||
93 | endColorVar.b = 0.1f; | ||
94 | endColorVar.a = 0.2f; | ||
95 | |||
96 | // size, in pixels | ||
97 | startSize = 8.0f; | ||
98 | startSizeVar = 2.0f; | ||
99 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
100 | |||
101 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
102 | |||
103 | // additive | ||
104 | self.blendAdditive = NO; | ||
105 | } | ||
106 | |||
107 | return self; | ||
108 | } | ||
109 | @end | ||
110 | |||
111 | // | ||
112 | // ParticleFire | ||
113 | // | ||
114 | @implementation CCParticleFire | ||
115 | -(id) init | ||
116 | { | ||
117 | return [self initWithTotalParticles:250]; | ||
118 | } | ||
119 | |||
120 | -(id) initWithTotalParticles:(NSUInteger) p | ||
121 | { | ||
122 | if( (self=[super initWithTotalParticles:p]) ) { | ||
123 | |||
124 | // duration | ||
125 | duration = kCCParticleDurationInfinity; | ||
126 | |||
127 | // Gravity Mode | ||
128 | self.emitterMode = kCCParticleModeGravity; | ||
129 | |||
130 | // Gravity Mode: gravity | ||
131 | self.gravity = ccp(0,0); | ||
132 | |||
133 | // Gravity Mode: radial acceleration | ||
134 | self.radialAccel = 0; | ||
135 | self.radialAccelVar = 0; | ||
136 | |||
137 | // Gravity Mode: speed of particles | ||
138 | self.speed = 60; | ||
139 | self.speedVar = 20; | ||
140 | |||
141 | // starting angle | ||
142 | angle = 90; | ||
143 | angleVar = 10; | ||
144 | |||
145 | // emitter position | ||
146 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
147 | self.position = ccp(winSize.width/2, 60); | ||
148 | posVar = ccp(40, 20); | ||
149 | |||
150 | // life of particles | ||
151 | life = 3; | ||
152 | lifeVar = 0.25f; | ||
153 | |||
154 | |||
155 | // size, in pixels | ||
156 | startSize = 54.0f; | ||
157 | startSizeVar = 10.0f; | ||
158 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
159 | |||
160 | // emits per frame | ||
161 | emissionRate = totalParticles/life; | ||
162 | |||
163 | // color of particles | ||
164 | startColor.r = 0.76f; | ||
165 | startColor.g = 0.25f; | ||
166 | startColor.b = 0.12f; | ||
167 | startColor.a = 1.0f; | ||
168 | startColorVar.r = 0.0f; | ||
169 | startColorVar.g = 0.0f; | ||
170 | startColorVar.b = 0.0f; | ||
171 | startColorVar.a = 0.0f; | ||
172 | endColor.r = 0.0f; | ||
173 | endColor.g = 0.0f; | ||
174 | endColor.b = 0.0f; | ||
175 | endColor.a = 1.0f; | ||
176 | endColorVar.r = 0.0f; | ||
177 | endColorVar.g = 0.0f; | ||
178 | endColorVar.b = 0.0f; | ||
179 | endColorVar.a = 0.0f; | ||
180 | |||
181 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
182 | |||
183 | // additive | ||
184 | self.blendAdditive = YES; | ||
185 | } | ||
186 | |||
187 | return self; | ||
188 | } | ||
189 | @end | ||
190 | |||
191 | // | ||
192 | // ParticleSun | ||
193 | // | ||
194 | @implementation CCParticleSun | ||
195 | -(id) init | ||
196 | { | ||
197 | return [self initWithTotalParticles:350]; | ||
198 | } | ||
199 | |||
200 | -(id) initWithTotalParticles:(NSUInteger) p | ||
201 | { | ||
202 | if( (self=[super initWithTotalParticles:p]) ) { | ||
203 | |||
204 | // additive | ||
205 | self.blendAdditive = YES; | ||
206 | |||
207 | // duration | ||
208 | duration = kCCParticleDurationInfinity; | ||
209 | |||
210 | // Gravity Mode | ||
211 | self.emitterMode = kCCParticleModeGravity; | ||
212 | |||
213 | // Gravity Mode: gravity | ||
214 | self.gravity = ccp(0,0); | ||
215 | |||
216 | // Gravity mode: radial acceleration | ||
217 | self.radialAccel = 0; | ||
218 | self.radialAccelVar = 0; | ||
219 | |||
220 | // Gravity mode: speed of particles | ||
221 | self.speed = 20; | ||
222 | self.speedVar = 5; | ||
223 | |||
224 | |||
225 | // angle | ||
226 | angle = 90; | ||
227 | angleVar = 360; | ||
228 | |||
229 | // emitter position | ||
230 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
231 | self.position = ccp(winSize.width/2, winSize.height/2); | ||
232 | posVar = CGPointZero; | ||
233 | |||
234 | // life of particles | ||
235 | life = 1; | ||
236 | lifeVar = 0.5f; | ||
237 | |||
238 | // size, in pixels | ||
239 | startSize = 30.0f; | ||
240 | startSizeVar = 10.0f; | ||
241 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
242 | |||
243 | // emits per seconds | ||
244 | emissionRate = totalParticles/life; | ||
245 | |||
246 | // color of particles | ||
247 | startColor.r = 0.76f; | ||
248 | startColor.g = 0.25f; | ||
249 | startColor.b = 0.12f; | ||
250 | startColor.a = 1.0f; | ||
251 | startColorVar.r = 0.0f; | ||
252 | startColorVar.g = 0.0f; | ||
253 | startColorVar.b = 0.0f; | ||
254 | startColorVar.a = 0.0f; | ||
255 | endColor.r = 0.0f; | ||
256 | endColor.g = 0.0f; | ||
257 | endColor.b = 0.0f; | ||
258 | endColor.a = 1.0f; | ||
259 | endColorVar.r = 0.0f; | ||
260 | endColorVar.g = 0.0f; | ||
261 | endColorVar.b = 0.0f; | ||
262 | endColorVar.a = 0.0f; | ||
263 | |||
264 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
265 | } | ||
266 | |||
267 | return self; | ||
268 | } | ||
269 | @end | ||
270 | |||
271 | // | ||
272 | // ParticleGalaxy | ||
273 | // | ||
274 | @implementation CCParticleGalaxy | ||
275 | -(id) init | ||
276 | { | ||
277 | return [self initWithTotalParticles:200]; | ||
278 | } | ||
279 | |||
280 | -(id) initWithTotalParticles:(NSUInteger)p | ||
281 | { | ||
282 | if( (self=[super initWithTotalParticles:p]) ) { | ||
283 | |||
284 | // duration | ||
285 | duration = kCCParticleDurationInfinity; | ||
286 | |||
287 | // Gravity Mode | ||
288 | self.emitterMode = kCCParticleModeGravity; | ||
289 | |||
290 | // Gravity Mode: gravity | ||
291 | self.gravity = ccp(0,0); | ||
292 | |||
293 | // Gravity Mode: speed of particles | ||
294 | self.speed = 60; | ||
295 | self.speedVar = 10; | ||
296 | |||
297 | // Gravity Mode: radial | ||
298 | self.radialAccel = -80; | ||
299 | self.radialAccelVar = 0; | ||
300 | |||
301 | // Gravity Mode: tagential | ||
302 | self.tangentialAccel = 80; | ||
303 | self.tangentialAccelVar = 0; | ||
304 | |||
305 | // angle | ||
306 | angle = 90; | ||
307 | angleVar = 360; | ||
308 | |||
309 | // emitter position | ||
310 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
311 | self.position = ccp(winSize.width/2, winSize.height/2); | ||
312 | posVar = CGPointZero; | ||
313 | |||
314 | // life of particles | ||
315 | life = 4; | ||
316 | lifeVar = 1; | ||
317 | |||
318 | // size, in pixels | ||
319 | startSize = 37.0f; | ||
320 | startSizeVar = 10.0f; | ||
321 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
322 | |||
323 | // emits per second | ||
324 | emissionRate = totalParticles/life; | ||
325 | |||
326 | // color of particles | ||
327 | startColor.r = 0.12f; | ||
328 | startColor.g = 0.25f; | ||
329 | startColor.b = 0.76f; | ||
330 | startColor.a = 1.0f; | ||
331 | startColorVar.r = 0.0f; | ||
332 | startColorVar.g = 0.0f; | ||
333 | startColorVar.b = 0.0f; | ||
334 | startColorVar.a = 0.0f; | ||
335 | endColor.r = 0.0f; | ||
336 | endColor.g = 0.0f; | ||
337 | endColor.b = 0.0f; | ||
338 | endColor.a = 1.0f; | ||
339 | endColorVar.r = 0.0f; | ||
340 | endColorVar.g = 0.0f; | ||
341 | endColorVar.b = 0.0f; | ||
342 | endColorVar.a = 0.0f; | ||
343 | |||
344 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
345 | |||
346 | // additive | ||
347 | self.blendAdditive = YES; | ||
348 | } | ||
349 | |||
350 | return self; | ||
351 | } | ||
352 | @end | ||
353 | |||
354 | // | ||
355 | // ParticleFlower | ||
356 | // | ||
357 | @implementation CCParticleFlower | ||
358 | -(id) init | ||
359 | { | ||
360 | return [self initWithTotalParticles:250]; | ||
361 | } | ||
362 | |||
363 | -(id) initWithTotalParticles:(NSUInteger) p | ||
364 | { | ||
365 | if( (self=[super initWithTotalParticles:p]) ) { | ||
366 | |||
367 | // duration | ||
368 | duration = kCCParticleDurationInfinity; | ||
369 | |||
370 | // Gravity Mode | ||
371 | self.emitterMode = kCCParticleModeGravity; | ||
372 | |||
373 | // Gravity Mode: gravity | ||
374 | self.gravity = ccp(0,0); | ||
375 | |||
376 | // Gravity Mode: speed of particles | ||
377 | self.speed = 80; | ||
378 | self.speedVar = 10; | ||
379 | |||
380 | // Gravity Mode: radial | ||
381 | self.radialAccel = -60; | ||
382 | self.radialAccelVar = 0; | ||
383 | |||
384 | // Gravity Mode: tagential | ||
385 | self.tangentialAccel = 15; | ||
386 | self.tangentialAccelVar = 0; | ||
387 | |||
388 | // angle | ||
389 | angle = 90; | ||
390 | angleVar = 360; | ||
391 | |||
392 | // emitter position | ||
393 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
394 | self.position = ccp(winSize.width/2, winSize.height/2); | ||
395 | posVar = CGPointZero; | ||
396 | |||
397 | // life of particles | ||
398 | life = 4; | ||
399 | lifeVar = 1; | ||
400 | |||
401 | // size, in pixels | ||
402 | startSize = 30.0f; | ||
403 | startSizeVar = 10.0f; | ||
404 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
405 | |||
406 | // emits per second | ||
407 | emissionRate = totalParticles/life; | ||
408 | |||
409 | // color of particles | ||
410 | startColor.r = 0.50f; | ||
411 | startColor.g = 0.50f; | ||
412 | startColor.b = 0.50f; | ||
413 | startColor.a = 1.0f; | ||
414 | startColorVar.r = 0.5f; | ||
415 | startColorVar.g = 0.5f; | ||
416 | startColorVar.b = 0.5f; | ||
417 | startColorVar.a = 0.5f; | ||
418 | endColor.r = 0.0f; | ||
419 | endColor.g = 0.0f; | ||
420 | endColor.b = 0.0f; | ||
421 | endColor.a = 1.0f; | ||
422 | endColorVar.r = 0.0f; | ||
423 | endColorVar.g = 0.0f; | ||
424 | endColorVar.b = 0.0f; | ||
425 | endColorVar.a = 0.0f; | ||
426 | |||
427 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
428 | |||
429 | // additive | ||
430 | self.blendAdditive = YES; | ||
431 | } | ||
432 | |||
433 | return self; | ||
434 | } | ||
435 | @end | ||
436 | |||
437 | // | ||
438 | // ParticleMeteor | ||
439 | // | ||
440 | @implementation CCParticleMeteor | ||
441 | -(id) init | ||
442 | { | ||
443 | return [self initWithTotalParticles:150]; | ||
444 | } | ||
445 | |||
446 | -(id) initWithTotalParticles:(NSUInteger) p | ||
447 | { | ||
448 | if( (self=[super initWithTotalParticles:p]) ) { | ||
449 | |||
450 | // duration | ||
451 | duration = kCCParticleDurationInfinity; | ||
452 | |||
453 | // Gravity Mode | ||
454 | self.emitterMode = kCCParticleModeGravity; | ||
455 | |||
456 | // Gravity Mode: gravity | ||
457 | self.gravity = ccp(-200,200); | ||
458 | |||
459 | // Gravity Mode: speed of particles | ||
460 | self.speed = 15; | ||
461 | self.speedVar = 5; | ||
462 | |||
463 | // Gravity Mode: radial | ||
464 | self.radialAccel = 0; | ||
465 | self.radialAccelVar = 0; | ||
466 | |||
467 | // Gravity Mode: tagential | ||
468 | self.tangentialAccel = 0; | ||
469 | self.tangentialAccelVar = 0; | ||
470 | |||
471 | // angle | ||
472 | angle = 90; | ||
473 | angleVar = 360; | ||
474 | |||
475 | // emitter position | ||
476 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
477 | self.position = ccp(winSize.width/2, winSize.height/2); | ||
478 | posVar = CGPointZero; | ||
479 | |||
480 | // life of particles | ||
481 | life = 2; | ||
482 | lifeVar = 1; | ||
483 | |||
484 | // size, in pixels | ||
485 | startSize = 60.0f; | ||
486 | startSizeVar = 10.0f; | ||
487 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
488 | |||
489 | // emits per second | ||
490 | emissionRate = totalParticles/life; | ||
491 | |||
492 | // color of particles | ||
493 | startColor.r = 0.2f; | ||
494 | startColor.g = 0.4f; | ||
495 | startColor.b = 0.7f; | ||
496 | startColor.a = 1.0f; | ||
497 | startColorVar.r = 0.0f; | ||
498 | startColorVar.g = 0.0f; | ||
499 | startColorVar.b = 0.2f; | ||
500 | startColorVar.a = 0.1f; | ||
501 | endColor.r = 0.0f; | ||
502 | endColor.g = 0.0f; | ||
503 | endColor.b = 0.0f; | ||
504 | endColor.a = 1.0f; | ||
505 | endColorVar.r = 0.0f; | ||
506 | endColorVar.g = 0.0f; | ||
507 | endColorVar.b = 0.0f; | ||
508 | endColorVar.a = 0.0f; | ||
509 | |||
510 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
511 | |||
512 | // additive | ||
513 | self.blendAdditive = YES; | ||
514 | } | ||
515 | |||
516 | return self; | ||
517 | } | ||
518 | @end | ||
519 | |||
520 | // | ||
521 | // ParticleSpiral | ||
522 | // | ||
523 | @implementation CCParticleSpiral | ||
524 | -(id) init | ||
525 | { | ||
526 | return [self initWithTotalParticles:500]; | ||
527 | } | ||
528 | |||
529 | -(id) initWithTotalParticles:(NSUInteger) p | ||
530 | { | ||
531 | if( (self=[super initWithTotalParticles:p]) ) { | ||
532 | |||
533 | // duration | ||
534 | duration = kCCParticleDurationInfinity; | ||
535 | |||
536 | // Gravity Mode | ||
537 | self.emitterMode = kCCParticleModeGravity; | ||
538 | |||
539 | // Gravity Mode: gravity | ||
540 | self.gravity = ccp(0,0); | ||
541 | |||
542 | // Gravity Mode: speed of particles | ||
543 | self.speed = 150; | ||
544 | self.speedVar = 0; | ||
545 | |||
546 | // Gravity Mode: radial | ||
547 | self.radialAccel = -380; | ||
548 | self.radialAccelVar = 0; | ||
549 | |||
550 | // Gravity Mode: tagential | ||
551 | self.tangentialAccel = 45; | ||
552 | self.tangentialAccelVar = 0; | ||
553 | |||
554 | // angle | ||
555 | angle = 90; | ||
556 | angleVar = 0; | ||
557 | |||
558 | // emitter position | ||
559 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
560 | self.position = ccp(winSize.width/2, winSize.height/2); | ||
561 | posVar = CGPointZero; | ||
562 | |||
563 | // life of particles | ||
564 | life = 12; | ||
565 | lifeVar = 0; | ||
566 | |||
567 | // size, in pixels | ||
568 | startSize = 20.0f; | ||
569 | startSizeVar = 0.0f; | ||
570 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
571 | |||
572 | // emits per second | ||
573 | emissionRate = totalParticles/life; | ||
574 | |||
575 | // color of particles | ||
576 | startColor.r = 0.5f; | ||
577 | startColor.g = 0.5f; | ||
578 | startColor.b = 0.5f; | ||
579 | startColor.a = 1.0f; | ||
580 | startColorVar.r = 0.5f; | ||
581 | startColorVar.g = 0.5f; | ||
582 | startColorVar.b = 0.5f; | ||
583 | startColorVar.a = 0.0f; | ||
584 | endColor.r = 0.5f; | ||
585 | endColor.g = 0.5f; | ||
586 | endColor.b = 0.5f; | ||
587 | endColor.a = 1.0f; | ||
588 | endColorVar.r = 0.5f; | ||
589 | endColorVar.g = 0.5f; | ||
590 | endColorVar.b = 0.5f; | ||
591 | endColorVar.a = 0.0f; | ||
592 | |||
593 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
594 | |||
595 | // additive | ||
596 | self.blendAdditive = NO; | ||
597 | } | ||
598 | |||
599 | return self; | ||
600 | } | ||
601 | @end | ||
602 | |||
603 | // | ||
604 | // ParticleExplosion | ||
605 | // | ||
606 | @implementation CCParticleExplosion | ||
607 | -(id) init | ||
608 | { | ||
609 | return [self initWithTotalParticles:700]; | ||
610 | } | ||
611 | |||
612 | -(id) initWithTotalParticles:(NSUInteger)p | ||
613 | { | ||
614 | if( (self=[super initWithTotalParticles:p]) ) { | ||
615 | |||
616 | // duration | ||
617 | duration = 0.1f; | ||
618 | |||
619 | self.emitterMode = kCCParticleModeGravity; | ||
620 | |||
621 | // Gravity Mode: gravity | ||
622 | self.gravity = ccp(0,0); | ||
623 | |||
624 | // Gravity Mode: speed of particles | ||
625 | self.speed = 70; | ||
626 | self.speedVar = 40; | ||
627 | |||
628 | // Gravity Mode: radial | ||
629 | self.radialAccel = 0; | ||
630 | self.radialAccelVar = 0; | ||
631 | |||
632 | // Gravity Mode: tagential | ||
633 | self.tangentialAccel = 0; | ||
634 | self.tangentialAccelVar = 0; | ||
635 | |||
636 | // angle | ||
637 | angle = 90; | ||
638 | angleVar = 360; | ||
639 | |||
640 | // emitter position | ||
641 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
642 | self.position = ccp(winSize.width/2, winSize.height/2); | ||
643 | posVar = CGPointZero; | ||
644 | |||
645 | // life of particles | ||
646 | life = 5.0f; | ||
647 | lifeVar = 2; | ||
648 | |||
649 | // size, in pixels | ||
650 | startSize = 15.0f; | ||
651 | startSizeVar = 10.0f; | ||
652 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
653 | |||
654 | // emits per second | ||
655 | emissionRate = totalParticles/duration; | ||
656 | |||
657 | // color of particles | ||
658 | startColor.r = 0.7f; | ||
659 | startColor.g = 0.1f; | ||
660 | startColor.b = 0.2f; | ||
661 | startColor.a = 1.0f; | ||
662 | startColorVar.r = 0.5f; | ||
663 | startColorVar.g = 0.5f; | ||
664 | startColorVar.b = 0.5f; | ||
665 | startColorVar.a = 0.0f; | ||
666 | endColor.r = 0.5f; | ||
667 | endColor.g = 0.5f; | ||
668 | endColor.b = 0.5f; | ||
669 | endColor.a = 0.0f; | ||
670 | endColorVar.r = 0.5f; | ||
671 | endColorVar.g = 0.5f; | ||
672 | endColorVar.b = 0.5f; | ||
673 | endColorVar.a = 0.0f; | ||
674 | |||
675 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
676 | |||
677 | // additive | ||
678 | self.blendAdditive = NO; | ||
679 | } | ||
680 | |||
681 | return self; | ||
682 | } | ||
683 | @end | ||
684 | |||
685 | // | ||
686 | // ParticleSmoke | ||
687 | // | ||
688 | @implementation CCParticleSmoke | ||
689 | -(id) init | ||
690 | { | ||
691 | return [self initWithTotalParticles:200]; | ||
692 | } | ||
693 | |||
694 | -(id) initWithTotalParticles:(NSUInteger) p | ||
695 | { | ||
696 | if( (self=[super initWithTotalParticles:p]) ) { | ||
697 | |||
698 | // duration | ||
699 | duration = kCCParticleDurationInfinity; | ||
700 | |||
701 | // Emitter mode: Gravity Mode | ||
702 | self.emitterMode = kCCParticleModeGravity; | ||
703 | |||
704 | // Gravity Mode: gravity | ||
705 | self.gravity = ccp(0,0); | ||
706 | |||
707 | // Gravity Mode: radial acceleration | ||
708 | self.radialAccel = 0; | ||
709 | self.radialAccelVar = 0; | ||
710 | |||
711 | // Gravity Mode: speed of particles | ||
712 | self.speed = 25; | ||
713 | self.speedVar = 10; | ||
714 | |||
715 | // angle | ||
716 | angle = 90; | ||
717 | angleVar = 5; | ||
718 | |||
719 | // emitter position | ||
720 | CGSize winSize = [[CCDirector sharedDirector] winSize]; | ||
721 | self.position = ccp(winSize.width/2, 0); | ||
722 | posVar = ccp(20, 0); | ||
723 | |||
724 | // life of particles | ||
725 | life = 4; | ||
726 | lifeVar = 1; | ||
727 | |||
728 | // size, in pixels | ||
729 | startSize = 60.0f; | ||
730 | startSizeVar = 10.0f; | ||
731 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
732 | |||
733 | // emits per frame | ||
734 | emissionRate = totalParticles/life; | ||
735 | |||
736 | // color of particles | ||
737 | startColor.r = 0.8f; | ||
738 | startColor.g = 0.8f; | ||
739 | startColor.b = 0.8f; | ||
740 | startColor.a = 1.0f; | ||
741 | startColorVar.r = 0.02f; | ||
742 | startColorVar.g = 0.02f; | ||
743 | startColorVar.b = 0.02f; | ||
744 | startColorVar.a = 0.0f; | ||
745 | endColor.r = 0.0f; | ||
746 | endColor.g = 0.0f; | ||
747 | endColor.b = 0.0f; | ||
748 | endColor.a = 1.0f; | ||
749 | endColorVar.r = 0.0f; | ||
750 | endColorVar.g = 0.0f; | ||
751 | endColorVar.b = 0.0f; | ||
752 | endColorVar.a = 0.0f; | ||
753 | |||
754 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
755 | |||
756 | // additive | ||
757 | self.blendAdditive = NO; | ||
758 | } | ||
759 | |||
760 | return self; | ||
761 | } | ||
762 | @end | ||
763 | |||
764 | @implementation CCParticleSnow | ||
765 | -(id) init | ||
766 | { | ||
767 | return [self initWithTotalParticles:700]; | ||
768 | } | ||
769 | |||
770 | -(id) initWithTotalParticles:(NSUInteger)p | ||
771 | { | ||
772 | if( (self=[super initWithTotalParticles:p]) ) { | ||
773 | |||
774 | // duration | ||
775 | duration = kCCParticleDurationInfinity; | ||
776 | |||
777 | // set gravity mode. | ||
778 | self.emitterMode = kCCParticleModeGravity; | ||
779 | |||
780 | // Gravity Mode: gravity | ||
781 | self.gravity = ccp(0,-1); | ||
782 | |||
783 | // Gravity Mode: speed of particles | ||
784 | self.speed = 5; | ||
785 | self.speedVar = 1; | ||
786 | |||
787 | // Gravity Mode: radial | ||
788 | self.radialAccel = 0; | ||
789 | self.radialAccelVar = 1; | ||
790 | |||
791 | // Gravity mode: tagential | ||
792 | self.tangentialAccel = 0; | ||
793 | self.tangentialAccelVar = 1; | ||
794 | |||
795 | // emitter position | ||
796 | self.position = (CGPoint) { | ||
797 | [[CCDirector sharedDirector] winSize].width / 2, | ||
798 | [[CCDirector sharedDirector] winSize].height + 10 | ||
799 | }; | ||
800 | posVar = ccp( [[CCDirector sharedDirector] winSize].width / 2, 0 ); | ||
801 | |||
802 | // angle | ||
803 | angle = -90; | ||
804 | angleVar = 5; | ||
805 | |||
806 | // life of particles | ||
807 | life = 45; | ||
808 | lifeVar = 15; | ||
809 | |||
810 | // size, in pixels | ||
811 | startSize = 10.0f; | ||
812 | startSizeVar = 5.0f; | ||
813 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
814 | |||
815 | // emits per second | ||
816 | emissionRate = 10; | ||
817 | |||
818 | // color of particles | ||
819 | startColor.r = 1.0f; | ||
820 | startColor.g = 1.0f; | ||
821 | startColor.b = 1.0f; | ||
822 | startColor.a = 1.0f; | ||
823 | startColorVar.r = 0.0f; | ||
824 | startColorVar.g = 0.0f; | ||
825 | startColorVar.b = 0.0f; | ||
826 | startColorVar.a = 0.0f; | ||
827 | endColor.r = 1.0f; | ||
828 | endColor.g = 1.0f; | ||
829 | endColor.b = 1.0f; | ||
830 | endColor.a = 0.0f; | ||
831 | endColorVar.r = 0.0f; | ||
832 | endColorVar.g = 0.0f; | ||
833 | endColorVar.b = 0.0f; | ||
834 | endColorVar.a = 0.0f; | ||
835 | |||
836 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
837 | |||
838 | // additive | ||
839 | self.blendAdditive = NO; | ||
840 | } | ||
841 | |||
842 | return self; | ||
843 | } | ||
844 | @end | ||
845 | |||
846 | @implementation CCParticleRain | ||
847 | -(id) init | ||
848 | { | ||
849 | return [self initWithTotalParticles:1000]; | ||
850 | } | ||
851 | |||
852 | -(id) initWithTotalParticles:(NSUInteger)p | ||
853 | { | ||
854 | if( (self=[super initWithTotalParticles:p]) ) { | ||
855 | |||
856 | // duration | ||
857 | duration = kCCParticleDurationInfinity; | ||
858 | |||
859 | self.emitterMode = kCCParticleModeGravity; | ||
860 | |||
861 | // Gravity Mode: gravity | ||
862 | self.gravity = ccp(10,-10); | ||
863 | |||
864 | // Gravity Mode: radial | ||
865 | self.radialAccel = 0; | ||
866 | self.radialAccelVar = 1; | ||
867 | |||
868 | // Gravity Mode: tagential | ||
869 | self.tangentialAccel = 0; | ||
870 | self.tangentialAccelVar = 1; | ||
871 | |||
872 | // Gravity Mode: speed of particles | ||
873 | self.speed = 130; | ||
874 | self.speedVar = 30; | ||
875 | |||
876 | // angle | ||
877 | angle = -90; | ||
878 | angleVar = 5; | ||
879 | |||
880 | |||
881 | // emitter position | ||
882 | self.position = (CGPoint) { | ||
883 | [[CCDirector sharedDirector] winSize].width / 2, | ||
884 | [[CCDirector sharedDirector] winSize].height | ||
885 | }; | ||
886 | posVar = ccp( [[CCDirector sharedDirector] winSize].width / 2, 0 ); | ||
887 | |||
888 | // life of particles | ||
889 | life = 4.5f; | ||
890 | lifeVar = 0; | ||
891 | |||
892 | // size, in pixels | ||
893 | startSize = 4.0f; | ||
894 | startSizeVar = 2.0f; | ||
895 | endSize = kCCParticleStartSizeEqualToEndSize; | ||
896 | |||
897 | // emits per second | ||
898 | emissionRate = 20; | ||
899 | |||
900 | // color of particles | ||
901 | startColor.r = 0.7f; | ||
902 | startColor.g = 0.8f; | ||
903 | startColor.b = 1.0f; | ||
904 | startColor.a = 1.0f; | ||
905 | startColorVar.r = 0.0f; | ||
906 | startColorVar.g = 0.0f; | ||
907 | startColorVar.b = 0.0f; | ||
908 | startColorVar.a = 0.0f; | ||
909 | endColor.r = 0.7f; | ||
910 | endColor.g = 0.8f; | ||
911 | endColor.b = 1.0f; | ||
912 | endColor.a = 0.5f; | ||
913 | endColorVar.r = 0.0f; | ||
914 | endColorVar.g = 0.0f; | ||
915 | endColorVar.b = 0.0f; | ||
916 | endColorVar.a = 0.0f; | ||
917 | |||
918 | self.texture = [[CCTextureCache sharedTextureCache] addImage: @"fire.png"]; | ||
919 | |||
920 | // additive | ||
921 | self.blendAdditive = NO; | ||
922 | } | ||
923 | |||
924 | return self; | ||
925 | } | ||
926 | @end | ||
diff --git a/libs/cocos2d/CCParticleSystem.h b/libs/cocos2d/CCParticleSystem.h new file mode 100755 index 0000000..429e814 --- /dev/null +++ b/libs/cocos2d/CCParticleSystem.h | |||
@@ -0,0 +1,445 @@ | |||
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 | #import "CCProtocols.h" | ||
29 | #import "CCNode.h" | ||
30 | #import "ccTypes.h" | ||
31 | #import "ccConfig.h" | ||
32 | |||
33 | #if CC_ENABLE_PROFILERS | ||
34 | @class CCProfilingTimer; | ||
35 | #endif | ||
36 | |||
37 | //* @enum | ||
38 | enum { | ||
39 | /** The Particle emitter lives forever */ | ||
40 | kCCParticleDurationInfinity = -1, | ||
41 | |||
42 | /** The starting size of the particle is equal to the ending size */ | ||
43 | kCCParticleStartSizeEqualToEndSize = -1, | ||
44 | |||
45 | /** The starting radius of the particle is equal to the ending radius */ | ||
46 | kCCParticleStartRadiusEqualToEndRadius = -1, | ||
47 | |||
48 | // backward compatible | ||
49 | kParticleStartSizeEqualToEndSize = kCCParticleStartSizeEqualToEndSize, | ||
50 | kParticleDurationInfinity = kCCParticleDurationInfinity, | ||
51 | }; | ||
52 | |||
53 | //* @enum | ||
54 | enum { | ||
55 | /** Gravity mode (A mode) */ | ||
56 | kCCParticleModeGravity, | ||
57 | |||
58 | /** Radius mode (B mode) */ | ||
59 | kCCParticleModeRadius, | ||
60 | }; | ||
61 | |||
62 | |||
63 | /** @typedef tCCPositionType | ||
64 | possible types of particle positions | ||
65 | */ | ||
66 | typedef enum { | ||
67 | /** Living particles are attached to the world and are unaffected by emitter repositioning. */ | ||
68 | kCCPositionTypeFree, | ||
69 | |||
70 | /** Living particles are attached to the world but will follow the emitter repositioning. | ||
71 | Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite. | ||
72 | */ | ||
73 | kCCPositionTypeRelative, | ||
74 | |||
75 | /** Living particles are attached to the emitter and are translated along with it. */ | ||
76 | kCCPositionTypeGrouped, | ||
77 | }tCCPositionType; | ||
78 | |||
79 | // backward compatible | ||
80 | enum { | ||
81 | kPositionTypeFree = kCCPositionTypeFree, | ||
82 | kPositionTypeGrouped = kCCPositionTypeGrouped, | ||
83 | }; | ||
84 | |||
85 | /** @struct tCCParticle | ||
86 | Structure that contains the values of each particle | ||
87 | */ | ||
88 | typedef struct sCCParticle { | ||
89 | CGPoint pos; | ||
90 | CGPoint startPos; | ||
91 | |||
92 | ccColor4F color; | ||
93 | ccColor4F deltaColor; | ||
94 | |||
95 | float size; | ||
96 | float deltaSize; | ||
97 | |||
98 | float rotation; | ||
99 | float deltaRotation; | ||
100 | |||
101 | ccTime timeToLive; | ||
102 | |||
103 | union { | ||
104 | // Mode A: gravity, direction, radial accel, tangential accel | ||
105 | struct { | ||
106 | CGPoint dir; | ||
107 | float radialAccel; | ||
108 | float tangentialAccel; | ||
109 | } A; | ||
110 | |||
111 | // Mode B: radius mode | ||
112 | struct { | ||
113 | float angle; | ||
114 | float degreesPerSecond; | ||
115 | float radius; | ||
116 | float deltaRadius; | ||
117 | } B; | ||
118 | } mode; | ||
119 | |||
120 | }tCCParticle; | ||
121 | |||
122 | typedef void (*CC_UPDATE_PARTICLE_IMP)(id, SEL, tCCParticle*, CGPoint); | ||
123 | |||
124 | @class CCTexture2D; | ||
125 | |||
126 | /** Particle System base class | ||
127 | Attributes of a Particle System: | ||
128 | - emmision rate of the particles | ||
129 | - Gravity Mode (Mode A): | ||
130 | - gravity | ||
131 | - direction | ||
132 | - speed +- variance | ||
133 | - tangential acceleration +- variance | ||
134 | - radial acceleration +- variance | ||
135 | - Radius Mode (Mode B): | ||
136 | - startRadius +- variance | ||
137 | - endRadius +- variance | ||
138 | - rotate +- variance | ||
139 | - Properties common to all modes: | ||
140 | - life +- life variance | ||
141 | - start spin +- variance | ||
142 | - end spin +- variance | ||
143 | - start size +- variance | ||
144 | - end size +- variance | ||
145 | - start color +- variance | ||
146 | - end color +- variance | ||
147 | - life +- variance | ||
148 | - blending function | ||
149 | - texture | ||
150 | |||
151 | cocos2d also supports particles generated by Particle Designer (http://particledesigner.71squared.com/). | ||
152 | 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d, | ||
153 | cocos2d uses a another approach, but the results are almost identical. | ||
154 | |||
155 | cocos2d supports all the variables used by Particle Designer plus a bit more: | ||
156 | - spinning particles (supported when using CCParticleSystemQuad) | ||
157 | - tangential acceleration (Gravity mode) | ||
158 | - radial acceleration (Gravity mode) | ||
159 | - radius direction (Radius mode) (Particle Designer supports outwards to inwards direction only) | ||
160 | |||
161 | It is possible to customize any of the above mentioned properties in runtime. Example: | ||
162 | |||
163 | @code | ||
164 | emitter.radialAccel = 15; | ||
165 | emitter.startSpin = 0; | ||
166 | @endcode | ||
167 | |||
168 | */ | ||
169 | @interface CCParticleSystem : CCNode <CCTextureProtocol> | ||
170 | { | ||
171 | // is the particle system active ? | ||
172 | BOOL active; | ||
173 | // duration in seconds of the system. -1 is infinity | ||
174 | float duration; | ||
175 | // time elapsed since the start of the system (in seconds) | ||
176 | float elapsed; | ||
177 | |||
178 | // position is from "superclass" CocosNode | ||
179 | CGPoint sourcePosition; | ||
180 | // Position variance | ||
181 | CGPoint posVar; | ||
182 | |||
183 | // The angle (direction) of the particles measured in degrees | ||
184 | float angle; | ||
185 | // Angle variance measured in degrees; | ||
186 | float angleVar; | ||
187 | |||
188 | // Different modes | ||
189 | |||
190 | NSInteger emitterMode_; | ||
191 | union { | ||
192 | // Mode A:Gravity + Tangential Accel + Radial Accel | ||
193 | struct { | ||
194 | // gravity of the particles | ||
195 | CGPoint gravity; | ||
196 | |||
197 | // The speed the particles will have. | ||
198 | float speed; | ||
199 | // The speed variance | ||
200 | float speedVar; | ||
201 | |||
202 | // Tangential acceleration | ||
203 | float tangentialAccel; | ||
204 | // Tangential acceleration variance | ||
205 | float tangentialAccelVar; | ||
206 | |||
207 | // Radial acceleration | ||
208 | float radialAccel; | ||
209 | // Radial acceleration variance | ||
210 | float radialAccelVar; | ||
211 | } A; | ||
212 | |||
213 | // Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode) | ||
214 | struct { | ||
215 | |||
216 | // The starting radius of the particles | ||
217 | float startRadius; | ||
218 | // The starting radius variance of the particles | ||
219 | float startRadiusVar; | ||
220 | // The ending radius of the particles | ||
221 | float endRadius; | ||
222 | // The ending radius variance of the particles | ||
223 | float endRadiusVar; | ||
224 | // Number of degress to rotate a particle around the source pos per second | ||
225 | float rotatePerSecond; | ||
226 | // Variance in degrees for rotatePerSecond | ||
227 | float rotatePerSecondVar; | ||
228 | } B; | ||
229 | } mode; | ||
230 | |||
231 | // start ize of the particles | ||
232 | float startSize; | ||
233 | // start Size variance | ||
234 | float startSizeVar; | ||
235 | // End size of the particle | ||
236 | float endSize; | ||
237 | // end size of variance | ||
238 | float endSizeVar; | ||
239 | |||
240 | // How many seconds will the particle live | ||
241 | float life; | ||
242 | // Life variance | ||
243 | float lifeVar; | ||
244 | |||
245 | // Start color of the particles | ||
246 | ccColor4F startColor; | ||
247 | // Start color variance | ||
248 | ccColor4F startColorVar; | ||
249 | // End color of the particles | ||
250 | ccColor4F endColor; | ||
251 | // End color variance | ||
252 | ccColor4F endColorVar; | ||
253 | |||
254 | // start angle of the particles | ||
255 | float startSpin; | ||
256 | // start angle variance | ||
257 | float startSpinVar; | ||
258 | // End angle of the particle | ||
259 | float endSpin; | ||
260 | // end angle ariance | ||
261 | float endSpinVar; | ||
262 | |||
263 | |||
264 | // Array of particles | ||
265 | tCCParticle *particles; | ||
266 | // Maximum particles | ||
267 | NSUInteger totalParticles; | ||
268 | // Count of active particles | ||
269 | NSUInteger particleCount; | ||
270 | |||
271 | // color modulate | ||
272 | // BOOL colorModulate; | ||
273 | |||
274 | // How many particles can be emitted per second | ||
275 | float emissionRate; | ||
276 | float emitCounter; | ||
277 | |||
278 | // Texture of the particles | ||
279 | CCTexture2D *texture_; | ||
280 | // blend function | ||
281 | ccBlendFunc blendFunc_; | ||
282 | |||
283 | // movment type: free or grouped | ||
284 | tCCPositionType positionType_; | ||
285 | |||
286 | // Whether or not the node will be auto-removed when there are not particles | ||
287 | BOOL autoRemoveOnFinish_; | ||
288 | |||
289 | // particle idx | ||
290 | NSUInteger particleIdx; | ||
291 | |||
292 | // Optimization | ||
293 | CC_UPDATE_PARTICLE_IMP updateParticleImp; | ||
294 | SEL updateParticleSel; | ||
295 | |||
296 | // profiling | ||
297 | #if CC_ENABLE_PROFILERS | ||
298 | CCProfilingTimer* _profilingTimer; | ||
299 | #endif | ||
300 | } | ||
301 | |||
302 | /** Is the emitter active */ | ||
303 | @property (nonatomic,readonly) BOOL active; | ||
304 | /** Quantity of particles that are being simulated at the moment */ | ||
305 | @property (nonatomic,readonly) NSUInteger particleCount; | ||
306 | /** How many seconds the emitter wil run. -1 means 'forever' */ | ||
307 | @property (nonatomic,readwrite,assign) float duration; | ||
308 | /** sourcePosition of the emitter */ | ||
309 | @property (nonatomic,readwrite,assign) CGPoint sourcePosition; | ||
310 | /** Position variance of the emitter */ | ||
311 | @property (nonatomic,readwrite,assign) CGPoint posVar; | ||
312 | /** life, and life variation of each particle */ | ||
313 | @property (nonatomic,readwrite,assign) float life; | ||
314 | /** life variance of each particle */ | ||
315 | @property (nonatomic,readwrite,assign) float lifeVar; | ||
316 | /** angle and angle variation of each particle */ | ||
317 | @property (nonatomic,readwrite,assign) float angle; | ||
318 | /** angle variance of each particle */ | ||
319 | @property (nonatomic,readwrite,assign) float angleVar; | ||
320 | |||
321 | /** Gravity value. Only available in 'Gravity' mode. */ | ||
322 | @property (nonatomic,readwrite,assign) CGPoint gravity; | ||
323 | /** speed of each particle. Only available in 'Gravity' mode. */ | ||
324 | @property (nonatomic,readwrite,assign) float speed; | ||
325 | /** speed variance of each particle. Only available in 'Gravity' mode. */ | ||
326 | @property (nonatomic,readwrite,assign) float speedVar; | ||
327 | /** tangential acceleration of each particle. Only available in 'Gravity' mode. */ | ||
328 | @property (nonatomic,readwrite,assign) float tangentialAccel; | ||
329 | /** tangential acceleration variance of each particle. Only available in 'Gravity' mode. */ | ||
330 | @property (nonatomic,readwrite,assign) float tangentialAccelVar; | ||
331 | /** radial acceleration of each particle. Only available in 'Gravity' mode. */ | ||
332 | @property (nonatomic,readwrite,assign) float radialAccel; | ||
333 | /** radial acceleration variance of each particle. Only available in 'Gravity' mode. */ | ||
334 | @property (nonatomic,readwrite,assign) float radialAccelVar; | ||
335 | |||
336 | /** The starting radius of the particles. Only available in 'Radius' mode. */ | ||
337 | @property (nonatomic,readwrite,assign) float startRadius; | ||
338 | /** The starting radius variance of the particles. Only available in 'Radius' mode. */ | ||
339 | @property (nonatomic,readwrite,assign) float startRadiusVar; | ||
340 | /** The ending radius of the particles. Only available in 'Radius' mode. */ | ||
341 | @property (nonatomic,readwrite,assign) float endRadius; | ||
342 | /** The ending radius variance of the particles. Only available in 'Radius' mode. */ | ||
343 | @property (nonatomic,readwrite,assign) float endRadiusVar; | ||
344 | /** Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. */ | ||
345 | @property (nonatomic,readwrite,assign) float rotatePerSecond; | ||
346 | /** Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. */ | ||
347 | @property (nonatomic,readwrite,assign) float rotatePerSecondVar; | ||
348 | |||
349 | /** start size in pixels of each particle */ | ||
350 | @property (nonatomic,readwrite,assign) float startSize; | ||
351 | /** size variance in pixels of each particle */ | ||
352 | @property (nonatomic,readwrite,assign) float startSizeVar; | ||
353 | /** end size in pixels of each particle */ | ||
354 | @property (nonatomic,readwrite,assign) float endSize; | ||
355 | /** end size variance in pixels of each particle */ | ||
356 | @property (nonatomic,readwrite,assign) float endSizeVar; | ||
357 | /** start color of each particle */ | ||
358 | @property (nonatomic,readwrite,assign) ccColor4F startColor; | ||
359 | /** start color variance of each particle */ | ||
360 | @property (nonatomic,readwrite,assign) ccColor4F startColorVar; | ||
361 | /** end color and end color variation of each particle */ | ||
362 | @property (nonatomic,readwrite,assign) ccColor4F endColor; | ||
363 | /** end color variance of each particle */ | ||
364 | @property (nonatomic,readwrite,assign) ccColor4F endColorVar; | ||
365 | //* initial angle of each particle | ||
366 | @property (nonatomic,readwrite,assign) float startSpin; | ||
367 | //* initial angle of each particle | ||
368 | @property (nonatomic,readwrite,assign) float startSpinVar; | ||
369 | //* initial angle of each particle | ||
370 | @property (nonatomic,readwrite,assign) float endSpin; | ||
371 | //* initial angle of each particle | ||
372 | @property (nonatomic,readwrite,assign) float endSpinVar; | ||
373 | /** emission rate of the particles */ | ||
374 | @property (nonatomic,readwrite,assign) float emissionRate; | ||
375 | /** maximum particles of the system */ | ||
376 | @property (nonatomic,readwrite,assign) NSUInteger totalParticles; | ||
377 | /** conforms to CocosNodeTexture protocol */ | ||
378 | @property (nonatomic,readwrite, retain) CCTexture2D * texture; | ||
379 | /** conforms to CocosNodeTexture protocol */ | ||
380 | @property (nonatomic,readwrite) ccBlendFunc blendFunc; | ||
381 | /** whether or not the particles are using blend additive. | ||
382 | If enabled, the following blending function will be used. | ||
383 | @code | ||
384 | source blend function = GL_SRC_ALPHA; | ||
385 | dest blend function = GL_ONE; | ||
386 | @endcode | ||
387 | */ | ||
388 | @property (nonatomic,readwrite) BOOL blendAdditive; | ||
389 | /** particles movement type: Free or Grouped | ||
390 | @since v0.8 | ||
391 | */ | ||
392 | @property (nonatomic,readwrite) tCCPositionType positionType; | ||
393 | /** whether or not the node will be auto-removed when it has no particles left. | ||
394 | By default it is NO. | ||
395 | @since v0.8 | ||
396 | */ | ||
397 | @property (nonatomic,readwrite) BOOL autoRemoveOnFinish; | ||
398 | /** Switch between different kind of emitter modes: | ||
399 | - kCCParticleModeGravity: uses gravity, speed, radial and tangential acceleration | ||
400 | - kCCParticleModeRadius: uses radius movement + rotation | ||
401 | */ | ||
402 | @property (nonatomic,readwrite) NSInteger emitterMode; | ||
403 | |||
404 | /** creates an initializes a CCParticleSystem from a plist file. | ||
405 | This plist files can be creted manually or with Particle Designer: | ||
406 | http://particledesigner.71squared.com/ | ||
407 | @since v0.99.3 | ||
408 | */ | ||
409 | +(id) particleWithFile:(NSString*)plistFile; | ||
410 | |||
411 | /** initializes a CCParticleSystem from a plist file. | ||
412 | This plist files can be creted manually or with Particle Designer: | ||
413 | http://particledesigner.71squared.com/ | ||
414 | @since v0.99.3 | ||
415 | */ | ||
416 | -(id) initWithFile:(NSString*) plistFile; | ||
417 | |||
418 | /** initializes a CCQuadParticleSystem from a NSDictionary. | ||
419 | @since v0.99.3 | ||
420 | */ | ||
421 | -(id) initWithDictionary:(NSDictionary*)dictionary; | ||
422 | |||
423 | //! Initializes a system with a fixed number of particles | ||
424 | -(id) initWithTotalParticles:(NSUInteger) numberOfParticles; | ||
425 | //! Add a particle to the emitter | ||
426 | -(BOOL) addParticle; | ||
427 | //! Initializes a particle | ||
428 | -(void) initParticle: (tCCParticle*) particle; | ||
429 | //! stop emitting particles. Running particles will continue to run until they die | ||
430 | -(void) stopSystem; | ||
431 | //! Kill all living particles. | ||
432 | -(void) resetSystem; | ||
433 | //! whether or not the system is full | ||
434 | -(BOOL) isFull; | ||
435 | |||
436 | //! should be overriden by subclasses | ||
437 | -(void) updateQuadWithParticle:(tCCParticle*)particle newPosition:(CGPoint)pos; | ||
438 | //! should be overriden by subclasses | ||
439 | -(void) postStep; | ||
440 | |||
441 | //! called in every loop. | ||
442 | -(void) update: (ccTime) dt; | ||
443 | |||
444 | @end | ||
445 | |||
diff --git a/libs/cocos2d/CCParticleSystem.m b/libs/cocos2d/CCParticleSystem.m new file mode 100755 index 0000000..742676e --- /dev/null +++ b/libs/cocos2d/CCParticleSystem.m | |||
@@ -0,0 +1,808 @@ | |||
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 | // ideas taken from: | ||
29 | // . The ocean spray in your face [Jeff Lander] | ||
30 | // http://www.double.co.nz/dust/col0798.pdf | ||
31 | // . Building an Advanced Particle System [John van der Burg] | ||
32 | // http://www.gamasutra.com/features/20000623/vanderburg_01.htm | ||
33 | // . LOVE game engine | ||
34 | // http://love2d.org/ | ||
35 | // | ||
36 | // | ||
37 | // Radius mode support, from 71 squared | ||
38 | // http://particledesigner.71squared.com/ | ||
39 | // | ||
40 | // IMPORTANT: Particle Designer is supported by cocos2d, but | ||
41 | // 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d, | ||
42 | // cocos2d uses a another approach, but the results are almost identical. | ||
43 | // | ||
44 | |||
45 | // opengl | ||
46 | #import "Platforms/CCGL.h" | ||
47 | |||
48 | // cocos2d | ||
49 | #import "ccConfig.h" | ||
50 | #if CC_ENABLE_PROFILERS | ||
51 | #import "Support/CCProfiling.h" | ||
52 | #endif | ||
53 | #import "CCParticleSystem.h" | ||
54 | #import "CCTextureCache.h" | ||
55 | #import "ccMacros.h" | ||
56 | |||
57 | // support | ||
58 | #import "Support/OpenGL_Internal.h" | ||
59 | #import "Support/CGPointExtension.h" | ||
60 | #import "Support/base64.h" | ||
61 | #import "Support/ZipUtils.h" | ||
62 | #import "Support/CCFileUtils.h" | ||
63 | |||
64 | @implementation CCParticleSystem | ||
65 | @synthesize active, duration; | ||
66 | @synthesize sourcePosition, posVar; | ||
67 | @synthesize particleCount; | ||
68 | @synthesize life, lifeVar; | ||
69 | @synthesize angle, angleVar; | ||
70 | @synthesize startColor, startColorVar, endColor, endColorVar; | ||
71 | @synthesize startSpin, startSpinVar, endSpin, endSpinVar; | ||
72 | @synthesize emissionRate; | ||
73 | @synthesize totalParticles; | ||
74 | @synthesize startSize, startSizeVar; | ||
75 | @synthesize endSize, endSizeVar; | ||
76 | @synthesize blendFunc = blendFunc_; | ||
77 | @synthesize positionType = positionType_; | ||
78 | @synthesize autoRemoveOnFinish = autoRemoveOnFinish_; | ||
79 | @synthesize emitterMode = emitterMode_; | ||
80 | |||
81 | |||
82 | +(id) particleWithFile:(NSString*) plistFile | ||
83 | { | ||
84 | return [[[self alloc] initWithFile:plistFile] autorelease]; | ||
85 | } | ||
86 | |||
87 | -(id) init { | ||
88 | NSAssert(NO, @"CCParticleSystem: Init not supported."); | ||
89 | [self release]; | ||
90 | return nil; | ||
91 | } | ||
92 | |||
93 | -(id) initWithFile:(NSString *)plistFile | ||
94 | { | ||
95 | NSString *path = [CCFileUtils fullPathFromRelativePath:plistFile]; | ||
96 | NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; | ||
97 | |||
98 | NSAssert( dict != nil, @"Particles: file not found"); | ||
99 | return [self initWithDictionary:dict]; | ||
100 | } | ||
101 | |||
102 | -(id) initWithDictionary:(NSDictionary *)dictionary | ||
103 | { | ||
104 | NSUInteger maxParticles = [[dictionary valueForKey:@"maxParticles"] intValue]; | ||
105 | // self, not super | ||
106 | if ((self=[self initWithTotalParticles:maxParticles] ) ) { | ||
107 | |||
108 | // angle | ||
109 | angle = [[dictionary valueForKey:@"angle"] floatValue]; | ||
110 | angleVar = [[dictionary valueForKey:@"angleVariance"] floatValue]; | ||
111 | |||
112 | // duration | ||
113 | duration = [[dictionary valueForKey:@"duration"] floatValue]; | ||
114 | |||
115 | // blend function | ||
116 | blendFunc_.src = [[dictionary valueForKey:@"blendFuncSource"] intValue]; | ||
117 | blendFunc_.dst = [[dictionary valueForKey:@"blendFuncDestination"] intValue]; | ||
118 | |||
119 | // color | ||
120 | float r,g,b,a; | ||
121 | |||
122 | r = [[dictionary valueForKey:@"startColorRed"] floatValue]; | ||
123 | g = [[dictionary valueForKey:@"startColorGreen"] floatValue]; | ||
124 | b = [[dictionary valueForKey:@"startColorBlue"] floatValue]; | ||
125 | a = [[dictionary valueForKey:@"startColorAlpha"] floatValue]; | ||
126 | startColor = (ccColor4F) {r,g,b,a}; | ||
127 | |||
128 | r = [[dictionary valueForKey:@"startColorVarianceRed"] floatValue]; | ||
129 | g = [[dictionary valueForKey:@"startColorVarianceGreen"] floatValue]; | ||
130 | b = [[dictionary valueForKey:@"startColorVarianceBlue"] floatValue]; | ||
131 | a = [[dictionary valueForKey:@"startColorVarianceAlpha"] floatValue]; | ||
132 | startColorVar = (ccColor4F) {r,g,b,a}; | ||
133 | |||
134 | r = [[dictionary valueForKey:@"finishColorRed"] floatValue]; | ||
135 | g = [[dictionary valueForKey:@"finishColorGreen"] floatValue]; | ||
136 | b = [[dictionary valueForKey:@"finishColorBlue"] floatValue]; | ||
137 | a = [[dictionary valueForKey:@"finishColorAlpha"] floatValue]; | ||
138 | endColor = (ccColor4F) {r,g,b,a}; | ||
139 | |||
140 | r = [[dictionary valueForKey:@"finishColorVarianceRed"] floatValue]; | ||
141 | g = [[dictionary valueForKey:@"finishColorVarianceGreen"] floatValue]; | ||
142 | b = [[dictionary valueForKey:@"finishColorVarianceBlue"] floatValue]; | ||
143 | a = [[dictionary valueForKey:@"finishColorVarianceAlpha"] floatValue]; | ||
144 | endColorVar = (ccColor4F) {r,g,b,a}; | ||
145 | |||
146 | // particle size | ||
147 | startSize = [[dictionary valueForKey:@"startParticleSize"] floatValue]; | ||
148 | startSizeVar = [[dictionary valueForKey:@"startParticleSizeVariance"] floatValue]; | ||
149 | endSize = [[dictionary valueForKey:@"finishParticleSize"] floatValue]; | ||
150 | endSizeVar = [[dictionary valueForKey:@"finishParticleSizeVariance"] floatValue]; | ||
151 | |||
152 | |||
153 | // position | ||
154 | float x = [[dictionary valueForKey:@"sourcePositionx"] floatValue]; | ||
155 | float y = [[dictionary valueForKey:@"sourcePositiony"] floatValue]; | ||
156 | self.position = ccp(x,y); | ||
157 | posVar.x = [[dictionary valueForKey:@"sourcePositionVariancex"] floatValue]; | ||
158 | posVar.y = [[dictionary valueForKey:@"sourcePositionVariancey"] floatValue]; | ||
159 | |||
160 | |||
161 | // Spinning | ||
162 | startSpin = [[dictionary valueForKey:@"rotationStart"] floatValue]; | ||
163 | startSpinVar = [[dictionary valueForKey:@"rotationStartVariance"] floatValue]; | ||
164 | endSpin = [[dictionary valueForKey:@"rotationEnd"] floatValue]; | ||
165 | endSpinVar = [[dictionary valueForKey:@"rotationEndVariance"] floatValue]; | ||
166 | |||
167 | emitterMode_ = [[dictionary valueForKey:@"emitterType"] intValue]; | ||
168 | |||
169 | // Mode A: Gravity + tangential accel + radial accel | ||
170 | if( emitterMode_ == kCCParticleModeGravity ) { | ||
171 | // gravity | ||
172 | mode.A.gravity.x = [[dictionary valueForKey:@"gravityx"] floatValue]; | ||
173 | mode.A.gravity.y = [[dictionary valueForKey:@"gravityy"] floatValue]; | ||
174 | |||
175 | // | ||
176 | // speed | ||
177 | mode.A.speed = [[dictionary valueForKey:@"speed"] floatValue]; | ||
178 | mode.A.speedVar = [[dictionary valueForKey:@"speedVariance"] floatValue]; | ||
179 | |||
180 | // radial acceleration | ||
181 | NSString *tmp = [dictionary valueForKey:@"radialAcceleration"]; | ||
182 | mode.A.radialAccel = tmp ? [tmp floatValue] : 0; | ||
183 | |||
184 | tmp = [dictionary valueForKey:@"radialAccelVariance"]; | ||
185 | mode.A.radialAccelVar = tmp ? [tmp floatValue] : 0; | ||
186 | |||
187 | // tangential acceleration | ||
188 | tmp = [dictionary valueForKey:@"tangentialAcceleration"]; | ||
189 | mode.A.tangentialAccel = tmp ? [tmp floatValue] : 0; | ||
190 | |||
191 | tmp = [dictionary valueForKey:@"tangentialAccelVariance"]; | ||
192 | mode.A.tangentialAccelVar = tmp ? [tmp floatValue] : 0; | ||
193 | } | ||
194 | |||
195 | |||
196 | // or Mode B: radius movement | ||
197 | else if( emitterMode_ == kCCParticleModeRadius ) { | ||
198 | float maxRadius = [[dictionary valueForKey:@"maxRadius"] floatValue]; | ||
199 | float maxRadiusVar = [[dictionary valueForKey:@"maxRadiusVariance"] floatValue]; | ||
200 | float minRadius = [[dictionary valueForKey:@"minRadius"] floatValue]; | ||
201 | |||
202 | mode.B.startRadius = maxRadius; | ||
203 | mode.B.startRadiusVar = maxRadiusVar; | ||
204 | mode.B.endRadius = minRadius; | ||
205 | mode.B.endRadiusVar = 0; | ||
206 | mode.B.rotatePerSecond = [[dictionary valueForKey:@"rotatePerSecond"] floatValue]; | ||
207 | mode.B.rotatePerSecondVar = [[dictionary valueForKey:@"rotatePerSecondVariance"] floatValue]; | ||
208 | |||
209 | } else { | ||
210 | NSAssert( NO, @"Invalid emitterType in config file"); | ||
211 | } | ||
212 | |||
213 | // life span | ||
214 | life = [[dictionary valueForKey:@"particleLifespan"] floatValue]; | ||
215 | lifeVar = [[dictionary valueForKey:@"particleLifespanVariance"] floatValue]; | ||
216 | |||
217 | // emission Rate | ||
218 | emissionRate = totalParticles/life; | ||
219 | |||
220 | // texture | ||
221 | // Try to get the texture from the cache | ||
222 | NSString *textureName = [dictionary valueForKey:@"textureFileName"]; | ||
223 | |||
224 | CCTexture2D *tex = [[CCTextureCache sharedTextureCache] addImage:textureName]; | ||
225 | |||
226 | if( tex ) | ||
227 | self.texture = tex; | ||
228 | |||
229 | else { | ||
230 | |||
231 | NSString *textureData = [dictionary valueForKey:@"textureImageData"]; | ||
232 | NSAssert( textureData, @"CCParticleSystem: Couldn't load texture"); | ||
233 | |||
234 | // if it fails, try to get it from the base64-gzipped data | ||
235 | unsigned char *buffer = NULL; | ||
236 | int len = base64Decode((unsigned char*)[textureData UTF8String], (unsigned int)[textureData length], &buffer); | ||
237 | NSAssert( buffer != NULL, @"CCParticleSystem: error decoding textureImageData"); | ||
238 | |||
239 | unsigned char *deflated = NULL; | ||
240 | NSUInteger deflatedLen = ccInflateMemory(buffer, len, &deflated); | ||
241 | free( buffer ); | ||
242 | |||
243 | NSAssert( deflated != NULL, @"CCParticleSystem: error ungzipping textureImageData"); | ||
244 | NSData *data = [[NSData alloc] initWithBytes:deflated length:deflatedLen]; | ||
245 | |||
246 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
247 | UIImage *image = [[UIImage alloc] initWithData:data]; | ||
248 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
249 | NSBitmapImageRep *image = [[NSBitmapImageRep alloc] initWithData:data]; | ||
250 | #endif | ||
251 | |||
252 | free(deflated); deflated = NULL; | ||
253 | |||
254 | self.texture = [[CCTextureCache sharedTextureCache] addCGImage:[image CGImage] forKey:textureName]; | ||
255 | [data release]; | ||
256 | [image release]; | ||
257 | } | ||
258 | |||
259 | NSAssert( [self texture] != NULL, @"CCParticleSystem: error loading the texture"); | ||
260 | |||
261 | } | ||
262 | |||
263 | return self; | ||
264 | } | ||
265 | |||
266 | -(id) initWithTotalParticles:(NSUInteger) numberOfParticles | ||
267 | { | ||
268 | if( (self=[super init]) ) { | ||
269 | |||
270 | totalParticles = numberOfParticles; | ||
271 | |||
272 | particles = calloc( totalParticles, sizeof(tCCParticle) ); | ||
273 | |||
274 | if( ! particles ) { | ||
275 | NSLog(@"Particle system: not enough memory"); | ||
276 | [self release]; | ||
277 | return nil; | ||
278 | } | ||
279 | |||
280 | // default, active | ||
281 | active = YES; | ||
282 | |||
283 | // default blend function | ||
284 | blendFunc_ = (ccBlendFunc) { CC_BLEND_SRC, CC_BLEND_DST }; | ||
285 | |||
286 | // default movement type; | ||
287 | positionType_ = kCCPositionTypeFree; | ||
288 | |||
289 | // by default be in mode A: | ||
290 | emitterMode_ = kCCParticleModeGravity; | ||
291 | |||
292 | // default: modulate | ||
293 | // XXX: not used | ||
294 | // colorModulate = YES; | ||
295 | |||
296 | autoRemoveOnFinish_ = NO; | ||
297 | |||
298 | // profiling | ||
299 | #if CC_ENABLE_PROFILERS | ||
300 | _profilingTimer = [[CCProfiler timerWithName:@"particle system" andInstance:self] retain]; | ||
301 | #endif | ||
302 | |||
303 | // Optimization: compile udpateParticle method | ||
304 | updateParticleSel = @selector(updateQuadWithParticle:newPosition:); | ||
305 | updateParticleImp = (CC_UPDATE_PARTICLE_IMP) [self methodForSelector:updateParticleSel]; | ||
306 | |||
307 | // udpate after action in run! | ||
308 | [self scheduleUpdateWithPriority:1]; | ||
309 | |||
310 | } | ||
311 | |||
312 | return self; | ||
313 | } | ||
314 | |||
315 | -(void) dealloc | ||
316 | { | ||
317 | free( particles ); | ||
318 | |||
319 | [texture_ release]; | ||
320 | // profiling | ||
321 | #if CC_ENABLE_PROFILERS | ||
322 | [CCProfiler releaseTimer:_profilingTimer]; | ||
323 | #endif | ||
324 | |||
325 | [super dealloc]; | ||
326 | } | ||
327 | |||
328 | -(BOOL) addParticle | ||
329 | { | ||
330 | if( [self isFull] ) | ||
331 | return NO; | ||
332 | |||
333 | tCCParticle * particle = &particles[ particleCount ]; | ||
334 | |||
335 | [self initParticle: particle]; | ||
336 | particleCount++; | ||
337 | |||
338 | return YES; | ||
339 | } | ||
340 | |||
341 | -(void) initParticle: (tCCParticle*) particle | ||
342 | { | ||
343 | |||
344 | // timeToLive | ||
345 | // no negative life. prevent division by 0 | ||
346 | particle->timeToLive = life + lifeVar * CCRANDOM_MINUS1_1(); | ||
347 | particle->timeToLive = MAX(0, particle->timeToLive); | ||
348 | |||
349 | // position | ||
350 | particle->pos.x = sourcePosition.x + posVar.x * CCRANDOM_MINUS1_1(); | ||
351 | particle->pos.x *= CC_CONTENT_SCALE_FACTOR(); | ||
352 | particle->pos.y = sourcePosition.y + posVar.y * CCRANDOM_MINUS1_1(); | ||
353 | particle->pos.y *= CC_CONTENT_SCALE_FACTOR(); | ||
354 | |||
355 | // Color | ||
356 | ccColor4F start; | ||
357 | start.r = clampf( startColor.r + startColorVar.r * CCRANDOM_MINUS1_1(), 0, 1); | ||
358 | start.g = clampf( startColor.g + startColorVar.g * CCRANDOM_MINUS1_1(), 0, 1); | ||
359 | start.b = clampf( startColor.b + startColorVar.b * CCRANDOM_MINUS1_1(), 0, 1); | ||
360 | start.a = clampf( startColor.a + startColorVar.a * CCRANDOM_MINUS1_1(), 0, 1); | ||
361 | |||
362 | ccColor4F end; | ||
363 | end.r = clampf( endColor.r + endColorVar.r * CCRANDOM_MINUS1_1(), 0, 1); | ||
364 | end.g = clampf( endColor.g + endColorVar.g * CCRANDOM_MINUS1_1(), 0, 1); | ||
365 | end.b = clampf( endColor.b + endColorVar.b * CCRANDOM_MINUS1_1(), 0, 1); | ||
366 | end.a = clampf( endColor.a + endColorVar.a * CCRANDOM_MINUS1_1(), 0, 1); | ||
367 | |||
368 | particle->color = start; | ||
369 | particle->deltaColor.r = (end.r - start.r) / particle->timeToLive; | ||
370 | particle->deltaColor.g = (end.g - start.g) / particle->timeToLive; | ||
371 | particle->deltaColor.b = (end.b - start.b) / particle->timeToLive; | ||
372 | particle->deltaColor.a = (end.a - start.a) / particle->timeToLive; | ||
373 | |||
374 | // size | ||
375 | float startS = startSize + startSizeVar * CCRANDOM_MINUS1_1(); | ||
376 | startS = MAX(0, startS); // No negative value | ||
377 | startS *= CC_CONTENT_SCALE_FACTOR(); | ||
378 | |||
379 | particle->size = startS; | ||
380 | if( endSize == kCCParticleStartSizeEqualToEndSize ) | ||
381 | particle->deltaSize = 0; | ||
382 | else { | ||
383 | float endS = endSize + endSizeVar * CCRANDOM_MINUS1_1(); | ||
384 | endS = MAX(0, endS); // No negative values | ||
385 | endS *= CC_CONTENT_SCALE_FACTOR(); | ||
386 | particle->deltaSize = (endS - startS) / particle->timeToLive; | ||
387 | } | ||
388 | |||
389 | // rotation | ||
390 | float startA = startSpin + startSpinVar * CCRANDOM_MINUS1_1(); | ||
391 | float endA = endSpin + endSpinVar * CCRANDOM_MINUS1_1(); | ||
392 | particle->rotation = startA; | ||
393 | particle->deltaRotation = (endA - startA) / particle->timeToLive; | ||
394 | |||
395 | // position | ||
396 | if( positionType_ == kCCPositionTypeFree ) { | ||
397 | CGPoint p = [self convertToWorldSpace:CGPointZero]; | ||
398 | particle->startPos = ccpMult( p, CC_CONTENT_SCALE_FACTOR() ); | ||
399 | } | ||
400 | else if( positionType_ == kCCPositionTypeRelative ) { | ||
401 | particle->startPos = ccpMult( position_, CC_CONTENT_SCALE_FACTOR() ); | ||
402 | } | ||
403 | |||
404 | // direction | ||
405 | float a = CC_DEGREES_TO_RADIANS( angle + angleVar * CCRANDOM_MINUS1_1() ); | ||
406 | |||
407 | // Mode Gravity: A | ||
408 | if( emitterMode_ == kCCParticleModeGravity ) { | ||
409 | |||
410 | CGPoint v = {cosf( a ), sinf( a )}; | ||
411 | float s = mode.A.speed + mode.A.speedVar * CCRANDOM_MINUS1_1(); | ||
412 | s *= CC_CONTENT_SCALE_FACTOR(); | ||
413 | |||
414 | // direction | ||
415 | particle->mode.A.dir = ccpMult( v, s ); | ||
416 | |||
417 | // radial accel | ||
418 | particle->mode.A.radialAccel = mode.A.radialAccel + mode.A.radialAccelVar * CCRANDOM_MINUS1_1(); | ||
419 | particle->mode.A.radialAccel *= CC_CONTENT_SCALE_FACTOR(); | ||
420 | |||
421 | // tangential accel | ||
422 | particle->mode.A.tangentialAccel = mode.A.tangentialAccel + mode.A.tangentialAccelVar * CCRANDOM_MINUS1_1(); | ||
423 | particle->mode.A.tangentialAccel *= CC_CONTENT_SCALE_FACTOR(); | ||
424 | |||
425 | } | ||
426 | |||
427 | // Mode Radius: B | ||
428 | else { | ||
429 | // Set the default diameter of the particle from the source position | ||
430 | float startRadius = mode.B.startRadius + mode.B.startRadiusVar * CCRANDOM_MINUS1_1(); | ||
431 | float endRadius = mode.B.endRadius + mode.B.endRadiusVar * CCRANDOM_MINUS1_1(); | ||
432 | |||
433 | startRadius *= CC_CONTENT_SCALE_FACTOR(); | ||
434 | endRadius *= CC_CONTENT_SCALE_FACTOR(); | ||
435 | |||
436 | particle->mode.B.radius = startRadius; | ||
437 | |||
438 | if( mode.B.endRadius == kCCParticleStartRadiusEqualToEndRadius ) | ||
439 | particle->mode.B.deltaRadius = 0; | ||
440 | else | ||
441 | particle->mode.B.deltaRadius = (endRadius - startRadius) / particle->timeToLive; | ||
442 | |||
443 | particle->mode.B.angle = a; | ||
444 | particle->mode.B.degreesPerSecond = CC_DEGREES_TO_RADIANS(mode.B.rotatePerSecond + mode.B.rotatePerSecondVar * CCRANDOM_MINUS1_1()); | ||
445 | } | ||
446 | } | ||
447 | |||
448 | -(void) stopSystem | ||
449 | { | ||
450 | active = NO; | ||
451 | elapsed = duration; | ||
452 | emitCounter = 0; | ||
453 | } | ||
454 | |||
455 | -(void) resetSystem | ||
456 | { | ||
457 | active = YES; | ||
458 | elapsed = 0; | ||
459 | for(particleIdx = 0; particleIdx < particleCount; ++particleIdx) { | ||
460 | tCCParticle *p = &particles[particleIdx]; | ||
461 | p->timeToLive = 0; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | -(BOOL) isFull | ||
466 | { | ||
467 | return (particleCount == totalParticles); | ||
468 | } | ||
469 | |||
470 | #pragma mark ParticleSystem - MainLoop | ||
471 | -(void) update: (ccTime) dt | ||
472 | { | ||
473 | if( active && emissionRate ) { | ||
474 | float rate = 1.0f / emissionRate; | ||
475 | emitCounter += dt; | ||
476 | while( particleCount < totalParticles && emitCounter > rate ) { | ||
477 | [self addParticle]; | ||
478 | emitCounter -= rate; | ||
479 | } | ||
480 | |||
481 | elapsed += dt; | ||
482 | if(duration != -1 && duration < elapsed) | ||
483 | [self stopSystem]; | ||
484 | } | ||
485 | |||
486 | particleIdx = 0; | ||
487 | |||
488 | |||
489 | #if CC_ENABLE_PROFILERS | ||
490 | CCProfilingBeginTimingBlock(_profilingTimer); | ||
491 | #endif | ||
492 | |||
493 | |||
494 | CGPoint currentPosition = CGPointZero; | ||
495 | if( positionType_ == kCCPositionTypeFree ) { | ||
496 | currentPosition = [self convertToWorldSpace:CGPointZero]; | ||
497 | currentPosition.x *= CC_CONTENT_SCALE_FACTOR(); | ||
498 | currentPosition.y *= CC_CONTENT_SCALE_FACTOR(); | ||
499 | } | ||
500 | else if( positionType_ == kCCPositionTypeRelative ) { | ||
501 | currentPosition = position_; | ||
502 | currentPosition.x *= CC_CONTENT_SCALE_FACTOR(); | ||
503 | currentPosition.y *= CC_CONTENT_SCALE_FACTOR(); | ||
504 | } | ||
505 | |||
506 | while( particleIdx < particleCount ) | ||
507 | { | ||
508 | tCCParticle *p = &particles[particleIdx]; | ||
509 | |||
510 | // life | ||
511 | p->timeToLive -= dt; | ||
512 | |||
513 | if( p->timeToLive > 0 ) { | ||
514 | |||
515 | // Mode A: gravity, direction, tangential accel & radial accel | ||
516 | if( emitterMode_ == kCCParticleModeGravity ) { | ||
517 | CGPoint tmp, radial, tangential; | ||
518 | |||
519 | radial = CGPointZero; | ||
520 | // radial acceleration | ||
521 | if(p->pos.x || p->pos.y) | ||
522 | radial = ccpNormalize(p->pos); | ||
523 | |||
524 | tangential = radial; | ||
525 | radial = ccpMult(radial, p->mode.A.radialAccel); | ||
526 | |||
527 | // tangential acceleration | ||
528 | float newy = tangential.x; | ||
529 | tangential.x = -tangential.y; | ||
530 | tangential.y = newy; | ||
531 | tangential = ccpMult(tangential, p->mode.A.tangentialAccel); | ||
532 | |||
533 | // (gravity + radial + tangential) * dt | ||
534 | tmp = ccpAdd( ccpAdd( radial, tangential), mode.A.gravity); | ||
535 | tmp = ccpMult( tmp, dt); | ||
536 | p->mode.A.dir = ccpAdd( p->mode.A.dir, tmp); | ||
537 | tmp = ccpMult(p->mode.A.dir, dt); | ||
538 | p->pos = ccpAdd( p->pos, tmp ); | ||
539 | } | ||
540 | |||
541 | // Mode B: radius movement | ||
542 | else { | ||
543 | // Update the angle and radius of the particle. | ||
544 | p->mode.B.angle += p->mode.B.degreesPerSecond * dt; | ||
545 | p->mode.B.radius += p->mode.B.deltaRadius * dt; | ||
546 | |||
547 | p->pos.x = - cosf(p->mode.B.angle) * p->mode.B.radius; | ||
548 | p->pos.y = - sinf(p->mode.B.angle) * p->mode.B.radius; | ||
549 | } | ||
550 | |||
551 | // color | ||
552 | p->color.r += (p->deltaColor.r * dt); | ||
553 | p->color.g += (p->deltaColor.g * dt); | ||
554 | p->color.b += (p->deltaColor.b * dt); | ||
555 | p->color.a += (p->deltaColor.a * dt); | ||
556 | |||
557 | // size | ||
558 | p->size += (p->deltaSize * dt); | ||
559 | p->size = MAX( 0, p->size ); | ||
560 | |||
561 | // angle | ||
562 | p->rotation += (p->deltaRotation * dt); | ||
563 | |||
564 | // | ||
565 | // update values in quad | ||
566 | // | ||
567 | |||
568 | CGPoint newPos; | ||
569 | |||
570 | if( positionType_ == kCCPositionTypeFree || positionType_ == kCCPositionTypeRelative ) { | ||
571 | CGPoint diff = ccpSub( currentPosition, p->startPos ); | ||
572 | newPos = ccpSub(p->pos, diff); | ||
573 | |||
574 | } else | ||
575 | newPos = p->pos; | ||
576 | |||
577 | |||
578 | updateParticleImp(self, updateParticleSel, p, newPos); | ||
579 | |||
580 | // update particle counter | ||
581 | particleIdx++; | ||
582 | |||
583 | } else { | ||
584 | // life < 0 | ||
585 | if( particleIdx != particleCount-1 ) | ||
586 | particles[particleIdx] = particles[particleCount-1]; | ||
587 | particleCount--; | ||
588 | |||
589 | if( particleCount == 0 && autoRemoveOnFinish_ ) { | ||
590 | [self unscheduleUpdate]; | ||
591 | [parent_ removeChild:self cleanup:YES]; | ||
592 | return; | ||
593 | } | ||
594 | } | ||
595 | } | ||
596 | |||
597 | #if CC_ENABLE_PROFILERS | ||
598 | CCProfilingEndTimingBlock(_profilingTimer); | ||
599 | #endif | ||
600 | |||
601 | #ifdef CC_USES_VBO | ||
602 | [self postStep]; | ||
603 | #endif | ||
604 | } | ||
605 | |||
606 | -(void) updateQuadWithParticle:(tCCParticle*)particle newPosition:(CGPoint)pos; | ||
607 | { | ||
608 | // should be overriden | ||
609 | } | ||
610 | |||
611 | -(void) postStep | ||
612 | { | ||
613 | // should be overriden | ||
614 | } | ||
615 | |||
616 | #pragma mark ParticleSystem - CCTexture protocol | ||
617 | |||
618 | -(void) setTexture:(CCTexture2D*) texture | ||
619 | { | ||
620 | [texture_ release]; | ||
621 | texture_ = [texture retain]; | ||
622 | |||
623 | // If the new texture has No premultiplied alpha, AND the blendFunc hasn't been changed, then update it | ||
624 | if( texture_ && ! [texture hasPremultipliedAlpha] && | ||
625 | ( blendFunc_.src == CC_BLEND_SRC && blendFunc_.dst == CC_BLEND_DST ) ) { | ||
626 | |||
627 | blendFunc_.src = GL_SRC_ALPHA; | ||
628 | blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; | ||
629 | } | ||
630 | } | ||
631 | |||
632 | -(CCTexture2D*) texture | ||
633 | { | ||
634 | return texture_; | ||
635 | } | ||
636 | |||
637 | #pragma mark ParticleSystem - Additive Blending | ||
638 | -(void) setBlendAdditive:(BOOL)additive | ||
639 | { | ||
640 | if( additive ) { | ||
641 | blendFunc_.src = GL_SRC_ALPHA; | ||
642 | blendFunc_.dst = GL_ONE; | ||
643 | |||
644 | } else { | ||
645 | |||
646 | if( texture_ && ! [texture_ hasPremultipliedAlpha] ) { | ||
647 | blendFunc_.src = GL_SRC_ALPHA; | ||
648 | blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; | ||
649 | } else { | ||
650 | blendFunc_.src = CC_BLEND_SRC; | ||
651 | blendFunc_.dst = CC_BLEND_DST; | ||
652 | } | ||
653 | } | ||
654 | } | ||
655 | |||
656 | -(BOOL) blendAdditive | ||
657 | { | ||
658 | return( blendFunc_.src == GL_SRC_ALPHA && blendFunc_.dst == GL_ONE); | ||
659 | } | ||
660 | |||
661 | #pragma mark ParticleSystem - Properties of Gravity Mode | ||
662 | -(void) setTangentialAccel:(float)t | ||
663 | { | ||
664 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
665 | mode.A.tangentialAccel = t; | ||
666 | } | ||
667 | -(float) tangentialAccel | ||
668 | { | ||
669 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
670 | return mode.A.tangentialAccel; | ||
671 | } | ||
672 | |||
673 | -(void) setTangentialAccelVar:(float)t | ||
674 | { | ||
675 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
676 | mode.A.tangentialAccelVar = t; | ||
677 | } | ||
678 | -(float) tangentialAccelVar | ||
679 | { | ||
680 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
681 | return mode.A.tangentialAccelVar; | ||
682 | } | ||
683 | |||
684 | -(void) setRadialAccel:(float)t | ||
685 | { | ||
686 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
687 | mode.A.radialAccel = t; | ||
688 | } | ||
689 | -(float) radialAccel | ||
690 | { | ||
691 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
692 | return mode.A.radialAccel; | ||
693 | } | ||
694 | |||
695 | -(void) setRadialAccelVar:(float)t | ||
696 | { | ||
697 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
698 | mode.A.radialAccelVar = t; | ||
699 | } | ||
700 | -(float) radialAccelVar | ||
701 | { | ||
702 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
703 | return mode.A.radialAccelVar; | ||
704 | } | ||
705 | |||
706 | -(void) setGravity:(CGPoint)g | ||
707 | { | ||
708 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
709 | mode.A.gravity = g; | ||
710 | } | ||
711 | -(CGPoint) gravity | ||
712 | { | ||
713 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
714 | return mode.A.gravity; | ||
715 | } | ||
716 | |||
717 | -(void) setSpeed:(float)speed | ||
718 | { | ||
719 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
720 | mode.A.speed = speed; | ||
721 | } | ||
722 | -(float) speed | ||
723 | { | ||
724 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
725 | return mode.A.speed; | ||
726 | } | ||
727 | |||
728 | -(void) setSpeedVar:(float)speedVar | ||
729 | { | ||
730 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
731 | mode.A.speedVar = speedVar; | ||
732 | } | ||
733 | -(float) speedVar | ||
734 | { | ||
735 | NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); | ||
736 | return mode.A.speedVar; | ||
737 | } | ||
738 | |||
739 | #pragma mark ParticleSystem - Properties of Radius Mode | ||
740 | |||
741 | -(void) setStartRadius:(float)startRadius | ||
742 | { | ||
743 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
744 | mode.B.startRadius = startRadius; | ||
745 | } | ||
746 | -(float) startRadius | ||
747 | { | ||
748 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
749 | return mode.B.startRadius; | ||
750 | } | ||
751 | |||
752 | -(void) setStartRadiusVar:(float)startRadiusVar | ||
753 | { | ||
754 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
755 | mode.B.startRadiusVar = startRadiusVar; | ||
756 | } | ||
757 | -(float) startRadiusVar | ||
758 | { | ||
759 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
760 | return mode.B.startRadiusVar; | ||
761 | } | ||
762 | |||
763 | -(void) setEndRadius:(float)endRadius | ||
764 | { | ||
765 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
766 | mode.B.endRadius = endRadius; | ||
767 | } | ||
768 | -(float) endRadius | ||
769 | { | ||
770 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
771 | return mode.B.endRadius; | ||
772 | } | ||
773 | |||
774 | -(void) setEndRadiusVar:(float)endRadiusVar | ||
775 | { | ||
776 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
777 | mode.B.endRadiusVar = endRadiusVar; | ||
778 | } | ||
779 | -(float) endRadiusVar | ||
780 | { | ||
781 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
782 | return mode.B.endRadiusVar; | ||
783 | } | ||
784 | |||
785 | -(void) setRotatePerSecond:(float)degrees | ||
786 | { | ||
787 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
788 | mode.B.rotatePerSecond = degrees; | ||
789 | } | ||
790 | -(float) rotatePerSecond | ||
791 | { | ||
792 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
793 | return mode.B.rotatePerSecond; | ||
794 | } | ||
795 | |||
796 | -(void) setRotatePerSecondVar:(float)degrees | ||
797 | { | ||
798 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
799 | mode.B.rotatePerSecondVar = degrees; | ||
800 | } | ||
801 | -(float) rotatePerSecondVar | ||
802 | { | ||
803 | NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); | ||
804 | return mode.B.rotatePerSecondVar; | ||
805 | } | ||
806 | @end | ||
807 | |||
808 | |||
diff --git a/libs/cocos2d/CCParticleSystemPoint.h b/libs/cocos2d/CCParticleSystemPoint.h new file mode 100755 index 0000000..f0918fe --- /dev/null +++ b/libs/cocos2d/CCParticleSystemPoint.h | |||
@@ -0,0 +1,65 @@ | |||
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 | #import <Availability.h> | ||
29 | #import "CCParticleSystem.h" | ||
30 | |||
31 | #define CC_MAX_PARTICLE_SIZE 64 | ||
32 | |||
33 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
34 | |||
35 | /** CCParticleSystemPoint is a subclass of CCParticleSystem | ||
36 | Attributes of a Particle System: | ||
37 | * All the attributes of Particle System | ||
38 | |||
39 | Features: | ||
40 | * consumes small memory: uses 1 vertex (x,y) per particle, no need to assign tex coordinates | ||
41 | * size can't be bigger than 64 | ||
42 | * the system can't be scaled since the particles are rendered using GL_POINT_SPRITE | ||
43 | |||
44 | Limitations: | ||
45 | * On 3rd gen iPhone devices and iPads, this node performs MUCH slower than CCParticleSystemQuad. | ||
46 | */ | ||
47 | @interface CCParticleSystemPoint : CCParticleSystem | ||
48 | { | ||
49 | // Array of (x,y,size) | ||
50 | ccPointSprite *vertices; | ||
51 | // vertices buffer id | ||
52 | #if CC_USES_VBO | ||
53 | GLuint verticesID; | ||
54 | #endif | ||
55 | } | ||
56 | @end | ||
57 | |||
58 | #elif __MAC_OS_X_VERSION_MAX_ALLOWED | ||
59 | |||
60 | #import "CCParticleSystemQuad.h" | ||
61 | |||
62 | @interface CCParticleSystemPoint : CCParticleSystemQuad | ||
63 | @end | ||
64 | |||
65 | #endif | ||
diff --git a/libs/cocos2d/CCParticleSystemPoint.m b/libs/cocos2d/CCParticleSystemPoint.m new file mode 100755 index 0000000..0894d2b --- /dev/null +++ b/libs/cocos2d/CCParticleSystemPoint.m | |||
@@ -0,0 +1,211 @@ | |||
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 | #import <Availability.h> | ||
28 | #import "CCParticleSystemPoint.h" | ||
29 | |||
30 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
31 | |||
32 | // opengl | ||
33 | #import "Platforms/CCGL.h" | ||
34 | |||
35 | // cocos2d | ||
36 | #import "CCTextureCache.h" | ||
37 | #import "ccMacros.h" | ||
38 | |||
39 | // support | ||
40 | #import "Support/OpenGL_Internal.h" | ||
41 | #import "Support/CGPointExtension.h" | ||
42 | |||
43 | @implementation CCParticleSystemPoint | ||
44 | |||
45 | -(id) initWithTotalParticles:(NSUInteger) numberOfParticles | ||
46 | { | ||
47 | if( (self=[super initWithTotalParticles:numberOfParticles]) ) { | ||
48 | |||
49 | vertices = malloc( sizeof(ccPointSprite) * totalParticles ); | ||
50 | |||
51 | if( ! vertices ) { | ||
52 | NSLog(@"cocos2d: Particle system: not enough memory"); | ||
53 | [self release]; | ||
54 | return nil; | ||
55 | } | ||
56 | |||
57 | #if CC_USES_VBO | ||
58 | glGenBuffers(1, &verticesID); | ||
59 | |||
60 | // initial binding | ||
61 | glBindBuffer(GL_ARRAY_BUFFER, verticesID); | ||
62 | glBufferData(GL_ARRAY_BUFFER, sizeof(ccPointSprite)*totalParticles, vertices, GL_DYNAMIC_DRAW); | ||
63 | glBindBuffer(GL_ARRAY_BUFFER, 0); | ||
64 | #endif | ||
65 | } | ||
66 | |||
67 | return self; | ||
68 | } | ||
69 | |||
70 | -(void) dealloc | ||
71 | { | ||
72 | free(vertices); | ||
73 | #if CC_USES_VBO | ||
74 | glDeleteBuffers(1, &verticesID); | ||
75 | #endif | ||
76 | |||
77 | [super dealloc]; | ||
78 | } | ||
79 | |||
80 | -(void) updateQuadWithParticle:(tCCParticle*)p newPosition:(CGPoint)newPos | ||
81 | { | ||
82 | // place vertices and colos in array | ||
83 | vertices[particleIdx].pos = (ccVertex2F) {newPos.x, newPos.y}; | ||
84 | vertices[particleIdx].size = p->size; | ||
85 | ccColor4B color = { p->color.r*255, p->color.g*255, p->color.b*255, p->color.a*255 }; | ||
86 | vertices[particleIdx].color = color; | ||
87 | } | ||
88 | |||
89 | -(void) postStep | ||
90 | { | ||
91 | #if CC_USES_VBO | ||
92 | glBindBuffer(GL_ARRAY_BUFFER, verticesID); | ||
93 | glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(ccPointSprite)*particleCount, vertices); | ||
94 | glBindBuffer(GL_ARRAY_BUFFER, 0); | ||
95 | #endif | ||
96 | } | ||
97 | |||
98 | -(void) draw | ||
99 | { | ||
100 | [super draw]; | ||
101 | |||
102 | if (particleIdx==0) | ||
103 | return; | ||
104 | |||
105 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
106 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY | ||
107 | // Unneeded states: GL_TEXTURE_COORD_ARRAY | ||
108 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
109 | |||
110 | glBindTexture(GL_TEXTURE_2D, texture_.name); | ||
111 | |||
112 | glEnable(GL_POINT_SPRITE_OES); | ||
113 | glTexEnvi( GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE ); | ||
114 | |||
115 | #define kPointSize sizeof(vertices[0]) | ||
116 | |||
117 | #if CC_USES_VBO | ||
118 | glBindBuffer(GL_ARRAY_BUFFER, verticesID); | ||
119 | |||
120 | glVertexPointer(2,GL_FLOAT, kPointSize, 0); | ||
121 | |||
122 | glColorPointer(4, GL_UNSIGNED_BYTE, kPointSize, (GLvoid*) offsetof(ccPointSprite, color) ); | ||
123 | |||
124 | glEnableClientState(GL_POINT_SIZE_ARRAY_OES); | ||
125 | glPointSizePointerOES(GL_FLOAT, kPointSize, (GLvoid*) offsetof(ccPointSprite, size) ); | ||
126 | #else // Uses Vertex Array List | ||
127 | int offset = (int)vertices; | ||
128 | glVertexPointer(2,GL_FLOAT, kPointSize, (GLvoid*) offset); | ||
129 | |||
130 | int diff = offsetof(ccPointSprite, color); | ||
131 | glColorPointer(4, GL_UNSIGNED_BYTE, kPointSize, (GLvoid*) (offset+diff)); | ||
132 | |||
133 | glEnableClientState(GL_POINT_SIZE_ARRAY_OES); | ||
134 | diff = offsetof(ccPointSprite, size); | ||
135 | glPointSizePointerOES(GL_FLOAT, kPointSize, (GLvoid*) (offset+diff)); | ||
136 | #endif | ||
137 | |||
138 | BOOL newBlend = blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST; | ||
139 | if( newBlend ) | ||
140 | glBlendFunc( blendFunc_.src, blendFunc_.dst ); | ||
141 | |||
142 | |||
143 | glDrawArrays(GL_POINTS, 0, particleIdx); | ||
144 | |||
145 | // restore blend state | ||
146 | if( newBlend ) | ||
147 | glBlendFunc( CC_BLEND_SRC, CC_BLEND_DST); | ||
148 | |||
149 | |||
150 | #if CC_USES_VBO | ||
151 | // unbind VBO buffer | ||
152 | glBindBuffer(GL_ARRAY_BUFFER, 0); | ||
153 | #endif | ||
154 | |||
155 | glDisableClientState(GL_POINT_SIZE_ARRAY_OES); | ||
156 | glDisable(GL_POINT_SPRITE_OES); | ||
157 | |||
158 | // restore GL default state | ||
159 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
160 | } | ||
161 | |||
162 | #pragma mark Non supported properties | ||
163 | |||
164 | // | ||
165 | // SPIN IS NOT SUPPORTED | ||
166 | // | ||
167 | -(void) setStartSpin:(float)a | ||
168 | { | ||
169 | NSAssert(a == 0, @"PointParticleSystem doesn't support spinning"); | ||
170 | [super setStartSpin:a]; | ||
171 | } | ||
172 | -(void) setStartSpinVar:(float)a | ||
173 | { | ||
174 | NSAssert(a == 0, @"PointParticleSystem doesn't support spinning"); | ||
175 | [super setStartSpin:a]; | ||
176 | } | ||
177 | -(void) setEndSpin:(float)a | ||
178 | { | ||
179 | NSAssert(a == 0, @"PointParticleSystem doesn't support spinning"); | ||
180 | [super setStartSpin:a]; | ||
181 | } | ||
182 | -(void) setEndSpinVar:(float)a | ||
183 | { | ||
184 | NSAssert(a == 0, @"PointParticleSystem doesn't support spinning"); | ||
185 | [super setStartSpin:a]; | ||
186 | } | ||
187 | |||
188 | // | ||
189 | // SIZE > 64 IS NOT SUPPORTED | ||
190 | // | ||
191 | -(void) setStartSize:(float)size | ||
192 | { | ||
193 | NSAssert(size >= 0 && size <= CC_MAX_PARTICLE_SIZE, @"PointParticleSystem only supports 0 <= size <= 64"); | ||
194 | [super setStartSize:size]; | ||
195 | } | ||
196 | |||
197 | -(void) setEndSize:(float)size | ||
198 | { | ||
199 | NSAssert( (size == kCCParticleStartSizeEqualToEndSize) || | ||
200 | ( size >= 0 && size <= CC_MAX_PARTICLE_SIZE), @"PointParticleSystem only supports 0 <= size <= 64"); | ||
201 | [super setEndSize:size]; | ||
202 | } | ||
203 | @end | ||
204 | |||
205 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
206 | @implementation CCParticleSystemPoint | ||
207 | @end | ||
208 | |||
209 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
210 | |||
211 | |||
diff --git a/libs/cocos2d/CCParticleSystemQuad.h b/libs/cocos2d/CCParticleSystemQuad.h new file mode 100755 index 0000000..74a9d93 --- /dev/null +++ b/libs/cocos2d/CCParticleSystemQuad.h | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Leonardo Kasperavičius | ||
5 | * | ||
6 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
7 | * Copyright (c) 2011 Zynga Inc. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | |||
30 | #import "CCParticleSystem.h" | ||
31 | #import "ccConfig.h" | ||
32 | |||
33 | @class CCSpriteFrame; | ||
34 | |||
35 | /** CCParticleSystemQuad is a subclass of CCParticleSystem | ||
36 | |||
37 | It includes all the features of ParticleSystem. | ||
38 | |||
39 | Special features and Limitations: | ||
40 | - Particle size can be any float number. | ||
41 | - The system can be scaled | ||
42 | - The particles can be rotated | ||
43 | - On 1st and 2nd gen iPhones: It is only a bit slower that CCParticleSystemPoint | ||
44 | - On 3rd gen iPhone and iPads: It is MUCH faster than CCParticleSystemPoint | ||
45 | - It consumes more RAM and more GPU memory than CCParticleSystemPoint | ||
46 | - It supports subrects | ||
47 | @since v0.8 | ||
48 | */ | ||
49 | @interface CCParticleSystemQuad : CCParticleSystem | ||
50 | { | ||
51 | ccV2F_C4B_T2F_Quad *quads_; // quads to be rendered | ||
52 | GLushort *indices_; // indices | ||
53 | #if CC_USES_VBO | ||
54 | GLuint quadsID_; // VBO id | ||
55 | #endif | ||
56 | } | ||
57 | |||
58 | /** initialices the indices for the vertices */ | ||
59 | -(void) initIndices; | ||
60 | |||
61 | /** initilizes the texture with a rectangle measured Points */ | ||
62 | -(void) initTexCoordsWithRect:(CGRect)rect; | ||
63 | |||
64 | /** Sets a new CCSpriteFrame as particle. | ||
65 | WARNING: this method is experimental. Use setTexture:withRect instead. | ||
66 | @since v0.99.4 | ||
67 | */ | ||
68 | -(void)setDisplayFrame:(CCSpriteFrame*)spriteFrame; | ||
69 | |||
70 | /** Sets a new texture with a rect. The rect is in Points. | ||
71 | @since v0.99.4 | ||
72 | */ | ||
73 | -(void) setTexture:(CCTexture2D *)texture withRect:(CGRect)rect; | ||
74 | |||
75 | @end | ||
76 | |||
diff --git a/libs/cocos2d/CCParticleSystemQuad.m b/libs/cocos2d/CCParticleSystemQuad.m new file mode 100755 index 0000000..4916964 --- /dev/null +++ b/libs/cocos2d/CCParticleSystemQuad.m | |||
@@ -0,0 +1,318 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Leonardo Kasperavičius | ||
5 | * | ||
6 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
7 | * Copyright (c) 2011 Zynga Inc. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | |||
30 | // opengl | ||
31 | #import "Platforms/CCGL.h" | ||
32 | |||
33 | // cocos2d | ||
34 | #import "ccConfig.h" | ||
35 | #import "CCParticleSystemQuad.h" | ||
36 | #import "CCTextureCache.h" | ||
37 | #import "ccMacros.h" | ||
38 | #import "CCSpriteFrame.h" | ||
39 | |||
40 | // support | ||
41 | #import "Support/OpenGL_Internal.h" | ||
42 | #import "Support/CGPointExtension.h" | ||
43 | |||
44 | @implementation CCParticleSystemQuad | ||
45 | |||
46 | |||
47 | // overriding the init method | ||
48 | -(id) initWithTotalParticles:(NSUInteger) numberOfParticles | ||
49 | { | ||
50 | // base initialization | ||
51 | if( (self=[super initWithTotalParticles:numberOfParticles]) ) { | ||
52 | |||
53 | // allocating data space | ||
54 | quads_ = calloc( sizeof(quads_[0]) * totalParticles, 1 ); | ||
55 | indices_ = calloc( sizeof(indices_[0]) * totalParticles * 6, 1 ); | ||
56 | |||
57 | if( !quads_ || !indices_) { | ||
58 | NSLog(@"cocos2d: Particle system: not enough memory"); | ||
59 | if( quads_ ) | ||
60 | free( quads_ ); | ||
61 | if(indices_) | ||
62 | free(indices_); | ||
63 | |||
64 | [self release]; | ||
65 | return nil; | ||
66 | } | ||
67 | |||
68 | // initialize only once the texCoords and the indices | ||
69 | [self initTexCoordsWithRect:CGRectMake(0, 0, [texture_ pixelsWide], [texture_ pixelsHigh])]; | ||
70 | [self initIndices]; | ||
71 | |||
72 | #if CC_USES_VBO | ||
73 | // create the VBO buffer | ||
74 | glGenBuffers(1, &quadsID_); | ||
75 | |||
76 | // initial binding | ||
77 | glBindBuffer(GL_ARRAY_BUFFER, quadsID_); | ||
78 | glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0])*totalParticles, quads_,GL_DYNAMIC_DRAW); | ||
79 | glBindBuffer(GL_ARRAY_BUFFER, 0); | ||
80 | #endif | ||
81 | } | ||
82 | |||
83 | return self; | ||
84 | } | ||
85 | |||
86 | -(void) dealloc | ||
87 | { | ||
88 | free(quads_); | ||
89 | free(indices_); | ||
90 | #if CC_USES_VBO | ||
91 | glDeleteBuffers(1, &quadsID_); | ||
92 | #endif | ||
93 | |||
94 | [super dealloc]; | ||
95 | } | ||
96 | |||
97 | // pointRect is in Points coordinates. | ||
98 | -(void) initTexCoordsWithRect:(CGRect)pointRect | ||
99 | { | ||
100 | // convert to pixels coords | ||
101 | CGRect rect = CGRectMake( | ||
102 | pointRect.origin.x * CC_CONTENT_SCALE_FACTOR(), | ||
103 | pointRect.origin.y * CC_CONTENT_SCALE_FACTOR(), | ||
104 | pointRect.size.width * CC_CONTENT_SCALE_FACTOR(), | ||
105 | pointRect.size.height * CC_CONTENT_SCALE_FACTOR() ); | ||
106 | |||
107 | GLfloat wide = [texture_ pixelsWide]; | ||
108 | GLfloat high = [texture_ pixelsHigh]; | ||
109 | |||
110 | #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
111 | GLfloat left = (rect.origin.x*2+1) / (wide*2); | ||
112 | GLfloat bottom = (rect.origin.y*2+1) / (high*2); | ||
113 | GLfloat right = left + (rect.size.width*2-2) / (wide*2); | ||
114 | GLfloat top = bottom + (rect.size.height*2-2) / (high*2); | ||
115 | #else | ||
116 | GLfloat left = rect.origin.x / wide; | ||
117 | GLfloat bottom = rect.origin.y / high; | ||
118 | GLfloat right = left + rect.size.width / wide; | ||
119 | GLfloat top = bottom + rect.size.height / high; | ||
120 | #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
121 | |||
122 | // Important. Texture in cocos2d are inverted, so the Y component should be inverted | ||
123 | CC_SWAP( top, bottom); | ||
124 | |||
125 | for(NSUInteger i=0; i<totalParticles; i++) { | ||
126 | // bottom-left vertex: | ||
127 | quads_[i].bl.texCoords.u = left; | ||
128 | quads_[i].bl.texCoords.v = bottom; | ||
129 | // bottom-right vertex: | ||
130 | quads_[i].br.texCoords.u = right; | ||
131 | quads_[i].br.texCoords.v = bottom; | ||
132 | // top-left vertex: | ||
133 | quads_[i].tl.texCoords.u = left; | ||
134 | quads_[i].tl.texCoords.v = top; | ||
135 | // top-right vertex: | ||
136 | quads_[i].tr.texCoords.u = right; | ||
137 | quads_[i].tr.texCoords.v = top; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | -(void) setTexture:(CCTexture2D *)texture withRect:(CGRect)rect | ||
142 | { | ||
143 | // Only update the texture if is different from the current one | ||
144 | if( [texture name] != [texture_ name] ) | ||
145 | [super setTexture:texture]; | ||
146 | |||
147 | [self initTexCoordsWithRect:rect]; | ||
148 | } | ||
149 | |||
150 | -(void) setTexture:(CCTexture2D *)texture | ||
151 | { | ||
152 | CGSize s = [texture contentSize]; | ||
153 | [self setTexture:texture withRect:CGRectMake(0,0, s.width, s.height)]; | ||
154 | } | ||
155 | |||
156 | -(void) setDisplayFrame:(CCSpriteFrame *)spriteFrame | ||
157 | { | ||
158 | |||
159 | NSAssert( CGPointEqualToPoint( spriteFrame.offsetInPixels , CGPointZero ), @"QuadParticle only supports SpriteFrames with no offsets"); | ||
160 | |||
161 | // update texture before updating texture rect | ||
162 | if ( spriteFrame.texture.name != texture_.name ) | ||
163 | [self setTexture: spriteFrame.texture]; | ||
164 | } | ||
165 | |||
166 | -(void) initIndices | ||
167 | { | ||
168 | for( NSUInteger i=0;i< totalParticles;i++) { | ||
169 | const NSUInteger i6 = i*6; | ||
170 | const NSUInteger i4 = i*4; | ||
171 | indices_[i6+0] = (GLushort) i4+0; | ||
172 | indices_[i6+1] = (GLushort) i4+1; | ||
173 | indices_[i6+2] = (GLushort) i4+2; | ||
174 | |||
175 | indices_[i6+5] = (GLushort) i4+1; | ||
176 | indices_[i6+4] = (GLushort) i4+2; | ||
177 | indices_[i6+3] = (GLushort) i4+3; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | -(void) updateQuadWithParticle:(tCCParticle*)p newPosition:(CGPoint)newPos | ||
182 | { | ||
183 | // colors | ||
184 | ccV2F_C4B_T2F_Quad *quad = &(quads_[particleIdx]); | ||
185 | |||
186 | ccColor4B color = { p->color.r*255, p->color.g*255, p->color.b*255, p->color.a*255}; | ||
187 | quad->bl.colors = color; | ||
188 | quad->br.colors = color; | ||
189 | quad->tl.colors = color; | ||
190 | quad->tr.colors = color; | ||
191 | |||
192 | // vertices | ||
193 | GLfloat size_2 = p->size/2; | ||
194 | if( p->rotation ) { | ||
195 | GLfloat x1 = -size_2; | ||
196 | GLfloat y1 = -size_2; | ||
197 | |||
198 | GLfloat x2 = size_2; | ||
199 | GLfloat y2 = size_2; | ||
200 | GLfloat x = newPos.x; | ||
201 | GLfloat y = newPos.y; | ||
202 | |||
203 | GLfloat r = (GLfloat)-CC_DEGREES_TO_RADIANS(p->rotation); | ||
204 | GLfloat cr = cosf(r); | ||
205 | GLfloat sr = sinf(r); | ||
206 | GLfloat ax = x1 * cr - y1 * sr + x; | ||
207 | GLfloat ay = x1 * sr + y1 * cr + y; | ||
208 | GLfloat bx = x2 * cr - y1 * sr + x; | ||
209 | GLfloat by = x2 * sr + y1 * cr + y; | ||
210 | GLfloat cx = x2 * cr - y2 * sr + x; | ||
211 | GLfloat cy = x2 * sr + y2 * cr + y; | ||
212 | GLfloat dx = x1 * cr - y2 * sr + x; | ||
213 | GLfloat dy = x1 * sr + y2 * cr + y; | ||
214 | |||
215 | // bottom-left | ||
216 | quad->bl.vertices.x = ax; | ||
217 | quad->bl.vertices.y = ay; | ||
218 | |||
219 | // bottom-right vertex: | ||
220 | quad->br.vertices.x = bx; | ||
221 | quad->br.vertices.y = by; | ||
222 | |||
223 | // top-left vertex: | ||
224 | quad->tl.vertices.x = dx; | ||
225 | quad->tl.vertices.y = dy; | ||
226 | |||
227 | // top-right vertex: | ||
228 | quad->tr.vertices.x = cx; | ||
229 | quad->tr.vertices.y = cy; | ||
230 | } else { | ||
231 | // bottom-left vertex: | ||
232 | quad->bl.vertices.x = newPos.x - size_2; | ||
233 | quad->bl.vertices.y = newPos.y - size_2; | ||
234 | |||
235 | // bottom-right vertex: | ||
236 | quad->br.vertices.x = newPos.x + size_2; | ||
237 | quad->br.vertices.y = newPos.y - size_2; | ||
238 | |||
239 | // top-left vertex: | ||
240 | quad->tl.vertices.x = newPos.x - size_2; | ||
241 | quad->tl.vertices.y = newPos.y + size_2; | ||
242 | |||
243 | // top-right vertex: | ||
244 | quad->tr.vertices.x = newPos.x + size_2; | ||
245 | quad->tr.vertices.y = newPos.y + size_2; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | -(void) postStep | ||
250 | { | ||
251 | #if CC_USES_VBO | ||
252 | glBindBuffer(GL_ARRAY_BUFFER, quadsID_); | ||
253 | glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(quads_[0])*particleCount, quads_); | ||
254 | glBindBuffer(GL_ARRAY_BUFFER, 0); | ||
255 | #endif | ||
256 | } | ||
257 | |||
258 | // overriding draw method | ||
259 | -(void) draw | ||
260 | { | ||
261 | [super draw]; | ||
262 | |||
263 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
264 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
265 | // Unneeded states: - | ||
266 | |||
267 | glBindTexture(GL_TEXTURE_2D, [texture_ name]); | ||
268 | |||
269 | #define kQuadSize sizeof(quads_[0].bl) | ||
270 | |||
271 | #if CC_USES_VBO | ||
272 | glBindBuffer(GL_ARRAY_BUFFER, quadsID_); | ||
273 | |||
274 | glVertexPointer(2,GL_FLOAT, kQuadSize, 0); | ||
275 | |||
276 | glColorPointer(4, GL_UNSIGNED_BYTE, kQuadSize, (GLvoid*) offsetof(ccV2F_C4B_T2F,colors) ); | ||
277 | |||
278 | glTexCoordPointer(2, GL_FLOAT, kQuadSize, (GLvoid*) offsetof(ccV2F_C4B_T2F,texCoords) ); | ||
279 | #else // vertex array list | ||
280 | |||
281 | NSUInteger offset = (NSUInteger) quads_; | ||
282 | |||
283 | // vertex | ||
284 | NSUInteger diff = offsetof( ccV2F_C4B_T2F, vertices); | ||
285 | glVertexPointer(2,GL_FLOAT, kQuadSize, (GLvoid*) (offset+diff) ); | ||
286 | |||
287 | // color | ||
288 | diff = offsetof( ccV2F_C4B_T2F, colors); | ||
289 | glColorPointer(4, GL_UNSIGNED_BYTE, kQuadSize, (GLvoid*)(offset + diff)); | ||
290 | |||
291 | // tex coords | ||
292 | diff = offsetof( ccV2F_C4B_T2F, texCoords); | ||
293 | glTexCoordPointer(2, GL_FLOAT, kQuadSize, (GLvoid*)(offset + diff)); | ||
294 | |||
295 | #endif // ! CC_USES_VBO | ||
296 | |||
297 | BOOL newBlend = blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST; | ||
298 | if( newBlend ) | ||
299 | glBlendFunc( blendFunc_.src, blendFunc_.dst ); | ||
300 | |||
301 | NSAssert( particleIdx == particleCount, @"Abnormal error in particle quad"); | ||
302 | glDrawElements(GL_TRIANGLES, (GLsizei) particleIdx*6, GL_UNSIGNED_SHORT, indices_); | ||
303 | |||
304 | // restore blend state | ||
305 | if( newBlend ) | ||
306 | glBlendFunc( CC_BLEND_SRC, CC_BLEND_DST ); | ||
307 | |||
308 | #if CC_USES_VBO | ||
309 | glBindBuffer(GL_ARRAY_BUFFER, 0); | ||
310 | #endif | ||
311 | |||
312 | // restore GL default state | ||
313 | // - | ||
314 | } | ||
315 | |||
316 | @end | ||
317 | |||
318 | |||
diff --git a/libs/cocos2d/CCProgressTimer.h b/libs/cocos2d/CCProgressTimer.h new file mode 100755 index 0000000..9a07f2f --- /dev/null +++ b/libs/cocos2d/CCProgressTimer.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Lam Pham | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import <Foundation/Foundation.h> | ||
27 | #import "CCSprite.h" | ||
28 | |||
29 | /** Types of progress | ||
30 | @since v0.99.1 | ||
31 | */ | ||
32 | typedef enum { | ||
33 | /// Radial Counter-Clockwise | ||
34 | kCCProgressTimerTypeRadialCCW, | ||
35 | /// Radial ClockWise | ||
36 | kCCProgressTimerTypeRadialCW, | ||
37 | /// Horizontal Left-Right | ||
38 | kCCProgressTimerTypeHorizontalBarLR, | ||
39 | /// Horizontal Right-Left | ||
40 | kCCProgressTimerTypeHorizontalBarRL, | ||
41 | /// Vertical Bottom-top | ||
42 | kCCProgressTimerTypeVerticalBarBT, | ||
43 | /// Vertical Top-Bottom | ||
44 | kCCProgressTimerTypeVerticalBarTB, | ||
45 | } CCProgressTimerType; | ||
46 | |||
47 | /** | ||
48 | CCProgresstimer is a subclass of CCNode. | ||
49 | It renders the inner sprite according to the percentage. | ||
50 | The progress can be Radial, Horizontal or vertical. | ||
51 | @since v0.99.1 | ||
52 | */ | ||
53 | @interface CCProgressTimer : CCNode | ||
54 | { | ||
55 | CCProgressTimerType type_; | ||
56 | float percentage_; | ||
57 | CCSprite *sprite_; | ||
58 | |||
59 | int vertexDataCount_; | ||
60 | ccV2F_C4B_T2F *vertexData_; | ||
61 | } | ||
62 | |||
63 | /** Change the percentage to change progress. */ | ||
64 | @property (nonatomic, readwrite) CCProgressTimerType type; | ||
65 | |||
66 | /** Percentages are from 0 to 100 */ | ||
67 | @property (nonatomic, readwrite) float percentage; | ||
68 | |||
69 | /** The image to show the progress percentage */ | ||
70 | @property (nonatomic, readwrite, retain) CCSprite *sprite; | ||
71 | |||
72 | |||
73 | /** Creates a progress timer with an image filename as the shape the timer goes through */ | ||
74 | + (id) progressWithFile:(NSString*) filename; | ||
75 | /** Initializes a progress timer with an image filename as the shape the timer goes through */ | ||
76 | - (id) initWithFile:(NSString*) filename; | ||
77 | |||
78 | /** Creates a progress timer with the texture as the shape the timer goes through */ | ||
79 | + (id) progressWithTexture:(CCTexture2D*) texture; | ||
80 | /** Creates a progress timer with the texture as the shape the timer goes through */ | ||
81 | - (id) initWithTexture:(CCTexture2D*) texture; | ||
82 | |||
83 | @end | ||
diff --git a/libs/cocos2d/CCProgressTimer.m b/libs/cocos2d/CCProgressTimer.m new file mode 100755 index 0000000..4e697b2 --- /dev/null +++ b/libs/cocos2d/CCProgressTimer.m | |||
@@ -0,0 +1,493 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Lam Pham | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import "CCProgressTimer.h" | ||
27 | |||
28 | #import "ccMacros.h" | ||
29 | #import "CCTextureCache.h" | ||
30 | #import "Support/CGPointExtension.h" | ||
31 | |||
32 | |||
33 | |||
34 | #define kProgressTextureCoordsCount 4 | ||
35 | // kProgressTextureCoords holds points {0,0} {0,1} {1,1} {1,0} we can represent it as bits | ||
36 | const char kProgressTextureCoords = 0x1e; | ||
37 | |||
38 | @interface CCProgressTimer (Internal) | ||
39 | |||
40 | -(void)updateProgress; | ||
41 | -(void)updateBar; | ||
42 | -(void)updateRadial; | ||
43 | -(void)updateColor; | ||
44 | -(CGPoint)boundaryTexCoord:(char)index; | ||
45 | @end | ||
46 | |||
47 | |||
48 | @implementation CCProgressTimer | ||
49 | @synthesize percentage = percentage_; | ||
50 | @synthesize sprite = sprite_; | ||
51 | @synthesize type = type_; | ||
52 | |||
53 | +(id)progressWithFile:(NSString*) filename | ||
54 | { | ||
55 | return [[[self alloc]initWithFile:filename] autorelease]; | ||
56 | } | ||
57 | -(id)initWithFile:(NSString*) filename | ||
58 | { | ||
59 | return [self initWithTexture:[[CCTextureCache sharedTextureCache] addImage: filename]]; | ||
60 | } | ||
61 | |||
62 | +(id)progressWithTexture:(CCTexture2D*) texture | ||
63 | { | ||
64 | return [[[self alloc]initWithTexture:texture] autorelease]; | ||
65 | } | ||
66 | -(id)initWithTexture:(CCTexture2D*) texture | ||
67 | { | ||
68 | if(( self = [super init] )){ | ||
69 | self.sprite = [CCSprite spriteWithTexture:texture]; | ||
70 | percentage_ = 0.f; | ||
71 | vertexData_ = NULL; | ||
72 | vertexDataCount_ = 0; | ||
73 | self.anchorPoint = ccp(.5f,.5f); | ||
74 | self.contentSize = sprite_.contentSize; | ||
75 | self.type = kCCProgressTimerTypeRadialCCW; | ||
76 | } | ||
77 | return self; | ||
78 | } | ||
79 | -(void)dealloc | ||
80 | { | ||
81 | if(vertexData_) | ||
82 | free(vertexData_); | ||
83 | |||
84 | [sprite_ release]; | ||
85 | [super dealloc]; | ||
86 | } | ||
87 | |||
88 | -(void)setPercentage:(float) percentage | ||
89 | { | ||
90 | if(percentage_ != percentage) { | ||
91 | percentage_ = clampf( percentage, 0, 100); | ||
92 | [self updateProgress]; | ||
93 | } | ||
94 | } | ||
95 | -(void)setSprite:(CCSprite *)newSprite | ||
96 | { | ||
97 | if(sprite_ != newSprite){ | ||
98 | [sprite_ release]; | ||
99 | sprite_ = [newSprite retain]; | ||
100 | |||
101 | // Everytime we set a new sprite, we free the current vertex data | ||
102 | if(vertexData_){ | ||
103 | free(vertexData_); | ||
104 | vertexData_ = NULL; | ||
105 | vertexDataCount_ = 0; | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | -(void)setType:(CCProgressTimerType)newType | ||
110 | { | ||
111 | if (newType != type_) { | ||
112 | |||
113 | // release all previous information | ||
114 | if(vertexData_){ | ||
115 | free(vertexData_); | ||
116 | vertexData_ = NULL; | ||
117 | vertexDataCount_ = 0; | ||
118 | } | ||
119 | type_ = newType; | ||
120 | } | ||
121 | } | ||
122 | @end | ||
123 | |||
124 | @implementation CCProgressTimer(Internal) | ||
125 | |||
126 | /// | ||
127 | // @returns the vertex position from the texture coordinate | ||
128 | /// | ||
129 | -(ccVertex2F)vertexFromTexCoord:(CGPoint) texCoord | ||
130 | { | ||
131 | CGPoint tmp; | ||
132 | ccVertex2F ret; | ||
133 | if (sprite_.texture) { | ||
134 | CCTexture2D *texture = [sprite_ texture]; | ||
135 | CGSize texSize = [texture contentSizeInPixels]; | ||
136 | tmp = ccp(texSize.width * texCoord.x/texture.maxS, | ||
137 | texSize.height * (1 - (texCoord.y/texture.maxT))); | ||
138 | } else | ||
139 | tmp = CGPointZero; | ||
140 | |||
141 | ret.x = tmp.x; | ||
142 | ret.y = tmp.y; | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | -(void)updateColor | ||
147 | { | ||
148 | GLubyte op = sprite_.opacity; | ||
149 | ccColor3B c3b = sprite_.color; | ||
150 | |||
151 | ccColor4B color = { c3b.r, c3b.g, c3b.b, op }; | ||
152 | if([sprite_.texture hasPremultipliedAlpha]){ | ||
153 | color.r *= op/255; | ||
154 | color.g *= op/255; | ||
155 | color.b *= op/255; | ||
156 | } | ||
157 | |||
158 | if(vertexData_){ | ||
159 | for (int i=0; i < vertexDataCount_; ++i) { | ||
160 | vertexData_[i].colors = color; | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | -(void)updateProgress | ||
166 | { | ||
167 | switch (type_) { | ||
168 | case kCCProgressTimerTypeRadialCW: | ||
169 | case kCCProgressTimerTypeRadialCCW: | ||
170 | [self updateRadial]; | ||
171 | break; | ||
172 | case kCCProgressTimerTypeHorizontalBarLR: | ||
173 | case kCCProgressTimerTypeHorizontalBarRL: | ||
174 | case kCCProgressTimerTypeVerticalBarBT: | ||
175 | case kCCProgressTimerTypeVerticalBarTB: | ||
176 | [self updateBar]; | ||
177 | break; | ||
178 | default: | ||
179 | break; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | /// | ||
184 | // Update does the work of mapping the texture onto the triangles | ||
185 | // It now doesn't occur the cost of free/alloc data every update cycle. | ||
186 | // It also only changes the percentage point but no other points if they have not | ||
187 | // been modified. | ||
188 | // | ||
189 | // It now deals with flipped texture. If you run into this problem, just use the | ||
190 | // sprite property and enable the methods flipX, flipY. | ||
191 | /// | ||
192 | -(void)updateRadial | ||
193 | { | ||
194 | // Texture Max is the actual max coordinates to deal with non-power of 2 textures | ||
195 | CGPoint tMax = ccp(sprite_.texture.maxS,sprite_.texture.maxT); | ||
196 | |||
197 | // Grab the midpoint | ||
198 | CGPoint midpoint = ccpCompMult(self.anchorPoint, tMax); | ||
199 | |||
200 | float alpha = percentage_ / 100.f; | ||
201 | |||
202 | // Otherwise we can get the angle from the alpha | ||
203 | float angle = 2.f*((float)M_PI) * ( type_ == kCCProgressTimerTypeRadialCW? alpha : 1.f - alpha); | ||
204 | |||
205 | // We find the vector to do a hit detection based on the percentage | ||
206 | // We know the first vector is the one @ 12 o'clock (top,mid) so we rotate | ||
207 | // from that by the progress angle around the midpoint pivot | ||
208 | CGPoint topMid = ccp(midpoint.x, 0.f); | ||
209 | CGPoint percentagePt = ccpRotateByAngle(topMid, midpoint, angle); | ||
210 | |||
211 | |||
212 | int index = 0; | ||
213 | CGPoint hit = CGPointZero; | ||
214 | |||
215 | if (alpha == 0.f) { | ||
216 | // More efficient since we don't always need to check intersection | ||
217 | // If the alpha is zero then the hit point is top mid and the index is 0. | ||
218 | hit = topMid; | ||
219 | index = 0; | ||
220 | } else if (alpha == 1.f) { | ||
221 | // More efficient since we don't always need to check intersection | ||
222 | // If the alpha is one then the hit point is top mid and the index is 4. | ||
223 | hit = topMid; | ||
224 | index = 4; | ||
225 | } else { | ||
226 | // We run a for loop checking the edges of the texture to find the | ||
227 | // intersection point | ||
228 | // We loop through five points since the top is split in half | ||
229 | |||
230 | float min_t = FLT_MAX; | ||
231 | |||
232 | for (int i = 0; i <= kProgressTextureCoordsCount; ++i) { | ||
233 | int pIndex = (i + (kProgressTextureCoordsCount - 1))%kProgressTextureCoordsCount; | ||
234 | |||
235 | CGPoint edgePtA = ccpCompMult([self boundaryTexCoord:i % kProgressTextureCoordsCount],tMax); | ||
236 | CGPoint edgePtB = ccpCompMult([self boundaryTexCoord:pIndex],tMax); | ||
237 | |||
238 | // Remember that the top edge is split in half for the 12 o'clock position | ||
239 | // Let's deal with that here by finding the correct endpoints | ||
240 | if(i == 0){ | ||
241 | edgePtB = ccpLerp(edgePtA,edgePtB,.5f); | ||
242 | } else if(i == 4){ | ||
243 | edgePtA = ccpLerp(edgePtA,edgePtB,.5f); | ||
244 | } | ||
245 | |||
246 | // s and t are returned by ccpLineIntersect | ||
247 | float s = 0, t = 0; | ||
248 | if(ccpLineIntersect(edgePtA, edgePtB, midpoint, percentagePt, &s, &t)) | ||
249 | { | ||
250 | |||
251 | // Since our hit test is on rays we have to deal with the top edge | ||
252 | // being in split in half so we have to test as a segment | ||
253 | if ((i == 0 || i == 4)) { | ||
254 | // s represents the point between edgePtA--edgePtB | ||
255 | if (!(0.f <= s && s <= 1.f)) { | ||
256 | continue; | ||
257 | } | ||
258 | } | ||
259 | // As long as our t isn't negative we are at least finding a | ||
260 | // correct hitpoint from midpoint to percentagePt. | ||
261 | if (t >= 0.f) { | ||
262 | // Because the percentage line and all the texture edges are | ||
263 | // rays we should only account for the shortest intersection | ||
264 | if (t < min_t) { | ||
265 | min_t = t; | ||
266 | index = i; | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | // Now that we have the minimum magnitude we can use that to find our intersection | ||
273 | hit = ccpAdd(midpoint, ccpMult(ccpSub(percentagePt, midpoint),min_t)); | ||
274 | |||
275 | } | ||
276 | |||
277 | |||
278 | // The size of the vertex data is the index from the hitpoint | ||
279 | // the 3 is for the midpoint, 12 o'clock point and hitpoint position. | ||
280 | |||
281 | BOOL sameIndexCount = YES; | ||
282 | if(vertexDataCount_ != index + 3){ | ||
283 | sameIndexCount = NO; | ||
284 | if(vertexData_){ | ||
285 | free(vertexData_); | ||
286 | vertexData_ = NULL; | ||
287 | vertexDataCount_ = 0; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | |||
292 | if(!vertexData_) { | ||
293 | vertexDataCount_ = index + 3; | ||
294 | vertexData_ = malloc(vertexDataCount_ * sizeof(ccV2F_C4B_T2F)); | ||
295 | NSAssert( vertexData_, @"CCProgressTimer. Not enough memory"); | ||
296 | |||
297 | [self updateColor]; | ||
298 | } | ||
299 | |||
300 | if (!sameIndexCount) { | ||
301 | |||
302 | // First we populate the array with the midpoint, then all | ||
303 | // vertices/texcoords/colors of the 12 'o clock start and edges and the hitpoint | ||
304 | vertexData_[0].texCoords = (ccTex2F){midpoint.x, midpoint.y}; | ||
305 | vertexData_[0].vertices = [self vertexFromTexCoord:midpoint]; | ||
306 | |||
307 | vertexData_[1].texCoords = (ccTex2F){midpoint.x, 0.f}; | ||
308 | vertexData_[1].vertices = [self vertexFromTexCoord:ccp(midpoint.x, 0.f)]; | ||
309 | |||
310 | for(int i = 0; i < index; ++i){ | ||
311 | CGPoint texCoords = ccpCompMult([self boundaryTexCoord:i], tMax); | ||
312 | |||
313 | vertexData_[i+2].texCoords = (ccTex2F){texCoords.x, texCoords.y}; | ||
314 | vertexData_[i+2].vertices = [self vertexFromTexCoord:texCoords]; | ||
315 | } | ||
316 | |||
317 | // Flip the texture coordinates if set | ||
318 | if (sprite_.flipY || sprite_.flipX) { | ||
319 | for(int i = 0; i < vertexDataCount_ - 1; ++i){ | ||
320 | if (sprite_.flipX) { | ||
321 | vertexData_[i].texCoords.u = tMax.x - vertexData_[i].texCoords.u; | ||
322 | } | ||
323 | if(sprite_.flipY){ | ||
324 | vertexData_[i].texCoords.v = tMax.y - vertexData_[i].texCoords.v; | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | } | ||
329 | |||
330 | // hitpoint will go last | ||
331 | vertexData_[vertexDataCount_ - 1].texCoords = (ccTex2F){hit.x, hit.y}; | ||
332 | vertexData_[vertexDataCount_ - 1].vertices = [self vertexFromTexCoord:hit]; | ||
333 | |||
334 | if (sprite_.flipY || sprite_.flipX) { | ||
335 | if (sprite_.flipX) { | ||
336 | vertexData_[vertexDataCount_ - 1].texCoords.u = tMax.x - vertexData_[vertexDataCount_ - 1].texCoords.u; | ||
337 | } | ||
338 | if(sprite_.flipY){ | ||
339 | vertexData_[vertexDataCount_ - 1].texCoords.v = tMax.y - vertexData_[vertexDataCount_ - 1].texCoords.v; | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /// | ||
345 | // Update does the work of mapping the texture onto the triangles for the bar | ||
346 | // It now doesn't occur the cost of free/alloc data every update cycle. | ||
347 | // It also only changes the percentage point but no other points if they have not | ||
348 | // been modified. | ||
349 | // | ||
350 | // It now deals with flipped texture. If you run into this problem, just use the | ||
351 | // sprite property and enable the methods flipX, flipY. | ||
352 | /// | ||
353 | -(void)updateBar | ||
354 | { | ||
355 | |||
356 | float alpha = percentage_ / 100.f; | ||
357 | |||
358 | CGPoint tMax = ccp(sprite_.texture.maxS,sprite_.texture.maxT); | ||
359 | |||
360 | unsigned char vIndexes[2] = {0,0}; | ||
361 | unsigned char index = 0; | ||
362 | |||
363 | // We know vertex data is always equal to the 4 corners | ||
364 | // If we don't have vertex data then we create it here and populate | ||
365 | // the side of the bar vertices that won't ever change. | ||
366 | if (!vertexData_) { | ||
367 | vertexDataCount_ = kProgressTextureCoordsCount; | ||
368 | vertexData_ = malloc(vertexDataCount_ * sizeof(ccV2F_C4B_T2F)); | ||
369 | NSAssert( vertexData_, @"CCProgressTimer. Not enough memory"); | ||
370 | |||
371 | if(type_ == kCCProgressTimerTypeHorizontalBarLR){ | ||
372 | vertexData_[vIndexes[0] = 0].texCoords = (ccTex2F){0,0}; | ||
373 | vertexData_[vIndexes[1] = 1].texCoords = (ccTex2F){0, tMax.y}; | ||
374 | }else if (type_ == kCCProgressTimerTypeHorizontalBarRL) { | ||
375 | vertexData_[vIndexes[0] = 2].texCoords = (ccTex2F){tMax.x, tMax.y}; | ||
376 | vertexData_[vIndexes[1] = 3].texCoords = (ccTex2F){tMax.x, 0.f}; | ||
377 | }else if (type_ == kCCProgressTimerTypeVerticalBarBT) { | ||
378 | vertexData_[vIndexes[0] = 1].texCoords = (ccTex2F){0, tMax.y}; | ||
379 | vertexData_[vIndexes[1] = 3].texCoords = (ccTex2F){tMax.x, tMax.y}; | ||
380 | }else if (type_ == kCCProgressTimerTypeVerticalBarTB) { | ||
381 | vertexData_[vIndexes[0] = 0].texCoords = (ccTex2F){0, 0}; | ||
382 | vertexData_[vIndexes[1] = 2].texCoords = (ccTex2F){tMax.x, 0}; | ||
383 | } | ||
384 | |||
385 | index = vIndexes[0]; | ||
386 | vertexData_[index].vertices = [self vertexFromTexCoord:ccp(vertexData_[index].texCoords.u, vertexData_[index].texCoords.v)]; | ||
387 | |||
388 | index = vIndexes[1]; | ||
389 | vertexData_[index].vertices = [self vertexFromTexCoord:ccp(vertexData_[index].texCoords.u, vertexData_[index].texCoords.v)]; | ||
390 | |||
391 | if (sprite_.flipY || sprite_.flipX) { | ||
392 | if (sprite_.flipX) { | ||
393 | index = vIndexes[0]; | ||
394 | vertexData_[index].texCoords.u = tMax.x - vertexData_[index].texCoords.u; | ||
395 | index = vIndexes[1]; | ||
396 | vertexData_[index].texCoords.u = tMax.x - vertexData_[index].texCoords.u; | ||
397 | } | ||
398 | if(sprite_.flipY){ | ||
399 | index = vIndexes[0]; | ||
400 | vertexData_[index].texCoords.v = tMax.y - vertexData_[index].texCoords.v; | ||
401 | index = vIndexes[1]; | ||
402 | vertexData_[index].texCoords.v = tMax.y - vertexData_[index].texCoords.v; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | [self updateColor]; | ||
407 | } | ||
408 | |||
409 | if(type_ == kCCProgressTimerTypeHorizontalBarLR){ | ||
410 | vertexData_[vIndexes[0] = 3].texCoords = (ccTex2F){tMax.x*alpha, tMax.y}; | ||
411 | vertexData_[vIndexes[1] = 2].texCoords = (ccTex2F){tMax.x*alpha, 0}; | ||
412 | }else if (type_ == kCCProgressTimerTypeHorizontalBarRL) { | ||
413 | vertexData_[vIndexes[0] = 1].texCoords = (ccTex2F){tMax.x*(1.f - alpha), 0}; | ||
414 | vertexData_[vIndexes[1] = 0].texCoords = (ccTex2F){tMax.x*(1.f - alpha), tMax.y}; | ||
415 | }else if (type_ == kCCProgressTimerTypeVerticalBarBT) { | ||
416 | vertexData_[vIndexes[0] = 0].texCoords = (ccTex2F){0, tMax.y*(1.f - alpha)}; | ||
417 | vertexData_[vIndexes[1] = 2].texCoords = (ccTex2F){tMax.x, tMax.y*(1.f - alpha)}; | ||
418 | }else if (type_ == kCCProgressTimerTypeVerticalBarTB) { | ||
419 | vertexData_[vIndexes[0] = 1].texCoords = (ccTex2F){0, tMax.y*alpha}; | ||
420 | vertexData_[vIndexes[1] = 3].texCoords = (ccTex2F){tMax.x, tMax.y*alpha}; | ||
421 | } | ||
422 | |||
423 | index = vIndexes[0]; | ||
424 | vertexData_[index].vertices = [self vertexFromTexCoord:ccp(vertexData_[index].texCoords.u, vertexData_[index].texCoords.v)]; | ||
425 | index = vIndexes[1]; | ||
426 | vertexData_[index].vertices = [self vertexFromTexCoord:ccp(vertexData_[index].texCoords.u, vertexData_[index].texCoords.v)]; | ||
427 | |||
428 | if (sprite_.flipY || sprite_.flipX) { | ||
429 | if (sprite_.flipX) { | ||
430 | index = vIndexes[0]; | ||
431 | vertexData_[index].texCoords.u = tMax.x - vertexData_[index].texCoords.u; | ||
432 | index = vIndexes[1]; | ||
433 | vertexData_[index].texCoords.u = tMax.x - vertexData_[index].texCoords.u; | ||
434 | } | ||
435 | if(sprite_.flipY){ | ||
436 | index = vIndexes[0]; | ||
437 | vertexData_[index].texCoords.v = tMax.y - vertexData_[index].texCoords.v; | ||
438 | index = vIndexes[1]; | ||
439 | vertexData_[index].texCoords.v = tMax.y - vertexData_[index].texCoords.v; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | } | ||
444 | |||
445 | -(CGPoint)boundaryTexCoord:(char)index | ||
446 | { | ||
447 | if (index < kProgressTextureCoordsCount) { | ||
448 | switch (type_) { | ||
449 | case kCCProgressTimerTypeRadialCW: | ||
450 | return ccp((kProgressTextureCoords>>((index<<1)+1))&1,(kProgressTextureCoords>>(index<<1))&1); | ||
451 | case kCCProgressTimerTypeRadialCCW: | ||
452 | return ccp((kProgressTextureCoords>>(7-(index<<1)))&1,(kProgressTextureCoords>>(7-((index<<1)+1)))&1); | ||
453 | default: | ||
454 | break; | ||
455 | } | ||
456 | } | ||
457 | return CGPointZero; | ||
458 | } | ||
459 | |||
460 | -(void)draw | ||
461 | { | ||
462 | [super draw]; | ||
463 | |||
464 | if(!vertexData_)return; | ||
465 | if(!sprite_)return; | ||
466 | ccBlendFunc blendFunc = sprite_.blendFunc; | ||
467 | BOOL newBlend = blendFunc.src != CC_BLEND_SRC || blendFunc.dst != CC_BLEND_DST; | ||
468 | if( newBlend ) | ||
469 | glBlendFunc( blendFunc.src, blendFunc.dst ); | ||
470 | |||
471 | /// ======================================================================== | ||
472 | // Replaced [texture_ drawAtPoint:CGPointZero] with my own vertexData | ||
473 | // Everything above me and below me is copied from CCTextureNode's draw | ||
474 | glBindTexture(GL_TEXTURE_2D, sprite_.texture.name); | ||
475 | glVertexPointer(2, GL_FLOAT, sizeof(ccV2F_C4B_T2F), &vertexData_[0].vertices); | ||
476 | glTexCoordPointer(2, GL_FLOAT, sizeof(ccV2F_C4B_T2F), &vertexData_[0].texCoords); | ||
477 | glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ccV2F_C4B_T2F), &vertexData_[0].colors); | ||
478 | if(type_ == kCCProgressTimerTypeRadialCCW || type_ == kCCProgressTimerTypeRadialCW){ | ||
479 | glDrawArrays(GL_TRIANGLE_FAN, 0, vertexDataCount_); | ||
480 | } else if (type_ == kCCProgressTimerTypeHorizontalBarLR || | ||
481 | type_ == kCCProgressTimerTypeHorizontalBarRL || | ||
482 | type_ == kCCProgressTimerTypeVerticalBarBT || | ||
483 | type_ == kCCProgressTimerTypeVerticalBarTB) { | ||
484 | glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexDataCount_); | ||
485 | } | ||
486 | //glDrawElements(GL_TRIANGLES, indicesCount_, GL_UNSIGNED_BYTE, indices_); | ||
487 | /// ======================================================================== | ||
488 | |||
489 | if( newBlend ) | ||
490 | glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); | ||
491 | } | ||
492 | |||
493 | @end | ||
diff --git a/libs/cocos2d/CCProtocols.h b/libs/cocos2d/CCProtocols.h new file mode 100755 index 0000000..f7043fc --- /dev/null +++ b/libs/cocos2d/CCProtocols.h | |||
@@ -0,0 +1,125 @@ | |||
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 | #import "ccTypes.h" | ||
28 | #import "CCTexture2D.h" | ||
29 | |||
30 | #pragma mark - | ||
31 | #pragma mark CCRGBAProtocol | ||
32 | |||
33 | /// CC RGBA protocol | ||
34 | @protocol CCRGBAProtocol <NSObject> | ||
35 | /** sets Color | ||
36 | @since v0.8 | ||
37 | */ | ||
38 | -(void) setColor:(ccColor3B)color; | ||
39 | /** returns the color | ||
40 | @since v0.8 | ||
41 | */ | ||
42 | -(ccColor3B) color; | ||
43 | |||
44 | /// returns the opacity | ||
45 | -(GLubyte) opacity; | ||
46 | /** sets the opacity. | ||
47 | @warning If the the texture has premultiplied alpha then, the R, G and B channels will be modifed. | ||
48 | Values goes from 0 to 255, where 255 means fully opaque. | ||
49 | */ | ||
50 | -(void) setOpacity: (GLubyte) opacity; | ||
51 | @optional | ||
52 | /** sets the premultipliedAlphaOpacity property. | ||
53 | If set to NO then opacity will be applied as: glColor(R,G,B,opacity); | ||
54 | If set to YES then oapcity will be applied as: glColor(opacity, opacity, opacity, opacity ); | ||
55 | Textures with premultiplied alpha will have this property by default on YES. Otherwise the default value is NO | ||
56 | @since v0.8 | ||
57 | */ | ||
58 | -(void) setOpacityModifyRGB:(BOOL)boolean; | ||
59 | /** returns whether or not the opacity will be applied using glColor(R,G,B,opacity) or glColor(opacity, opacity, opacity, opacity); | ||
60 | @since v0.8 | ||
61 | */ | ||
62 | -(BOOL) doesOpacityModifyRGB; | ||
63 | @end | ||
64 | |||
65 | #pragma mark - | ||
66 | #pragma mark CCBlendProtocol | ||
67 | /** | ||
68 | You can specify the blending fuction. | ||
69 | @since v0.99.0 | ||
70 | */ | ||
71 | @protocol CCBlendProtocol <NSObject> | ||
72 | /** set the source blending function for the texture */ | ||
73 | -(void) setBlendFunc:(ccBlendFunc)blendFunc; | ||
74 | /** returns the blending function used for the texture */ | ||
75 | -(ccBlendFunc) blendFunc; | ||
76 | @end | ||
77 | |||
78 | |||
79 | #pragma mark - | ||
80 | #pragma mark CCTextureProtocol | ||
81 | |||
82 | /** CCNode objects that uses a Texture2D to render the images. | ||
83 | The texture can have a blending function. | ||
84 | If the texture has alpha premultiplied the default blending function is: | ||
85 | src=GL_ONE dst= GL_ONE_MINUS_SRC_ALPHA | ||
86 | else | ||
87 | src=GL_SRC_ALPHA dst= GL_ONE_MINUS_SRC_ALPHA | ||
88 | But you can change the blending funtion at any time. | ||
89 | @since v0.8.0 | ||
90 | */ | ||
91 | @protocol CCTextureProtocol <CCBlendProtocol> | ||
92 | /** returns the used texture */ | ||
93 | -(CCTexture2D*) texture; | ||
94 | /** sets a new texture. it will be retained */ | ||
95 | -(void) setTexture:(CCTexture2D*)texture; | ||
96 | @end | ||
97 | |||
98 | #pragma mark - | ||
99 | #pragma mark CCLabelProtocol | ||
100 | /** Common interface for Labels */ | ||
101 | @protocol CCLabelProtocol <NSObject> | ||
102 | /** sets a new label using an NSString. | ||
103 | The string will be copied. | ||
104 | */ | ||
105 | -(void) setString:(NSString*)label; | ||
106 | /** returns the string that is rendered */ | ||
107 | -(NSString*) string; | ||
108 | @optional | ||
109 | /** sets a new label using a CString. | ||
110 | It is faster than setString since it doesn't require to alloc/retain/release an NString object. | ||
111 | @since v0.99.0 | ||
112 | */ | ||
113 | -(void) setCString:(char*)label; | ||
114 | @end | ||
115 | |||
116 | |||
117 | #pragma mark - | ||
118 | #pragma mark CCProjectionProtocol | ||
119 | /** OpenGL projection protocol */ | ||
120 | @protocol CCProjectionProtocol <NSObject> | ||
121 | /** Called by CCDirector when the porjection is updated, and "custom" projection is used | ||
122 | @since v0.99.5 | ||
123 | */ | ||
124 | -(void) updateProjection; | ||
125 | @end | ||
diff --git a/libs/cocos2d/CCRenderTexture.h b/libs/cocos2d/CCRenderTexture.h new file mode 100755 index 0000000..d5e39cc --- /dev/null +++ b/libs/cocos2d/CCRenderTexture.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Jason Booth | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import <Foundation/Foundation.h> | ||
27 | #import "CCNode.h" | ||
28 | #import "CCSprite.h" | ||
29 | #import "Support/OpenGL_Internal.h" | ||
30 | |||
31 | #import <Availability.h> | ||
32 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
33 | #import <UIKit/UIKit.h> | ||
34 | #endif // iPHone | ||
35 | |||
36 | enum | ||
37 | { | ||
38 | kCCImageFormatJPG = 0, | ||
39 | kCCImageFormatPNG = 1, | ||
40 | kCCImageFormatRawData =2 | ||
41 | }; | ||
42 | |||
43 | |||
44 | /** | ||
45 | CCRenderTexture is a generic rendering target. To render things into it, | ||
46 | simply construct a render target, call begin on it, call visit on any cocos | ||
47 | scenes or objects to render them, and call end. For convienience, render texture | ||
48 | adds a sprite as it's display child with the results, so you can simply add | ||
49 | the render texture to your scene and treat it like any other CocosNode. | ||
50 | There are also functions for saving the render texture to disk in PNG or JPG format. | ||
51 | |||
52 | @since v0.8.1 | ||
53 | */ | ||
54 | @interface CCRenderTexture : CCNode | ||
55 | { | ||
56 | GLuint fbo_; | ||
57 | GLint oldFBO_; | ||
58 | CCTexture2D* texture_; | ||
59 | CCSprite* sprite_; | ||
60 | |||
61 | GLenum pixelFormat_; | ||
62 | } | ||
63 | |||
64 | /** The CCSprite being used. | ||
65 | The sprite, by default, will use the following blending function: GL_ONE, GL_ONE_MINUS_SRC_ALPHA. | ||
66 | The blending function can be changed in runtime by calling: | ||
67 | - [[renderTexture sprite] setBlendFunc:(ccBlendFunc){GL_ONE, GL_ONE_MINUS_SRC_ALPHA}]; | ||
68 | */ | ||
69 | @property (nonatomic,readwrite, assign) CCSprite* sprite; | ||
70 | |||
71 | /** creates a RenderTexture object with width and height in Points and a pixel format, only RGB and RGBA formats are valid */ | ||
72 | +(id)renderTextureWithWidth:(int)w height:(int)h pixelFormat:(CCTexture2DPixelFormat) format; | ||
73 | |||
74 | /** creates a RenderTexture object with width and height in Points, pixel format is RGBA8888 */ | ||
75 | +(id)renderTextureWithWidth:(int)w height:(int)h; | ||
76 | |||
77 | /** initializes a RenderTexture object with width and height in Points and a pixel format, only RGB and RGBA formats are valid */ | ||
78 | -(id)initWithWidth:(int)w height:(int)h pixelFormat:(CCTexture2DPixelFormat) format; | ||
79 | |||
80 | /** starts grabbing */ | ||
81 | -(void)begin; | ||
82 | |||
83 | /** starts rendering to the texture while clearing the texture first. | ||
84 | This is more efficient then calling -clear first and then -begin */ | ||
85 | -(void)beginWithClear:(float)r g:(float)g b:(float)b a:(float)a; | ||
86 | |||
87 | /** ends grabbing */ | ||
88 | -(void)end; | ||
89 | |||
90 | /** clears the texture with a color */ | ||
91 | -(void)clear:(float)r g:(float)g b:(float)b a:(float)a; | ||
92 | |||
93 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
94 | |||
95 | /** saves the texture into a file */ | ||
96 | -(BOOL)saveBuffer:(NSString*)name; | ||
97 | /** saves the texture into a file. The format can be JPG or PNG */ | ||
98 | -(BOOL)saveBuffer:(NSString*)name format:(int)format; | ||
99 | /* get buffer as UIImage, can only save a render buffer which has a RGBA8888 pixel format */ | ||
100 | -(NSData*)getUIImageAsDataFromBuffer:(int) format; | ||
101 | /* get buffer as UIImage */ | ||
102 | -(UIImage *)getUIImageFromBuffer; | ||
103 | |||
104 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
105 | |||
106 | @end | ||
107 | |||
108 | |||
diff --git a/libs/cocos2d/CCRenderTexture.m b/libs/cocos2d/CCRenderTexture.m new file mode 100755 index 0000000..4a4768e --- /dev/null +++ b/libs/cocos2d/CCRenderTexture.m | |||
@@ -0,0 +1,340 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Jason Booth | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import <Availability.h> | ||
27 | #import "CCRenderTexture.h" | ||
28 | #import "CCDirector.h" | ||
29 | #import "ccMacros.h" | ||
30 | #import "Support/ccUtils.h" | ||
31 | #import "Support/CCFileUtils.h" | ||
32 | |||
33 | @implementation CCRenderTexture | ||
34 | |||
35 | @synthesize sprite=sprite_; | ||
36 | |||
37 | // issue #994 | ||
38 | +(id)renderTextureWithWidth:(int)w height:(int)h pixelFormat:(CCTexture2DPixelFormat) format | ||
39 | { | ||
40 | return [[[self alloc] initWithWidth:w height:h pixelFormat:format] autorelease]; | ||
41 | } | ||
42 | |||
43 | +(id)renderTextureWithWidth:(int)w height:(int)h | ||
44 | { | ||
45 | return [[[self alloc] initWithWidth:w height:h pixelFormat:kCCTexture2DPixelFormat_RGBA8888] autorelease]; | ||
46 | } | ||
47 | |||
48 | -(id)initWithWidth:(int)w height:(int)h | ||
49 | { | ||
50 | return [self initWithWidth:w height:h pixelFormat:kCCTexture2DPixelFormat_RGBA8888]; | ||
51 | } | ||
52 | |||
53 | -(id)initWithWidth:(int)w height:(int)h pixelFormat:(CCTexture2DPixelFormat) format | ||
54 | { | ||
55 | if ((self = [super init])) | ||
56 | { | ||
57 | NSAssert(format != kCCTexture2DPixelFormat_A8,@"only RGB and RGBA formats are valid for a render texture"); | ||
58 | |||
59 | w *= CC_CONTENT_SCALE_FACTOR(); | ||
60 | h *= CC_CONTENT_SCALE_FACTOR(); | ||
61 | |||
62 | glGetIntegerv(CC_GL_FRAMEBUFFER_BINDING, &oldFBO_); | ||
63 | |||
64 | // textures must be power of two | ||
65 | NSUInteger powW = ccNextPOT(w); | ||
66 | NSUInteger powH = ccNextPOT(h); | ||
67 | |||
68 | void *data = malloc((int)(powW * powH * 4)); | ||
69 | memset(data, 0, (int)(powW * powH * 4)); | ||
70 | pixelFormat_=format; | ||
71 | |||
72 | texture_ = [[CCTexture2D alloc] initWithData:data pixelFormat:pixelFormat_ pixelsWide:powW pixelsHigh:powH contentSize:CGSizeMake(w, h)]; | ||
73 | free( data ); | ||
74 | |||
75 | // generate FBO | ||
76 | ccglGenFramebuffers(1, &fbo_); | ||
77 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, fbo_); | ||
78 | |||
79 | // associate texture with FBO | ||
80 | ccglFramebufferTexture2D(CC_GL_FRAMEBUFFER, CC_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_.name, 0); | ||
81 | |||
82 | // check if it worked (probably worth doing :) ) | ||
83 | GLuint status = ccglCheckFramebufferStatus(CC_GL_FRAMEBUFFER); | ||
84 | if (status != CC_GL_FRAMEBUFFER_COMPLETE) | ||
85 | { | ||
86 | [NSException raise:@"Render Texture" format:@"Could not attach texture to framebuffer"]; | ||
87 | } | ||
88 | [texture_ setAliasTexParameters]; | ||
89 | |||
90 | sprite_ = [CCSprite spriteWithTexture:texture_]; | ||
91 | |||
92 | [texture_ release]; | ||
93 | [sprite_ setScaleY:-1]; | ||
94 | [self addChild:sprite_]; | ||
95 | |||
96 | // issue #937 | ||
97 | [sprite_ setBlendFunc:(ccBlendFunc){GL_ONE, GL_ONE_MINUS_SRC_ALPHA}]; | ||
98 | |||
99 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, oldFBO_); | ||
100 | } | ||
101 | return self; | ||
102 | } | ||
103 | |||
104 | -(void)dealloc | ||
105 | { | ||
106 | // [self removeAllChildrenWithCleanup:YES]; | ||
107 | ccglDeleteFramebuffers(1, &fbo_); | ||
108 | [super dealloc]; | ||
109 | } | ||
110 | |||
111 | -(void)begin | ||
112 | { | ||
113 | // Save the current matrix | ||
114 | glPushMatrix(); | ||
115 | |||
116 | CGSize texSize = [texture_ contentSizeInPixels]; | ||
117 | |||
118 | |||
119 | // Calculate the adjustment ratios based on the old and new projections | ||
120 | CGSize size = [[CCDirector sharedDirector] displaySizeInPixels]; | ||
121 | float widthRatio = size.width / texSize.width; | ||
122 | float heightRatio = size.height / texSize.height; | ||
123 | |||
124 | |||
125 | // Adjust the orthographic propjection and viewport | ||
126 | ccglOrtho((float)-1.0 / widthRatio, (float)1.0 / widthRatio, (float)-1.0 / heightRatio, (float)1.0 / heightRatio, -1,1); | ||
127 | glViewport(0, 0, texSize.width, texSize.height); | ||
128 | |||
129 | |||
130 | glGetIntegerv(CC_GL_FRAMEBUFFER_BINDING, &oldFBO_); | ||
131 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, fbo_);//Will direct drawing to the frame buffer created above | ||
132 | |||
133 | // Issue #1145 | ||
134 | // There is no need to enable the default GL states here | ||
135 | // but since CCRenderTexture is mostly used outside the "render" loop | ||
136 | // these states needs to be enabled. | ||
137 | // Since this bug was discovered in API-freeze (very close of 1.0 release) | ||
138 | // This bug won't be fixed to prevent incompatibilities with code. | ||
139 | // | ||
140 | // If you understand the above mentioned message, then you can comment the following line | ||
141 | // and enable the gl states manually, in case you need them. | ||
142 | CC_ENABLE_DEFAULT_GL_STATES(); | ||
143 | } | ||
144 | |||
145 | -(void)beginWithClear:(float)r g:(float)g b:(float)b a:(float)a | ||
146 | { | ||
147 | [self begin]; | ||
148 | |||
149 | // save clear color | ||
150 | GLfloat clearColor[4]; | ||
151 | glGetFloatv(GL_COLOR_CLEAR_VALUE,clearColor); | ||
152 | |||
153 | glClearColor(r, g, b, a); | ||
154 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||
155 | |||
156 | // restore clear color | ||
157 | glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); | ||
158 | } | ||
159 | |||
160 | -(void)end | ||
161 | { | ||
162 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, oldFBO_); | ||
163 | // Restore the original matrix and viewport | ||
164 | glPopMatrix(); | ||
165 | CGSize size = [[CCDirector sharedDirector] displaySizeInPixels]; | ||
166 | glViewport(0, 0, size.width, size.height); | ||
167 | } | ||
168 | |||
169 | -(void)clear:(float)r g:(float)g b:(float)b a:(float)a | ||
170 | { | ||
171 | [self beginWithClear:r g:g b:b a:a]; | ||
172 | [self end]; | ||
173 | } | ||
174 | |||
175 | #pragma mark RenderTexture - Save Image | ||
176 | |||
177 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
178 | -(BOOL)saveBuffer:(NSString*)name | ||
179 | { | ||
180 | return [self saveBuffer:name format:kCCImageFormatJPG]; | ||
181 | } | ||
182 | |||
183 | -(BOOL)saveBuffer:(NSString*)fileName format:(int)format | ||
184 | { | ||
185 | NSString *fullPath = [CCFileUtils fullPathFromRelativePath:fileName]; | ||
186 | |||
187 | NSData *data = [self getUIImageAsDataFromBuffer:format]; | ||
188 | |||
189 | return [data writeToFile:fullPath atomically:YES]; | ||
190 | } | ||
191 | |||
192 | /* get buffer as UIImage */ | ||
193 | -(UIImage *)getUIImageFromBuffer | ||
194 | { | ||
195 | NSAssert(pixelFormat_ == kCCTexture2DPixelFormat_RGBA8888,@"only RGBA8888 can be saved as image"); | ||
196 | |||
197 | CGSize s = [texture_ contentSizeInPixels]; | ||
198 | int tx = s.width; | ||
199 | int ty = s.height; | ||
200 | |||
201 | int bitsPerComponent = 8; | ||
202 | int bitsPerPixel = 32; | ||
203 | int bytesPerPixel = (bitsPerComponent * 4)/8; | ||
204 | int bytesPerRow = bytesPerPixel * tx; | ||
205 | NSInteger myDataLength = bytesPerRow * ty; | ||
206 | |||
207 | NSMutableData *buffer = [[NSMutableData alloc] initWithCapacity:myDataLength]; | ||
208 | NSMutableData *pixels = [[NSMutableData alloc] initWithCapacity:myDataLength]; | ||
209 | |||
210 | if( ! (buffer && pixels) ) { | ||
211 | CCLOG(@"cocos2d: CCRenderTexture#getUIImageFromBuffer: not enough memory"); | ||
212 | [buffer release]; | ||
213 | [pixels release]; | ||
214 | return nil; | ||
215 | } | ||
216 | |||
217 | [self begin]; | ||
218 | glReadPixels(0,0,tx,ty,GL_RGBA,GL_UNSIGNED_BYTE, [buffer mutableBytes]); | ||
219 | [self end]; | ||
220 | |||
221 | // make data provider with data. | ||
222 | |||
223 | CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault; | ||
224 | CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, [buffer mutableBytes], myDataLength, NULL); | ||
225 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); | ||
226 | CGImageRef iref = CGImageCreate(tx, ty, | ||
227 | bitsPerComponent, bitsPerPixel, bytesPerRow, | ||
228 | colorSpaceRef, bitmapInfo, provider, | ||
229 | NULL, false, | ||
230 | kCGRenderingIntentDefault); | ||
231 | |||
232 | CGContextRef context = CGBitmapContextCreate([pixels mutableBytes], tx, | ||
233 | ty, CGImageGetBitsPerComponent(iref), | ||
234 | CGImageGetBytesPerRow(iref), CGImageGetColorSpace(iref), | ||
235 | bitmapInfo); | ||
236 | CGContextTranslateCTM(context, 0.0f, ty); | ||
237 | CGContextScaleCTM(context, 1.0f, -1.0f); | ||
238 | CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, tx, ty), iref); | ||
239 | CGImageRef outputRef = CGBitmapContextCreateImage(context); | ||
240 | UIImage* image = [[UIImage alloc] initWithCGImage:outputRef]; | ||
241 | |||
242 | CGImageRelease(iref); | ||
243 | CGContextRelease(context); | ||
244 | CGColorSpaceRelease(colorSpaceRef); | ||
245 | CGDataProviderRelease(provider); | ||
246 | CGImageRelease(outputRef); | ||
247 | |||
248 | [pixels release]; | ||
249 | [buffer release]; | ||
250 | |||
251 | return [image autorelease]; | ||
252 | } | ||
253 | |||
254 | -(NSData*)getUIImageAsDataFromBuffer:(int) format | ||
255 | { | ||
256 | NSAssert(pixelFormat_ == kCCTexture2DPixelFormat_RGBA8888,@"only RGBA8888 can be saved as image"); | ||
257 | |||
258 | CGSize s = [texture_ contentSizeInPixels]; | ||
259 | int tx = s.width; | ||
260 | int ty = s.height; | ||
261 | |||
262 | int bitsPerComponent=8; | ||
263 | int bitsPerPixel=32; | ||
264 | |||
265 | int bytesPerRow = (bitsPerPixel/8) * tx; | ||
266 | NSInteger myDataLength = bytesPerRow * ty; | ||
267 | |||
268 | GLubyte *buffer = malloc(sizeof(GLubyte)*myDataLength); | ||
269 | GLubyte *pixels = malloc(sizeof(GLubyte)*myDataLength); | ||
270 | |||
271 | if( ! (buffer && pixels) ) { | ||
272 | CCLOG(@"cocos2d: CCRenderTexture#getUIImageFromBuffer: not enough memory"); | ||
273 | free(buffer); | ||
274 | free(pixels); | ||
275 | return nil; | ||
276 | } | ||
277 | |||
278 | [self begin]; | ||
279 | glReadPixels(0,0,tx,ty,GL_RGBA,GL_UNSIGNED_BYTE, buffer); | ||
280 | [self end]; | ||
281 | |||
282 | int x,y; | ||
283 | |||
284 | for(y = 0; y <ty; y++) { | ||
285 | for(x = 0; x <tx * 4; x++) { | ||
286 | pixels[((ty - 1 - y) * tx * 4 + x)] = buffer[(y * 4 * tx + x)]; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | NSData* data; | ||
291 | |||
292 | if (format == kCCImageFormatRawData) | ||
293 | { | ||
294 | free(buffer); | ||
295 | //data frees buffer when it is deallocated | ||
296 | data = [NSData dataWithBytesNoCopy:pixels length:myDataLength]; | ||
297 | |||
298 | } else { | ||
299 | |||
300 | /* | ||
301 | CGImageCreate(size_t width, size_t height, | ||
302 | size_t bitsPerComponent, size_t bitsPerPixel, size_t bytesPerRow, | ||
303 | CGColorSpaceRef space, CGBitmapInfo bitmapInfo, CGDataProviderRef provider, | ||
304 | const CGFloat decode[], bool shouldInterpolate, | ||
305 | CGColorRenderingIntent intent) | ||
306 | */ | ||
307 | // make data provider with data. | ||
308 | CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault; | ||
309 | CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, myDataLength, NULL); | ||
310 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); | ||
311 | CGImageRef iref = CGImageCreate(tx, ty, | ||
312 | bitsPerComponent, bitsPerPixel, bytesPerRow, | ||
313 | colorSpaceRef, bitmapInfo, provider, | ||
314 | NULL, false, | ||
315 | kCGRenderingIntentDefault); | ||
316 | |||
317 | UIImage* image = [[UIImage alloc] initWithCGImage:iref]; | ||
318 | |||
319 | CGImageRelease(iref); | ||
320 | CGColorSpaceRelease(colorSpaceRef); | ||
321 | CGDataProviderRelease(provider); | ||
322 | |||
323 | |||
324 | |||
325 | if (format == kCCImageFormatPNG) | ||
326 | data = UIImagePNGRepresentation(image); | ||
327 | else | ||
328 | data = UIImageJPEGRepresentation(image, 1.0f); | ||
329 | |||
330 | [image release]; | ||
331 | |||
332 | free(pixels); | ||
333 | free(buffer); | ||
334 | } | ||
335 | |||
336 | return data; | ||
337 | } | ||
338 | |||
339 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
340 | @end | ||
diff --git a/libs/cocos2d/CCRibbon.h b/libs/cocos2d/CCRibbon.h new file mode 100755 index 0000000..53898e6 --- /dev/null +++ b/libs/cocos2d/CCRibbon.h | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008, 2009 Jason Booth | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCNode.h" | ||
28 | #import "CCTexture2D.h" | ||
29 | #import "CCProtocols.h" | ||
30 | #import "Platforms/CCGL.h" | ||
31 | |||
32 | /** | ||
33 | * A CCRibbon is a dynamically generated list of polygons drawn as a single or series | ||
34 | * of triangle strips. The primary use of CCRibbon is as the drawing class of Motion Streak, | ||
35 | * but it is quite useful on it's own. When manually drawing a ribbon, you can call addPointAt | ||
36 | * and pass in the parameters for the next location in the ribbon. The system will automatically | ||
37 | * generate new polygons, texture them accourding to your texture width, etc, etc. | ||
38 | * | ||
39 | * CCRibbon data is stored in a CCRibbonSegment class. This class statically allocates enough verticies and | ||
40 | * texture coordinates for 50 locations (100 verts or 48 triangles). The ribbon class will allocate | ||
41 | * new segments when they are needed, and reuse old ones if available. The idea is to avoid constantly | ||
42 | * allocating new memory and prefer a more static method. However, since there is no way to determine | ||
43 | * the maximum size of some ribbons (motion streaks), a truely static allocation is not possible. | ||
44 | * | ||
45 | * @since v0.8.1 | ||
46 | */ | ||
47 | @interface CCRibbon : CCNode <CCTextureProtocol> | ||
48 | { | ||
49 | NSMutableArray* segments_; | ||
50 | NSMutableArray* deletedSegments_; | ||
51 | |||
52 | CGPoint lastPoint1_; | ||
53 | CGPoint lastPoint2_; | ||
54 | CGPoint lastLocation_; | ||
55 | int vertCount_; | ||
56 | float texVPos_; | ||
57 | float curTime_; | ||
58 | float fadeTime_; | ||
59 | float delta_; | ||
60 | float lastWidth_; | ||
61 | float lastSign_; | ||
62 | BOOL pastFirstPoint_; | ||
63 | |||
64 | // Texture used | ||
65 | CCTexture2D* texture_; | ||
66 | |||
67 | // texture length | ||
68 | float textureLength_; | ||
69 | |||
70 | // RGBA protocol | ||
71 | ccColor4B color_; | ||
72 | |||
73 | // blend func | ||
74 | ccBlendFunc blendFunc_; | ||
75 | } | ||
76 | |||
77 | /** Texture used by the ribbon. Conforms to CCTextureProtocol protocol */ | ||
78 | @property (nonatomic,readwrite,retain) CCTexture2D* texture; | ||
79 | |||
80 | /** Texture lengths in pixels */ | ||
81 | @property (nonatomic,readwrite) float textureLength; | ||
82 | |||
83 | /** GL blendind function */ | ||
84 | @property (nonatomic,readwrite,assign) ccBlendFunc blendFunc; | ||
85 | |||
86 | /** color used by the Ribbon (RGBA) */ | ||
87 | @property (nonatomic,readwrite) ccColor4B color; | ||
88 | |||
89 | /** creates the ribbon */ | ||
90 | +(id)ribbonWithWidth:(float)w image:(NSString*)path length:(float)l color:(ccColor4B)color fade:(float)fade; | ||
91 | /** init the ribbon */ | ||
92 | -(id)initWithWidth:(float)w image:(NSString*)path length:(float)l color:(ccColor4B)color fade:(float)fade; | ||
93 | /** add a point to the ribbon */ | ||
94 | -(void)addPointAt:(CGPoint)location width:(float)w; | ||
95 | /** polling function */ | ||
96 | -(void)update:(ccTime)delta; | ||
97 | /** determine side of line */ | ||
98 | -(float)sideOfLine:(CGPoint)p l1:(CGPoint)l1 l2:(CGPoint)l2; | ||
99 | |||
100 | @end | ||
101 | |||
102 | /** object to hold ribbon segment data */ | ||
103 | @interface CCRibbonSegment : NSObject | ||
104 | { | ||
105 | @public | ||
106 | GLfloat verts[50*6]; | ||
107 | GLfloat coords[50*4]; | ||
108 | GLubyte colors[50*8]; | ||
109 | float creationTime[50]; | ||
110 | BOOL finished; | ||
111 | uint end; | ||
112 | uint begin; | ||
113 | } | ||
114 | -(id)init; | ||
115 | -(void)reset; | ||
116 | -(void)draw:(float)curTime fadeTime:(float)fadeTime color:(ccColor4B)color; | ||
117 | @end | ||
diff --git a/libs/cocos2d/CCRibbon.m b/libs/cocos2d/CCRibbon.m new file mode 100755 index 0000000..2d9acaa --- /dev/null +++ b/libs/cocos2d/CCRibbon.m | |||
@@ -0,0 +1,383 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008, 2009 Jason Booth | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | * A ribbon is a dynamically generated list of polygons drawn as a single or series | ||
27 | * of triangle strips. The primary use of Ribbon is as the drawing class of Motion Streak, | ||
28 | * but it is quite useful on it's own. When manually drawing a ribbon, you can call addPointAt | ||
29 | * and pass in the parameters for the next location in the ribbon. The system will automatically | ||
30 | * generate new polygons, texture them accourding to your texture width, etc, etc. | ||
31 | * | ||
32 | * Ribbon data is stored in a RibbonSegment class. This class statically allocates enough verticies and | ||
33 | * texture coordinates for 50 locations (100 verts or 48 triangles). The ribbon class will allocate | ||
34 | * new segments when they are needed, and reuse old ones if available. The idea is to avoid constantly | ||
35 | * allocating new memory and prefer a more static method. However, since there is no way to determine | ||
36 | * the maximum size of some ribbons (motion streaks), a truely static allocation is not possible. | ||
37 | * | ||
38 | */ | ||
39 | |||
40 | |||
41 | #import "CCRibbon.h" | ||
42 | #import "CCTextureCache.h" | ||
43 | #import "Support/CGPointExtension.h" | ||
44 | #import "ccMacros.h" | ||
45 | |||
46 | // | ||
47 | // Ribbon | ||
48 | // | ||
49 | @implementation CCRibbon | ||
50 | @synthesize blendFunc=blendFunc_; | ||
51 | @synthesize color=color_; | ||
52 | @synthesize textureLength = textureLength_; | ||
53 | |||
54 | +(id)ribbonWithWidth:(float)w image:(NSString*)path length:(float)l color:(ccColor4B)color fade:(float)fade | ||
55 | { | ||
56 | self = [[[self alloc] initWithWidth:w image:path length:l color:color fade:fade] autorelease]; | ||
57 | return self; | ||
58 | } | ||
59 | |||
60 | -(id)initWithWidth:(float)w image:(NSString*)path length:(float)l color:(ccColor4B)color fade:(float)fade | ||
61 | { | ||
62 | self = [super init]; | ||
63 | if (self) | ||
64 | { | ||
65 | |||
66 | segments_ = [[NSMutableArray alloc] init]; | ||
67 | deletedSegments_ = [[NSMutableArray alloc] init]; | ||
68 | |||
69 | /* 1 initial segment */ | ||
70 | CCRibbonSegment* seg = [[CCRibbonSegment alloc] init]; | ||
71 | [segments_ addObject:seg]; | ||
72 | [seg release]; | ||
73 | |||
74 | textureLength_ = l; | ||
75 | |||
76 | color_ = color; | ||
77 | fadeTime_ = fade; | ||
78 | lastLocation_ = CGPointZero; | ||
79 | lastWidth_ = w/2; | ||
80 | texVPos_ = 0.0f; | ||
81 | |||
82 | curTime_ = 0; | ||
83 | pastFirstPoint_ = NO; | ||
84 | |||
85 | /* XXX: | ||
86 | Ribbon, by default uses this blend function, which might not be correct | ||
87 | if you are using premultiplied alpha images, | ||
88 | but 99% you might want to use this blending function regarding of the texture | ||
89 | */ | ||
90 | blendFunc_.src = GL_SRC_ALPHA; | ||
91 | blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; | ||
92 | |||
93 | self.texture = [[CCTextureCache sharedTextureCache] addImage:path]; | ||
94 | |||
95 | /* default texture parameter */ | ||
96 | ccTexParams params = { GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT }; | ||
97 | [texture_ setTexParameters:¶ms]; | ||
98 | } | ||
99 | return self; | ||
100 | } | ||
101 | |||
102 | -(void)dealloc | ||
103 | { | ||
104 | [segments_ release]; | ||
105 | [deletedSegments_ release]; | ||
106 | [texture_ release]; | ||
107 | [super dealloc]; | ||
108 | } | ||
109 | |||
110 | // rotates a point around 0, 0 | ||
111 | -(CGPoint)rotatePoint:(CGPoint)vec rotation:(float)a | ||
112 | { | ||
113 | float xtemp = (vec.x * cosf(a)) - (vec.y * sinf(a)); | ||
114 | vec.y = (vec.x * sinf(a)) + (vec.y * cosf(a)); | ||
115 | vec.x = xtemp; | ||
116 | return vec; | ||
117 | } | ||
118 | |||
119 | -(void)update:(ccTime)delta | ||
120 | { | ||
121 | curTime_+= delta; | ||
122 | delta_ = delta; | ||
123 | } | ||
124 | |||
125 | -(float)sideOfLine:(CGPoint)p l1:(CGPoint)l1 l2:(CGPoint)l2 | ||
126 | { | ||
127 | CGPoint vp = ccpPerp(ccpSub(l1, l2)); | ||
128 | CGPoint vx = ccpSub(p, l1); | ||
129 | return ccpDot(vx, vp); | ||
130 | } | ||
131 | |||
132 | // adds a new segment to the ribbon | ||
133 | -(void)addPointAt:(CGPoint)location width:(float)w | ||
134 | { | ||
135 | location.x *= CC_CONTENT_SCALE_FACTOR(); | ||
136 | location.y *= CC_CONTENT_SCALE_FACTOR(); | ||
137 | |||
138 | w = w*0.5f; | ||
139 | // if this is the first point added, cache it and return | ||
140 | if (!pastFirstPoint_) | ||
141 | { | ||
142 | lastWidth_ = w; | ||
143 | lastLocation_ = location; | ||
144 | pastFirstPoint_ = YES; | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | CGPoint sub = ccpSub(lastLocation_, location); | ||
149 | float r = ccpToAngle(sub) + (float)M_PI_2; | ||
150 | CGPoint p1 = ccpAdd([self rotatePoint:ccp(-w, 0) rotation:r], location); | ||
151 | CGPoint p2 = ccpAdd([self rotatePoint:ccp(w, 0) rotation:r], location); | ||
152 | float len = sqrtf(powf(lastLocation_.x - location.x, 2) + powf(lastLocation_.y - location.y, 2)); | ||
153 | float tend = texVPos_ + len/textureLength_; | ||
154 | CCRibbonSegment* seg; | ||
155 | // grab last segment | ||
156 | seg = [segments_ lastObject]; | ||
157 | // lets kill old segments | ||
158 | for (CCRibbonSegment* seg2 in segments_) | ||
159 | { | ||
160 | if (seg2 != seg && seg2->finished) | ||
161 | { | ||
162 | [deletedSegments_ addObject:seg2]; | ||
163 | } | ||
164 | } | ||
165 | [segments_ removeObjectsInArray:deletedSegments_]; | ||
166 | // is the segment full? | ||
167 | if (seg->end >= 50) | ||
168 | [segments_ removeObjectsInArray:deletedSegments_]; | ||
169 | // grab last segment and append to it if it's not full | ||
170 | seg = [segments_ lastObject]; | ||
171 | // is the segment full? | ||
172 | if (seg->end >= 50) | ||
173 | { | ||
174 | CCRibbonSegment* newSeg; | ||
175 | // grab it from the cache if we can | ||
176 | if ([deletedSegments_ count] > 0) | ||
177 | { | ||
178 | newSeg = [deletedSegments_ objectAtIndex:0]; | ||
179 | [newSeg retain]; // will be released later | ||
180 | [deletedSegments_ removeObject:newSeg]; | ||
181 | [newSeg reset]; | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | newSeg = [[CCRibbonSegment alloc] init]; // will be released later | ||
186 | } | ||
187 | |||
188 | newSeg->creationTime[0] = seg->creationTime[seg->end - 1]; | ||
189 | int v = (seg->end-1)*6; | ||
190 | int c = (seg->end-1)*4; | ||
191 | newSeg->verts[0] = seg->verts[v]; | ||
192 | newSeg->verts[1] = seg->verts[v+1]; | ||
193 | newSeg->verts[2] = seg->verts[v+2]; | ||
194 | newSeg->verts[3] = seg->verts[v+3]; | ||
195 | newSeg->verts[4] = seg->verts[v+4]; | ||
196 | newSeg->verts[5] = seg->verts[v+5]; | ||
197 | |||
198 | newSeg->coords[0] = seg->coords[c]; | ||
199 | newSeg->coords[1] = seg->coords[c+1]; | ||
200 | newSeg->coords[2] = seg->coords[c+2]; | ||
201 | newSeg->coords[3] = seg->coords[c+3]; | ||
202 | newSeg->end++; | ||
203 | seg = newSeg; | ||
204 | [segments_ addObject:seg]; | ||
205 | [newSeg release]; // it was retained before | ||
206 | |||
207 | } | ||
208 | if (seg->end == 0) | ||
209 | { | ||
210 | // first edge has to get rotation from the first real polygon | ||
211 | CGPoint lp1 = ccpAdd([self rotatePoint:ccp(-lastWidth_, 0) rotation:r], lastLocation_); | ||
212 | CGPoint lp2 = ccpAdd([self rotatePoint:ccp(+lastWidth_, 0) rotation:r], lastLocation_); | ||
213 | seg->creationTime[0] = curTime_ - delta_; | ||
214 | seg->verts[0] = lp1.x; | ||
215 | seg->verts[1] = lp1.y; | ||
216 | seg->verts[2] = 0.0f; | ||
217 | seg->verts[3] = lp2.x; | ||
218 | seg->verts[4] = lp2.y; | ||
219 | seg->verts[5] = 0.0f; | ||
220 | seg->coords[0] = 0.0f; | ||
221 | seg->coords[1] = texVPos_; | ||
222 | seg->coords[2] = 1.0f; | ||
223 | seg->coords[3] = texVPos_; | ||
224 | seg->end++; | ||
225 | } | ||
226 | |||
227 | int v = seg->end*6; | ||
228 | int c = seg->end*4; | ||
229 | // add new vertex | ||
230 | seg->creationTime[seg->end] = curTime_; | ||
231 | seg->verts[v] = p1.x; | ||
232 | seg->verts[v+1] = p1.y; | ||
233 | seg->verts[v+2] = 0.0f; | ||
234 | seg->verts[v+3] = p2.x; | ||
235 | seg->verts[v+4] = p2.y; | ||
236 | seg->verts[v+5] = 0.0f; | ||
237 | |||
238 | |||
239 | seg->coords[c] = 0.0f; | ||
240 | seg->coords[c+1] = tend; | ||
241 | seg->coords[c+2] = 1.0f; | ||
242 | seg->coords[c+3] = tend; | ||
243 | |||
244 | texVPos_ = tend; | ||
245 | lastLocation_ = location; | ||
246 | lastPoint1_ = p1; | ||
247 | lastPoint2_ = p2; | ||
248 | lastWidth_ = w; | ||
249 | seg->end++; | ||
250 | } | ||
251 | |||
252 | -(void) draw | ||
253 | { | ||
254 | [super draw]; | ||
255 | |||
256 | if ([segments_ count] > 0) | ||
257 | { | ||
258 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
259 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
260 | // Unneeded states: GL_COLOR_ARRAY | ||
261 | glDisableClientState(GL_COLOR_ARRAY); | ||
262 | |||
263 | glBindTexture(GL_TEXTURE_2D, [texture_ name]); | ||
264 | |||
265 | BOOL newBlend = blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST; | ||
266 | if( newBlend ) | ||
267 | glBlendFunc( blendFunc_.src, blendFunc_.dst ); | ||
268 | |||
269 | for (CCRibbonSegment* seg in segments_) | ||
270 | [seg draw:curTime_ fadeTime:fadeTime_ color:color_]; | ||
271 | |||
272 | if( newBlend ) | ||
273 | glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); | ||
274 | |||
275 | // restore default GL state | ||
276 | glEnableClientState( GL_COLOR_ARRAY ); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | #pragma mark Ribbon - CocosNodeTexture protocol | ||
281 | -(void) setTexture:(CCTexture2D*) texture | ||
282 | { | ||
283 | [texture_ release]; | ||
284 | texture_ = [texture retain]; | ||
285 | [self setContentSizeInPixels: texture.contentSizeInPixels]; | ||
286 | /* XXX Don't update blending function in Ribbons */ | ||
287 | } | ||
288 | |||
289 | -(CCTexture2D*) texture | ||
290 | { | ||
291 | return texture_; | ||
292 | } | ||
293 | |||
294 | @end | ||
295 | |||
296 | |||
297 | #pragma mark - | ||
298 | #pragma mark RibbonSegment | ||
299 | |||
300 | @implementation CCRibbonSegment | ||
301 | |||
302 | -(id)init | ||
303 | { | ||
304 | self = [super init]; | ||
305 | if (self) | ||
306 | { | ||
307 | [self reset]; | ||
308 | } | ||
309 | return self; | ||
310 | } | ||
311 | |||
312 | - (NSString*) description | ||
313 | { | ||
314 | return [NSString stringWithFormat:@"<%@ = %08X | end = %i, begin = %i>", [self class], self, end, begin]; | ||
315 | } | ||
316 | |||
317 | - (void) dealloc | ||
318 | { | ||
319 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
320 | [super dealloc]; | ||
321 | } | ||
322 | |||
323 | -(void)reset | ||
324 | { | ||
325 | end = 0; | ||
326 | begin = 0; | ||
327 | finished = NO; | ||
328 | } | ||
329 | |||
330 | -(void)draw:(float)curTime fadeTime:(float)fadeTime color:(ccColor4B)color | ||
331 | { | ||
332 | GLubyte r = color.r; | ||
333 | GLubyte g = color.g; | ||
334 | GLubyte b = color.b; | ||
335 | GLubyte a = color.a; | ||
336 | |||
337 | if (begin < 50) | ||
338 | { | ||
339 | // the motion streak class will call update and cause time to change, thus, if curTime_ != 0 | ||
340 | // we have to generate alpha for the ribbon each frame. | ||
341 | if (curTime == 0) | ||
342 | { | ||
343 | // no alpha over time, so just set the color | ||
344 | glColor4ub(r,g,b,a); | ||
345 | } | ||
346 | else | ||
347 | { | ||
348 | // generate alpha/color for each point | ||
349 | glEnableClientState(GL_COLOR_ARRAY); | ||
350 | uint i = begin; | ||
351 | for (; i < end; ++i) | ||
352 | { | ||
353 | int idx = i*8; | ||
354 | colors[idx] = r; | ||
355 | colors[idx+1] = g; | ||
356 | colors[idx+2] = b; | ||
357 | colors[idx+4] = r; | ||
358 | colors[idx+5] = g; | ||
359 | colors[idx+6] = b; | ||
360 | float alive = ((curTime - creationTime[i]) / fadeTime); | ||
361 | if (alive > 1) | ||
362 | { | ||
363 | begin++; | ||
364 | colors[idx+3] = 0; | ||
365 | colors[idx+7] = 0; | ||
366 | } | ||
367 | else | ||
368 | { | ||
369 | colors[idx+3] = (GLubyte)(255.f - (alive * 255.f)); | ||
370 | colors[idx+7] = colors[idx+3]; | ||
371 | } | ||
372 | } | ||
373 | glColorPointer(4, GL_UNSIGNED_BYTE, 0, &colors[begin*8]); | ||
374 | } | ||
375 | glVertexPointer(3, GL_FLOAT, 0, &verts[begin*6]); | ||
376 | glTexCoordPointer(2, GL_FLOAT, 0, &coords[begin*4]); | ||
377 | glDrawArrays(GL_TRIANGLE_STRIP, 0, (end - begin) * 2); | ||
378 | } | ||
379 | else | ||
380 | finished = YES; | ||
381 | } | ||
382 | @end | ||
383 | |||
diff --git a/libs/cocos2d/CCScene.h b/libs/cocos2d/CCScene.h new file mode 100755 index 0000000..1d104bc --- /dev/null +++ b/libs/cocos2d/CCScene.h | |||
@@ -0,0 +1,43 @@ | |||
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 | #import "CCNode.h" | ||
29 | |||
30 | /** CCScene is a subclass of CCNode that is used only as an abstract concept. | ||
31 | |||
32 | CCScene an CCNode are almost identical with the difference that CCScene has it's | ||
33 | anchor point (by default) at the center of the screen. | ||
34 | |||
35 | For the moment CCScene has no other logic than that, but in future releases it might have | ||
36 | additional logic. | ||
37 | |||
38 | It is a good practice to use and CCScene as the parent of all your nodes. | ||
39 | */ | ||
40 | @interface CCScene : CCNode | ||
41 | { | ||
42 | } | ||
43 | @end | ||
diff --git a/libs/cocos2d/CCScene.m b/libs/cocos2d/CCScene.m new file mode 100755 index 0000000..e991d6e --- /dev/null +++ b/libs/cocos2d/CCScene.m | |||
@@ -0,0 +1,45 @@ | |||
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 | #import "CCScene.h" | ||
29 | #import "Support/CGPointExtension.h" | ||
30 | #import "CCDirector.h" | ||
31 | |||
32 | |||
33 | @implementation CCScene | ||
34 | -(id) init | ||
35 | { | ||
36 | if( (self=[super init]) ) { | ||
37 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
38 | self.isRelativeAnchorPoint = NO; | ||
39 | anchorPoint_ = ccp(0.5f, 0.5f); | ||
40 | [self setContentSize:s]; | ||
41 | } | ||
42 | |||
43 | return self; | ||
44 | } | ||
45 | @end | ||
diff --git a/libs/cocos2d/CCScheduler.h b/libs/cocos2d/CCScheduler.h new file mode 100755 index 0000000..122b8fe --- /dev/null +++ b/libs/cocos2d/CCScheduler.h | |||
@@ -0,0 +1,199 @@ | |||
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 | #import "Support/uthash.h" | ||
29 | #import "ccTypes.h" | ||
30 | |||
31 | typedef void (*TICK_IMP)(id, SEL, ccTime); | ||
32 | |||
33 | // | ||
34 | // CCTimer | ||
35 | // | ||
36 | /** Light weight timer */ | ||
37 | @interface CCTimer : NSObject | ||
38 | { | ||
39 | id target; | ||
40 | TICK_IMP impMethod; | ||
41 | |||
42 | ccTime elapsed; | ||
43 | |||
44 | @public // optimization | ||
45 | ccTime interval; | ||
46 | SEL selector; | ||
47 | } | ||
48 | |||
49 | /** interval in seconds */ | ||
50 | @property (nonatomic,readwrite,assign) ccTime interval; | ||
51 | |||
52 | /** Allocates a timer with a target and a selector. | ||
53 | */ | ||
54 | +(id) timerWithTarget:(id) t selector:(SEL)s; | ||
55 | |||
56 | /** Allocates a timer with a target, a selector and an interval in seconds. | ||
57 | */ | ||
58 | +(id) timerWithTarget:(id) t selector:(SEL)s interval:(ccTime)seconds; | ||
59 | |||
60 | /** Initializes a timer with a target and a selector. | ||
61 | */ | ||
62 | -(id) initWithTarget:(id) t selector:(SEL)s; | ||
63 | |||
64 | /** Initializes a timer with a target, a selector and an interval in seconds. | ||
65 | */ | ||
66 | -(id) initWithTarget:(id) t selector:(SEL)s interval:(ccTime)seconds; | ||
67 | |||
68 | |||
69 | /** triggers the timer */ | ||
70 | -(void) update: (ccTime) dt; | ||
71 | @end | ||
72 | |||
73 | |||
74 | |||
75 | // | ||
76 | // CCScheduler | ||
77 | // | ||
78 | /** Scheduler is responsible of triggering the scheduled callbacks. | ||
79 | You should not use NSTimer. Instead use this class. | ||
80 | |||
81 | There are 2 different types of callbacks (selectors): | ||
82 | |||
83 | - update selector: the 'update' selector will be called every frame. You can customize the priority. | ||
84 | - custom selector: A custom selector will be called every frame, or with a custom interval of time | ||
85 | |||
86 | The 'custom selectors' should be avoided when possible. It is faster, and consumes less memory to use the 'update selector'. | ||
87 | |||
88 | */ | ||
89 | |||
90 | struct _listEntry; | ||
91 | struct _hashSelectorEntry; | ||
92 | struct _hashUpdateEntry; | ||
93 | |||
94 | @interface CCScheduler : NSObject | ||
95 | { | ||
96 | ccTime timeScale_; | ||
97 | |||
98 | // | ||
99 | // "updates with priority" stuff | ||
100 | // | ||
101 | struct _listEntry *updatesNeg; // list of priority < 0 | ||
102 | struct _listEntry *updates0; // list priority == 0 | ||
103 | struct _listEntry *updatesPos; // list priority > 0 | ||
104 | struct _hashUpdateEntry *hashForUpdates; // hash used to fetch quickly the list entries for pause,delete,etc. | ||
105 | |||
106 | // Used for "selectors with interval" | ||
107 | struct _hashSelectorEntry *hashForSelectors; | ||
108 | struct _hashSelectorEntry *currentTarget; | ||
109 | BOOL currentTargetSalvaged; | ||
110 | |||
111 | // Optimization | ||
112 | TICK_IMP impMethod; | ||
113 | SEL updateSelector; | ||
114 | |||
115 | BOOL updateHashLocked; // If true unschedule will not remove anything from a hash. Elements will only be marked for deletion. | ||
116 | } | ||
117 | |||
118 | /** Modifies the time of all scheduled callbacks. | ||
119 | You can use this property to create a 'slow motion' or 'fast fordward' effect. | ||
120 | Default is 1.0. To create a 'slow motion' effect, use values below 1.0. | ||
121 | To create a 'fast fordward' effect, use values higher than 1.0. | ||
122 | @since v0.8 | ||
123 | @warning It will affect EVERY scheduled selector / action. | ||
124 | */ | ||
125 | @property (nonatomic,readwrite) ccTime timeScale; | ||
126 | |||
127 | /** returns a shared instance of the Scheduler */ | ||
128 | +(CCScheduler *)sharedScheduler; | ||
129 | |||
130 | /** purges the shared scheduler. It releases the retained instance. | ||
131 | @since v0.99.0 | ||
132 | */ | ||
133 | +(void)purgeSharedScheduler; | ||
134 | |||
135 | /** 'tick' the scheduler. | ||
136 | You should NEVER call this method, unless you know what you are doing. | ||
137 | */ | ||
138 | -(void) tick:(ccTime)dt; | ||
139 | |||
140 | /** The scheduled method will be called every 'interval' seconds. | ||
141 | If paused is YES, then it won't be called until it is resumed. | ||
142 | If 'interval' is 0, it will be called every frame, but if so, it recommened to use 'scheduleUpdateForTarget:' instead. | ||
143 | If the selector is already scheduled, then only the interval parameter will be updated without re-scheduling it again. | ||
144 | |||
145 | @since v0.99.3 | ||
146 | */ | ||
147 | -(void) scheduleSelector:(SEL)selector forTarget:(id)target interval:(ccTime)interval paused:(BOOL)paused; | ||
148 | |||
149 | /** Schedules the 'update' selector for a given target with a given priority. | ||
150 | The 'update' selector will be called every frame. | ||
151 | The lower the priority, the earlier it is called. | ||
152 | @since v0.99.3 | ||
153 | */ | ||
154 | -(void) scheduleUpdateForTarget:(id)target priority:(NSInteger)priority paused:(BOOL)paused; | ||
155 | |||
156 | /** Unshedules a selector for a given target. | ||
157 | If you want to unschedule the "update", use unscheudleUpdateForTarget. | ||
158 | @since v0.99.3 | ||
159 | */ | ||
160 | -(void) unscheduleSelector:(SEL)selector forTarget:(id)target; | ||
161 | |||
162 | /** Unschedules the update selector for a given target | ||
163 | @since v0.99.3 | ||
164 | */ | ||
165 | -(void) unscheduleUpdateForTarget:(id)target; | ||
166 | |||
167 | /** Unschedules all selectors for a given target. | ||
168 | This also includes the "update" selector. | ||
169 | @since v0.99.3 | ||
170 | */ | ||
171 | -(void) unscheduleAllSelectorsForTarget:(id)target; | ||
172 | |||
173 | /** Unschedules all selectors from all targets. | ||
174 | You should NEVER call this method, unless you know what you are doing. | ||
175 | |||
176 | @since v0.99.3 | ||
177 | */ | ||
178 | -(void) unscheduleAllSelectors; | ||
179 | |||
180 | /** Pauses the target. | ||
181 | All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed. | ||
182 | If the target is not present, nothing happens. | ||
183 | @since v0.99.3 | ||
184 | */ | ||
185 | -(void) pauseTarget:(id)target; | ||
186 | |||
187 | /** Resumes the target. | ||
188 | The 'target' will be unpaused, so all schedule selectors/update will be 'ticked' again. | ||
189 | If the target is not present, nothing happens. | ||
190 | @since v0.99.3 | ||
191 | */ | ||
192 | -(void) resumeTarget:(id)target; | ||
193 | |||
194 | /** Returns whether or not the target is paused | ||
195 | @since v1.0.0 | ||
196 | */ | ||
197 | -(BOOL) isTargetPaused:(id)target; | ||
198 | |||
199 | @end | ||
diff --git a/libs/cocos2d/CCScheduler.m b/libs/cocos2d/CCScheduler.m new file mode 100755 index 0000000..a14ca10 --- /dev/null +++ b/libs/cocos2d/CCScheduler.m | |||
@@ -0,0 +1,657 @@ | |||
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 | // cocos2d imports | ||
28 | #import "CCScheduler.h" | ||
29 | #import "ccMacros.h" | ||
30 | #import "Support/uthash.h" | ||
31 | #import "Support/utlist.h" | ||
32 | #import "Support/ccCArray.h" | ||
33 | |||
34 | // | ||
35 | // Data structures | ||
36 | // | ||
37 | #pragma mark - | ||
38 | #pragma mark Data Structures | ||
39 | |||
40 | // A list double-linked list used for "updates with priority" | ||
41 | typedef struct _listEntry | ||
42 | { | ||
43 | struct _listEntry *prev, *next; | ||
44 | TICK_IMP impMethod; | ||
45 | id target; // not retained (retained by hashUpdateEntry) | ||
46 | NSInteger priority; | ||
47 | BOOL paused; | ||
48 | BOOL markedForDeletion; // selector will no longer be called and entry will be removed at end of the next tick | ||
49 | } tListEntry; | ||
50 | |||
51 | typedef struct _hashUpdateEntry | ||
52 | { | ||
53 | tListEntry **list; // Which list does it belong to ? | ||
54 | tListEntry *entry; // entry in the list | ||
55 | id target; // hash key (retained) | ||
56 | UT_hash_handle hh; | ||
57 | } tHashUpdateEntry; | ||
58 | |||
59 | // Hash Element used for "selectors with interval" | ||
60 | typedef struct _hashSelectorEntry | ||
61 | { | ||
62 | struct ccArray *timers; | ||
63 | id target; // hash key (retained) | ||
64 | unsigned int timerIndex; | ||
65 | CCTimer *currentTimer; | ||
66 | BOOL currentTimerSalvaged; | ||
67 | BOOL paused; | ||
68 | UT_hash_handle hh; | ||
69 | } tHashSelectorEntry; | ||
70 | |||
71 | |||
72 | |||
73 | // | ||
74 | // CCTimer | ||
75 | // | ||
76 | #pragma mark - | ||
77 | #pragma mark - CCTimer | ||
78 | |||
79 | @implementation CCTimer | ||
80 | |||
81 | @synthesize interval; | ||
82 | |||
83 | -(id) init | ||
84 | { | ||
85 | NSAssert(NO, @"CCTimer: Init not supported."); | ||
86 | [self release]; | ||
87 | return nil; | ||
88 | } | ||
89 | |||
90 | +(id) timerWithTarget:(id)t selector:(SEL)s | ||
91 | { | ||
92 | return [[[self alloc] initWithTarget:t selector:s] autorelease]; | ||
93 | } | ||
94 | |||
95 | +(id) timerWithTarget:(id)t selector:(SEL)s interval:(ccTime) i | ||
96 | { | ||
97 | return [[[self alloc] initWithTarget:t selector:s interval:i] autorelease]; | ||
98 | } | ||
99 | |||
100 | -(id) initWithTarget:(id)t selector:(SEL)s | ||
101 | { | ||
102 | return [self initWithTarget:t selector:s interval:0]; | ||
103 | } | ||
104 | |||
105 | -(id) initWithTarget:(id)t selector:(SEL)s interval:(ccTime) seconds | ||
106 | { | ||
107 | if( (self=[super init]) ) { | ||
108 | #if COCOS2D_DEBUG | ||
109 | NSMethodSignature *sig = [t methodSignatureForSelector:s]; | ||
110 | NSAssert(sig !=0 , @"Signature not found for selector - does it have the following form? -(void) name: (ccTime) dt"); | ||
111 | #endif | ||
112 | |||
113 | // target is not retained. It is retained in the hash structure | ||
114 | target = t; | ||
115 | selector = s; | ||
116 | impMethod = (TICK_IMP) [t methodForSelector:s]; | ||
117 | elapsed = -1; | ||
118 | interval = seconds; | ||
119 | } | ||
120 | return self; | ||
121 | } | ||
122 | |||
123 | - (NSString*) description | ||
124 | { | ||
125 | return [NSString stringWithFormat:@"<%@ = %08X | target:%@ selector:(%@)>", [self class], self, [target class], NSStringFromSelector(selector)]; | ||
126 | } | ||
127 | |||
128 | -(void) dealloc | ||
129 | { | ||
130 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
131 | [super dealloc]; | ||
132 | } | ||
133 | |||
134 | -(void) update: (ccTime) dt | ||
135 | { | ||
136 | if( elapsed == - 1) | ||
137 | elapsed = 0; | ||
138 | else | ||
139 | elapsed += dt; | ||
140 | if( elapsed >= interval ) { | ||
141 | impMethod(target, selector, elapsed); | ||
142 | elapsed = 0; | ||
143 | } | ||
144 | } | ||
145 | @end | ||
146 | |||
147 | // | ||
148 | // CCScheduler | ||
149 | // | ||
150 | #pragma mark - | ||
151 | #pragma mark - CCScheduler | ||
152 | |||
153 | @interface CCScheduler (Private) | ||
154 | -(void) removeHashElement:(tHashSelectorEntry*)element; | ||
155 | @end | ||
156 | |||
157 | @implementation CCScheduler | ||
158 | |||
159 | static CCScheduler *sharedScheduler; | ||
160 | |||
161 | @synthesize timeScale = timeScale_; | ||
162 | |||
163 | + (CCScheduler *)sharedScheduler | ||
164 | { | ||
165 | if (!sharedScheduler) | ||
166 | sharedScheduler = [[CCScheduler alloc] init]; | ||
167 | |||
168 | return sharedScheduler; | ||
169 | } | ||
170 | |||
171 | +(id)alloc | ||
172 | { | ||
173 | NSAssert(sharedScheduler == nil, @"Attempted to allocate a second instance of a singleton."); | ||
174 | return [super alloc]; | ||
175 | } | ||
176 | |||
177 | +(void)purgeSharedScheduler | ||
178 | { | ||
179 | [sharedScheduler release]; | ||
180 | sharedScheduler = nil; | ||
181 | } | ||
182 | |||
183 | - (id) init | ||
184 | { | ||
185 | if( (self=[super init]) ) { | ||
186 | timeScale_ = 1.0f; | ||
187 | |||
188 | // used to trigger CCTimer#update | ||
189 | updateSelector = @selector(update:); | ||
190 | impMethod = (TICK_IMP) [CCTimer instanceMethodForSelector:updateSelector]; | ||
191 | |||
192 | // updates with priority | ||
193 | updates0 = NULL; | ||
194 | updatesNeg = NULL; | ||
195 | updatesPos = NULL; | ||
196 | hashForUpdates = NULL; | ||
197 | |||
198 | // selectors with interval | ||
199 | currentTarget = nil; | ||
200 | currentTargetSalvaged = NO; | ||
201 | hashForSelectors = nil; | ||
202 | updateHashLocked = NO; | ||
203 | } | ||
204 | |||
205 | return self; | ||
206 | } | ||
207 | |||
208 | - (void) dealloc | ||
209 | { | ||
210 | CCLOG(@"cocos2d: deallocing %@", self); | ||
211 | |||
212 | [self unscheduleAllSelectors]; | ||
213 | |||
214 | sharedScheduler = nil; | ||
215 | |||
216 | [super dealloc]; | ||
217 | } | ||
218 | |||
219 | |||
220 | #pragma mark CCScheduler - Custom Selectors | ||
221 | |||
222 | -(void) removeHashElement:(tHashSelectorEntry*)element | ||
223 | { | ||
224 | ccArrayFree(element->timers); | ||
225 | [element->target release]; | ||
226 | HASH_DEL(hashForSelectors, element); | ||
227 | free(element); | ||
228 | } | ||
229 | |||
230 | -(void) scheduleSelector:(SEL)selector forTarget:(id)target interval:(ccTime)interval paused:(BOOL)paused | ||
231 | { | ||
232 | NSAssert( selector != nil, @"Argument selector must be non-nil"); | ||
233 | NSAssert( target != nil, @"Argument target must be non-nil"); | ||
234 | |||
235 | tHashSelectorEntry *element = NULL; | ||
236 | HASH_FIND_INT(hashForSelectors, &target, element); | ||
237 | |||
238 | if( ! element ) { | ||
239 | element = calloc( sizeof( *element ), 1 ); | ||
240 | element->target = [target retain]; | ||
241 | HASH_ADD_INT( hashForSelectors, target, element ); | ||
242 | |||
243 | // Is this the 1st element ? Then set the pause level to all the selectors of this target | ||
244 | element->paused = paused; | ||
245 | |||
246 | } else | ||
247 | NSAssert( element->paused == paused, @"CCScheduler. Trying to schedule a selector with a pause value different than the target"); | ||
248 | |||
249 | |||
250 | if( element->timers == nil ) | ||
251 | element->timers = ccArrayNew(10); | ||
252 | else | ||
253 | { | ||
254 | for( unsigned int i=0; i< element->timers->num; i++ ) { | ||
255 | CCTimer *timer = element->timers->arr[i]; | ||
256 | if( selector == timer->selector ) { | ||
257 | CCLOG(@"CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.2f to %.2f", timer->interval, interval); | ||
258 | timer->interval = interval; | ||
259 | return; | ||
260 | } | ||
261 | } | ||
262 | ccArrayEnsureExtraCapacity(element->timers, 1); | ||
263 | } | ||
264 | |||
265 | CCTimer *timer = [[CCTimer alloc] initWithTarget:target selector:selector interval:interval]; | ||
266 | ccArrayAppendObject(element->timers, timer); | ||
267 | [timer release]; | ||
268 | } | ||
269 | |||
270 | -(void) unscheduleSelector:(SEL)selector forTarget:(id)target | ||
271 | { | ||
272 | // explicity handle nil arguments when removing an object | ||
273 | if( target==nil && selector==NULL) | ||
274 | return; | ||
275 | |||
276 | NSAssert( target != nil, @"Target MUST not be nil"); | ||
277 | NSAssert( selector != NULL, @"Selector MUST not be NULL"); | ||
278 | |||
279 | tHashSelectorEntry *element = NULL; | ||
280 | HASH_FIND_INT(hashForSelectors, &target, element); | ||
281 | |||
282 | if( element ) { | ||
283 | |||
284 | for( unsigned int i=0; i< element->timers->num; i++ ) { | ||
285 | CCTimer *timer = element->timers->arr[i]; | ||
286 | |||
287 | |||
288 | if( selector == timer->selector ) { | ||
289 | |||
290 | if( timer == element->currentTimer && !element->currentTimerSalvaged ) { | ||
291 | [element->currentTimer retain]; | ||
292 | element->currentTimerSalvaged = YES; | ||
293 | } | ||
294 | |||
295 | ccArrayRemoveObjectAtIndex(element->timers, i ); | ||
296 | |||
297 | // update timerIndex in case we are in tick:, looping over the actions | ||
298 | if( element->timerIndex >= i ) | ||
299 | element->timerIndex--; | ||
300 | |||
301 | if( element->timers->num == 0 ) { | ||
302 | if( currentTarget == element ) | ||
303 | currentTargetSalvaged = YES; | ||
304 | else | ||
305 | [self removeHashElement: element]; | ||
306 | } | ||
307 | return; | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | // Not Found | ||
313 | // NSLog(@"CCScheduler#unscheduleSelector:forTarget: selector not found: %@", selString); | ||
314 | |||
315 | } | ||
316 | |||
317 | #pragma mark CCScheduler - Update Specific | ||
318 | |||
319 | -(void) priorityIn:(tListEntry**)list target:(id)target priority:(NSInteger)priority paused:(BOOL)paused | ||
320 | { | ||
321 | tListEntry *listElement = malloc( sizeof(*listElement) ); | ||
322 | |||
323 | listElement->target = target; | ||
324 | listElement->priority = priority; | ||
325 | listElement->paused = paused; | ||
326 | listElement->impMethod = (TICK_IMP) [target methodForSelector:updateSelector]; | ||
327 | listElement->next = listElement->prev = NULL; | ||
328 | listElement->markedForDeletion = NO; | ||
329 | |||
330 | // empty list ? | ||
331 | if( ! *list ) { | ||
332 | DL_APPEND( *list, listElement ); | ||
333 | |||
334 | } else { | ||
335 | BOOL added = NO; | ||
336 | |||
337 | for( tListEntry *elem = *list; elem ; elem = elem->next ) { | ||
338 | if( priority < elem->priority ) { | ||
339 | |||
340 | if( elem == *list ) | ||
341 | DL_PREPEND(*list, listElement); | ||
342 | else { | ||
343 | listElement->next = elem; | ||
344 | listElement->prev = elem->prev; | ||
345 | |||
346 | elem->prev->next = listElement; | ||
347 | elem->prev = listElement; | ||
348 | } | ||
349 | |||
350 | added = YES; | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | // Not added? priority has the higher value. Append it. | ||
356 | if( !added ) | ||
357 | DL_APPEND(*list, listElement); | ||
358 | } | ||
359 | |||
360 | // update hash entry for quicker access | ||
361 | tHashUpdateEntry *hashElement = calloc( sizeof(*hashElement), 1 ); | ||
362 | hashElement->target = [target retain]; | ||
363 | hashElement->list = list; | ||
364 | hashElement->entry = listElement; | ||
365 | HASH_ADD_INT(hashForUpdates, target, hashElement ); | ||
366 | } | ||
367 | |||
368 | -(void) appendIn:(tListEntry**)list target:(id)target paused:(BOOL)paused | ||
369 | { | ||
370 | tListEntry *listElement = malloc( sizeof( * listElement ) ); | ||
371 | |||
372 | listElement->target = target; | ||
373 | listElement->paused = paused; | ||
374 | listElement->markedForDeletion = NO; | ||
375 | listElement->impMethod = (TICK_IMP) [target methodForSelector:updateSelector]; | ||
376 | |||
377 | DL_APPEND(*list, listElement); | ||
378 | |||
379 | |||
380 | // update hash entry for quicker access | ||
381 | tHashUpdateEntry *hashElement = calloc( sizeof(*hashElement), 1 ); | ||
382 | hashElement->target = [target retain]; | ||
383 | hashElement->list = list; | ||
384 | hashElement->entry = listElement; | ||
385 | HASH_ADD_INT(hashForUpdates, target, hashElement ); | ||
386 | } | ||
387 | |||
388 | -(void) scheduleUpdateForTarget:(id)target priority:(NSInteger)priority paused:(BOOL)paused | ||
389 | { | ||
390 | tHashUpdateEntry * hashElement = NULL; | ||
391 | HASH_FIND_INT(hashForUpdates, &target, hashElement); | ||
392 | if(hashElement) | ||
393 | { | ||
394 | #if COCOS2D_DEBUG >= 1 | ||
395 | NSAssert( hashElement->entry->markedForDeletion, @"CCScheduler: You can't re-schedule an 'update' selector'. Unschedule it first"); | ||
396 | #endif | ||
397 | // TODO : check if priority has changed! | ||
398 | |||
399 | hashElement->entry->markedForDeletion = NO; | ||
400 | return; | ||
401 | } | ||
402 | |||
403 | // most of the updates are going to be 0, that's way there | ||
404 | // is an special list for updates with priority 0 | ||
405 | if( priority == 0 ) | ||
406 | [self appendIn:&updates0 target:target paused:paused]; | ||
407 | |||
408 | else if( priority < 0 ) | ||
409 | [self priorityIn:&updatesNeg target:target priority:priority paused:paused]; | ||
410 | |||
411 | else // priority > 0 | ||
412 | [self priorityIn:&updatesPos target:target priority:priority paused:paused]; | ||
413 | } | ||
414 | |||
415 | - (void) removeUpdateFromHash:(tListEntry*)entry | ||
416 | { | ||
417 | tHashUpdateEntry * element = NULL; | ||
418 | |||
419 | HASH_FIND_INT(hashForUpdates, &entry->target, element); | ||
420 | if( element ) { | ||
421 | // list entry | ||
422 | DL_DELETE( *element->list, element->entry ); | ||
423 | free( element->entry ); | ||
424 | |||
425 | // hash entry | ||
426 | [element->target release]; | ||
427 | HASH_DEL( hashForUpdates, element); | ||
428 | free(element); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | -(void) unscheduleUpdateForTarget:(id)target | ||
433 | { | ||
434 | if( target == nil ) | ||
435 | return; | ||
436 | |||
437 | tHashUpdateEntry * element = NULL; | ||
438 | HASH_FIND_INT(hashForUpdates, &target, element); | ||
439 | if( element ) { | ||
440 | if(updateHashLocked) | ||
441 | element->entry->markedForDeletion = YES; | ||
442 | else | ||
443 | [self removeUpdateFromHash:element->entry]; | ||
444 | |||
445 | // // list entry | ||
446 | // DL_DELETE( *element->list, element->entry ); | ||
447 | // free( element->entry ); | ||
448 | // | ||
449 | // // hash entry | ||
450 | // [element->target release]; | ||
451 | // HASH_DEL( hashForUpdates, element); | ||
452 | // free(element); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | #pragma mark CCScheduler - Common for Update selector & Custom Selectors | ||
457 | |||
458 | -(void) unscheduleAllSelectors | ||
459 | { | ||
460 | // Custom Selectors | ||
461 | for(tHashSelectorEntry *element=hashForSelectors; element != NULL; ) { | ||
462 | id target = element->target; | ||
463 | element=element->hh.next; | ||
464 | [self unscheduleAllSelectorsForTarget:target]; | ||
465 | } | ||
466 | |||
467 | // Updates selectors | ||
468 | tListEntry *entry, *tmp; | ||
469 | DL_FOREACH_SAFE( updates0, entry, tmp ) { | ||
470 | [self unscheduleUpdateForTarget:entry->target]; | ||
471 | } | ||
472 | DL_FOREACH_SAFE( updatesNeg, entry, tmp ) { | ||
473 | [self unscheduleUpdateForTarget:entry->target]; | ||
474 | } | ||
475 | DL_FOREACH_SAFE( updatesPos, entry, tmp ) { | ||
476 | [self unscheduleUpdateForTarget:entry->target]; | ||
477 | } | ||
478 | |||
479 | } | ||
480 | |||
481 | -(void) unscheduleAllSelectorsForTarget:(id)target | ||
482 | { | ||
483 | // explicit nil handling | ||
484 | if( target == nil ) | ||
485 | return; | ||
486 | |||
487 | // Custom Selectors | ||
488 | tHashSelectorEntry *element = NULL; | ||
489 | HASH_FIND_INT(hashForSelectors, &target, element); | ||
490 | |||
491 | if( element ) { | ||
492 | if( ccArrayContainsObject(element->timers, element->currentTimer) && !element->currentTimerSalvaged ) { | ||
493 | [element->currentTimer retain]; | ||
494 | element->currentTimerSalvaged = YES; | ||
495 | } | ||
496 | ccArrayRemoveAllObjects(element->timers); | ||
497 | if( currentTarget == element ) | ||
498 | currentTargetSalvaged = YES; | ||
499 | else | ||
500 | [self removeHashElement:element]; | ||
501 | } | ||
502 | |||
503 | // Update Selector | ||
504 | [self unscheduleUpdateForTarget:target]; | ||
505 | } | ||
506 | |||
507 | -(void) resumeTarget:(id)target | ||
508 | { | ||
509 | NSAssert( target != nil, @"target must be non nil" ); | ||
510 | |||
511 | // Custom Selectors | ||
512 | tHashSelectorEntry *element = NULL; | ||
513 | HASH_FIND_INT(hashForSelectors, &target, element); | ||
514 | if( element ) | ||
515 | element->paused = NO; | ||
516 | |||
517 | // Update selector | ||
518 | tHashUpdateEntry * elementUpdate = NULL; | ||
519 | HASH_FIND_INT(hashForUpdates, &target, elementUpdate); | ||
520 | if( elementUpdate ) { | ||
521 | NSAssert( elementUpdate->entry != NULL, @"resumeTarget: unknown error"); | ||
522 | elementUpdate->entry->paused = NO; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | -(void) pauseTarget:(id)target | ||
527 | { | ||
528 | NSAssert( target != nil, @"target must be non nil" ); | ||
529 | |||
530 | // Custom selectors | ||
531 | tHashSelectorEntry *element = NULL; | ||
532 | HASH_FIND_INT(hashForSelectors, &target, element); | ||
533 | if( element ) | ||
534 | element->paused = YES; | ||
535 | |||
536 | // Update selector | ||
537 | tHashUpdateEntry * elementUpdate = NULL; | ||
538 | HASH_FIND_INT(hashForUpdates, &target, elementUpdate); | ||
539 | if( elementUpdate ) { | ||
540 | NSAssert( elementUpdate->entry != NULL, @"pauseTarget: unknown error"); | ||
541 | elementUpdate->entry->paused = YES; | ||
542 | } | ||
543 | |||
544 | } | ||
545 | |||
546 | -(BOOL) isTargetPaused:(id)target | ||
547 | { | ||
548 | NSAssert( target != nil, @"target must be non nil" ); | ||
549 | |||
550 | // Custom selectors | ||
551 | tHashSelectorEntry *element = NULL; | ||
552 | HASH_FIND_INT(hashForSelectors, &target, element); | ||
553 | if( element ) | ||
554 | { | ||
555 | return element->paused; | ||
556 | } | ||
557 | return NO; // should never get here | ||
558 | |||
559 | } | ||
560 | |||
561 | #pragma mark CCScheduler - Main Loop | ||
562 | |||
563 | -(void) tick: (ccTime) dt | ||
564 | { | ||
565 | updateHashLocked = YES; | ||
566 | |||
567 | if( timeScale_ != 1.0f ) | ||
568 | dt *= timeScale_; | ||
569 | |||
570 | // Iterate all over the Updates selectors | ||
571 | tListEntry *entry, *tmp; | ||
572 | |||
573 | // updates with priority < 0 | ||
574 | DL_FOREACH_SAFE( updatesNeg, entry, tmp ) { | ||
575 | if( ! entry->paused && !entry->markedForDeletion ) | ||
576 | entry->impMethod( entry->target, updateSelector, dt ); | ||
577 | } | ||
578 | |||
579 | // updates with priority == 0 | ||
580 | DL_FOREACH_SAFE( updates0, entry, tmp ) { | ||
581 | if( ! entry->paused && !entry->markedForDeletion ) | ||
582 | { | ||
583 | entry->impMethod( entry->target, updateSelector, dt ); | ||
584 | } | ||
585 | } | ||
586 | |||
587 | // updates with priority > 0 | ||
588 | DL_FOREACH_SAFE( updatesPos, entry, tmp ) { | ||
589 | if( ! entry->paused && !entry->markedForDeletion ) | ||
590 | entry->impMethod( entry->target, updateSelector, dt ); | ||
591 | } | ||
592 | |||
593 | // Iterate all over the custome selectors | ||
594 | for(tHashSelectorEntry *elt=hashForSelectors; elt != NULL; ) { | ||
595 | |||
596 | currentTarget = elt; | ||
597 | currentTargetSalvaged = NO; | ||
598 | |||
599 | if( ! currentTarget->paused ) { | ||
600 | |||
601 | // The 'timers' ccArray may change while inside this loop. | ||
602 | for( elt->timerIndex = 0; elt->timerIndex < elt->timers->num; elt->timerIndex++) { | ||
603 | elt->currentTimer = elt->timers->arr[elt->timerIndex]; | ||
604 | elt->currentTimerSalvaged = NO; | ||
605 | |||
606 | impMethod( elt->currentTimer, updateSelector, dt); | ||
607 | |||
608 | if( elt->currentTimerSalvaged ) { | ||
609 | // The currentTimer told the remove itself. To prevent the timer from | ||
610 | // accidentally deallocating itself before finishing its step, we retained | ||
611 | // it. Now that step is done, it's safe to release it. | ||
612 | [elt->currentTimer release]; | ||
613 | } | ||
614 | |||
615 | elt->currentTimer = nil; | ||
616 | } | ||
617 | } | ||
618 | |||
619 | // elt, at this moment, is still valid | ||
620 | // so it is safe to ask this here (issue #490) | ||
621 | elt = elt->hh.next; | ||
622 | |||
623 | // only delete currentTarget if no actions were scheduled during the cycle (issue #481) | ||
624 | if( currentTargetSalvaged && currentTarget->timers->num == 0 ) | ||
625 | [self removeHashElement:currentTarget]; | ||
626 | } | ||
627 | |||
628 | // delete all updates that are morked for deletion | ||
629 | // updates with priority < 0 | ||
630 | DL_FOREACH_SAFE( updatesNeg, entry, tmp ) { | ||
631 | if(entry->markedForDeletion ) | ||
632 | { | ||
633 | [self removeUpdateFromHash:entry]; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | // updates with priority == 0 | ||
638 | DL_FOREACH_SAFE( updates0, entry, tmp ) { | ||
639 | if(entry->markedForDeletion ) | ||
640 | { | ||
641 | [self removeUpdateFromHash:entry]; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | // updates with priority > 0 | ||
646 | DL_FOREACH_SAFE( updatesPos, entry, tmp ) { | ||
647 | if(entry->markedForDeletion ) | ||
648 | { | ||
649 | [self removeUpdateFromHash:entry]; | ||
650 | } | ||
651 | } | ||
652 | |||
653 | updateHashLocked = NO; | ||
654 | currentTarget = nil; | ||
655 | } | ||
656 | @end | ||
657 | |||
diff --git a/libs/cocos2d/CCSprite.h b/libs/cocos2d/CCSprite.h new file mode 100755 index 0000000..f01688e --- /dev/null +++ b/libs/cocos2d/CCSprite.h | |||
@@ -0,0 +1,351 @@ | |||
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 | #import "CCNode.h" | ||
29 | #import "CCProtocols.h" | ||
30 | #import "CCTextureAtlas.h" | ||
31 | |||
32 | @class CCSpriteBatchNode; | ||
33 | @class CCSpriteFrame; | ||
34 | @class CCAnimation; | ||
35 | |||
36 | #pragma mark CCSprite | ||
37 | |||
38 | #define CCSpriteIndexNotInitialized 0xffffffff /// CCSprite invalid index on the CCSpriteBatchode | ||
39 | |||
40 | /** | ||
41 | Whether or not an CCSprite will rotate, scale or translate with it's parent. | ||
42 | Useful in health bars, when you want that the health bar translates with it's parent but you don't | ||
43 | want it to rotate with its parent. | ||
44 | @since v0.99.0 | ||
45 | */ | ||
46 | typedef enum { | ||
47 | //! Translate with it's parent | ||
48 | CC_HONOR_PARENT_TRANSFORM_TRANSLATE = 1 << 0, | ||
49 | //! Rotate with it's parent | ||
50 | CC_HONOR_PARENT_TRANSFORM_ROTATE = 1 << 1, | ||
51 | //! Scale with it's parent | ||
52 | CC_HONOR_PARENT_TRANSFORM_SCALE = 1 << 2, | ||
53 | //! Skew with it's parent | ||
54 | CC_HONOR_PARENT_TRANSFORM_SKEW = 1 << 3, | ||
55 | |||
56 | //! All possible transformation enabled. Default value. | ||
57 | CC_HONOR_PARENT_TRANSFORM_ALL = CC_HONOR_PARENT_TRANSFORM_TRANSLATE | CC_HONOR_PARENT_TRANSFORM_ROTATE | CC_HONOR_PARENT_TRANSFORM_SCALE | CC_HONOR_PARENT_TRANSFORM_SKEW, | ||
58 | |||
59 | } ccHonorParentTransform; | ||
60 | |||
61 | /** CCSprite is a 2d image ( http://en.wikipedia.org/wiki/Sprite_(computer_graphics) ) | ||
62 | * | ||
63 | * CCSprite can be created with an image, or with a sub-rectangle of an image. | ||
64 | * | ||
65 | * If the parent or any of its ancestors is a CCSpriteBatchNode then the following features/limitations are valid | ||
66 | * - Features when the parent is a CCBatchNode: | ||
67 | * - MUCH faster rendering, specially if the CCSpriteBatchNode has many children. All the children will be drawn in a single batch. | ||
68 | * | ||
69 | * - Limitations | ||
70 | * - Camera is not supported yet (eg: CCOrbitCamera action doesn't work) | ||
71 | * - GridBase actions are not supported (eg: CCLens, CCRipple, CCTwirl) | ||
72 | * - The Alias/Antialias property belongs to CCSpriteBatchNode, so you can't individually set the aliased property. | ||
73 | * - The Blending function property belongs to CCSpriteBatchNode, so you can't individually set the blending function property. | ||
74 | * - Parallax scroller is not supported, but can be simulated with a "proxy" sprite. | ||
75 | * | ||
76 | * If the parent is an standard CCNode, then CCSprite behaves like any other CCNode: | ||
77 | * - It supports blending functions | ||
78 | * - It supports aliasing / antialiasing | ||
79 | * - But the rendering will be slower: 1 draw per children. | ||
80 | * | ||
81 | * The default anchorPoint in CCSprite is (0.5, 0.5). | ||
82 | */ | ||
83 | @interface CCSprite : CCNode <CCRGBAProtocol, CCTextureProtocol> | ||
84 | { | ||
85 | |||
86 | // | ||
87 | // Data used when the sprite is rendered using a CCSpriteBatchNode | ||
88 | // | ||
89 | CCTextureAtlas *textureAtlas_; // Sprite Sheet texture atlas (weak reference) | ||
90 | NSUInteger atlasIndex_; // Absolute (real) Index on the batch node | ||
91 | CCSpriteBatchNode *batchNode_; // Used batch node (weak reference) | ||
92 | ccHonorParentTransform honorParentTransform_; // whether or not to transform according to its parent transformations | ||
93 | BOOL dirty_; // Sprite needs to be updated | ||
94 | BOOL recursiveDirty_; // Subchildren needs to be updated | ||
95 | BOOL hasChildren_; // optimization to check if it contain children | ||
96 | |||
97 | // | ||
98 | // Data used when the sprite is self-rendered | ||
99 | // | ||
100 | ccBlendFunc blendFunc_; // Needed for the texture protocol | ||
101 | CCTexture2D *texture_; // Texture used to render the sprite | ||
102 | |||
103 | // | ||
104 | // Shared data | ||
105 | // | ||
106 | |||
107 | // whether or not it's parent is a CCSpriteBatchNode | ||
108 | BOOL usesBatchNode_; | ||
109 | |||
110 | // texture | ||
111 | CGRect rect_; | ||
112 | CGRect rectInPixels_; | ||
113 | BOOL rectRotated_; | ||
114 | |||
115 | // Offset Position (used by Zwoptex) | ||
116 | CGPoint offsetPositionInPixels_; | ||
117 | CGPoint unflippedOffsetPositionFromCenter_; | ||
118 | |||
119 | // vertex coords, texture coords and color info | ||
120 | ccV3F_C4B_T2F_Quad quad_; | ||
121 | |||
122 | // opacity and RGB protocol | ||
123 | GLubyte opacity_; | ||
124 | ccColor3B color_; | ||
125 | ccColor3B colorUnmodified_; | ||
126 | BOOL opacityModifyRGB_; | ||
127 | |||
128 | // image is flipped | ||
129 | BOOL flipX_; | ||
130 | BOOL flipY_; | ||
131 | |||
132 | |||
133 | // Animations that belong to the sprite | ||
134 | NSMutableDictionary *animations_; | ||
135 | |||
136 | @public | ||
137 | // used internally. | ||
138 | void (*updateMethod)(id, SEL); | ||
139 | } | ||
140 | |||
141 | /** whether or not the Sprite needs to be updated in the Atlas */ | ||
142 | @property (nonatomic,readwrite) BOOL dirty; | ||
143 | /** the quad (tex coords, vertex coords and color) information */ | ||
144 | @property (nonatomic,readonly) ccV3F_C4B_T2F_Quad quad; | ||
145 | /** The index used on the TextureAtlas. Don't modify this value unless you know what you are doing */ | ||
146 | @property (nonatomic,readwrite) NSUInteger atlasIndex; | ||
147 | /** returns the rect of the CCSprite in points */ | ||
148 | @property (nonatomic,readonly) CGRect textureRect; | ||
149 | /** returns whether or not the texture rectangle is rotated */ | ||
150 | @property (nonatomic,readonly) BOOL textureRectRotated; | ||
151 | /** whether or not the sprite is flipped horizontally. | ||
152 | It only flips the texture of the sprite, and not the texture of the sprite's children. | ||
153 | Also, flipping the texture doesn't alter the anchorPoint. | ||
154 | If you want to flip the anchorPoint too, and/or to flip the children too use: | ||
155 | |||
156 | sprite.scaleX *= -1; | ||
157 | */ | ||
158 | @property (nonatomic,readwrite) BOOL flipX; | ||
159 | /** whether or not the sprite is flipped vertically. | ||
160 | It only flips the texture of the sprite, and not the texture of the sprite's children. | ||
161 | Also, flipping the texture doesn't alter the anchorPoint. | ||
162 | If you want to flip the anchorPoint too, and/or to flip the children too use: | ||
163 | |||
164 | sprite.scaleY *= -1; | ||
165 | */ | ||
166 | @property (nonatomic,readwrite) BOOL flipY; | ||
167 | /** opacity: conforms to CCRGBAProtocol protocol */ | ||
168 | @property (nonatomic,readwrite) GLubyte opacity; | ||
169 | /** RGB colors: conforms to CCRGBAProtocol protocol */ | ||
170 | @property (nonatomic,readwrite) ccColor3B color; | ||
171 | /** whether or not the Sprite is rendered using a CCSpriteBatchNode */ | ||
172 | @property (nonatomic,readwrite) BOOL usesBatchNode; | ||
173 | /** weak reference of the CCTextureAtlas used when the sprite is rendered using a CCSpriteBatchNode */ | ||
174 | @property (nonatomic,readwrite,assign) CCTextureAtlas *textureAtlas; | ||
175 | /** weak reference to the CCSpriteBatchNode that renders the CCSprite */ | ||
176 | @property (nonatomic,readwrite,assign) CCSpriteBatchNode *batchNode; | ||
177 | /** whether or not to transform according to its parent transfomrations. | ||
178 | Useful for health bars. eg: Don't rotate the health bar, even if the parent rotates. | ||
179 | IMPORTANT: Only valid if it is rendered using an CCSpriteBatchNode. | ||
180 | @since v0.99.0 | ||
181 | */ | ||
182 | @property (nonatomic,readwrite) ccHonorParentTransform honorParentTransform; | ||
183 | /** offset position in pixels of the sprite in points. Calculated automatically by editors like Zwoptex. | ||
184 | @since v0.99.0 | ||
185 | */ | ||
186 | @property (nonatomic,readonly) CGPoint offsetPositionInPixels; | ||
187 | /** conforms to CCTextureProtocol protocol */ | ||
188 | @property (nonatomic,readwrite) ccBlendFunc blendFunc; | ||
189 | |||
190 | #pragma mark CCSprite - Initializers | ||
191 | |||
192 | /** Creates an sprite with a texture. | ||
193 | The rect used will be the size of the texture. | ||
194 | The offset will be (0,0). | ||
195 | */ | ||
196 | +(id) spriteWithTexture:(CCTexture2D*)texture; | ||
197 | |||
198 | /** Creates an sprite with a texture and a rect. | ||
199 | The offset will be (0,0). | ||
200 | */ | ||
201 | +(id) spriteWithTexture:(CCTexture2D*)texture rect:(CGRect)rect; | ||
202 | |||
203 | /** Creates an sprite with an sprite frame. | ||
204 | */ | ||
205 | +(id) spriteWithSpriteFrame:(CCSpriteFrame*)spriteFrame; | ||
206 | |||
207 | /** Creates an sprite with an sprite frame name. | ||
208 | An CCSpriteFrame will be fetched from the CCSpriteFrameCache by name. | ||
209 | If the CCSpriteFrame doesn't exist it will raise an exception. | ||
210 | @since v0.9 | ||
211 | */ | ||
212 | +(id) spriteWithSpriteFrameName:(NSString*)spriteFrameName; | ||
213 | |||
214 | /** Creates an sprite with an image filename. | ||
215 | The rect used will be the size of the image. | ||
216 | The offset will be (0,0). | ||
217 | */ | ||
218 | +(id) spriteWithFile:(NSString*)filename; | ||
219 | |||
220 | /** Creates an sprite with an image filename and a rect. | ||
221 | The offset will be (0,0). | ||
222 | */ | ||
223 | +(id) spriteWithFile:(NSString*)filename rect:(CGRect)rect; | ||
224 | |||
225 | /** Creates an sprite with a CGImageRef and a key. | ||
226 | The key is used by the CCTextureCache to know if a texture was already created with this CGImage. | ||
227 | For example, a valid key is: @"sprite_frame_01". | ||
228 | If key is nil, then a new texture will be created each time by the CCTextureCache. | ||
229 | @since v0.99.0 | ||
230 | */ | ||
231 | +(id) spriteWithCGImage: (CGImageRef)image key:(NSString*)key; | ||
232 | |||
233 | |||
234 | /** Creates an sprite with an CCBatchNode and a rect | ||
235 | */ | ||
236 | +(id) spriteWithBatchNode:(CCSpriteBatchNode*)batchNode rect:(CGRect)rect; | ||
237 | |||
238 | |||
239 | /** Initializes an sprite with a texture. | ||
240 | The rect used will be the size of the texture. | ||
241 | The offset will be (0,0). | ||
242 | */ | ||
243 | -(id) initWithTexture:(CCTexture2D*)texture; | ||
244 | |||
245 | /** Initializes an sprite with a texture and a rect in points. | ||
246 | The offset will be (0,0). | ||
247 | */ | ||
248 | -(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect; | ||
249 | |||
250 | /** Initializes an sprite with an sprite frame. | ||
251 | */ | ||
252 | -(id) initWithSpriteFrame:(CCSpriteFrame*)spriteFrame; | ||
253 | |||
254 | /** Initializes an sprite with an sprite frame name. | ||
255 | An CCSpriteFrame will be fetched from the CCSpriteFrameCache by name. | ||
256 | If the CCSpriteFrame doesn't exist it will raise an exception. | ||
257 | @since v0.9 | ||
258 | */ | ||
259 | -(id) initWithSpriteFrameName:(NSString*)spriteFrameName; | ||
260 | |||
261 | /** Initializes an sprite with an image filename. | ||
262 | The rect used will be the size of the image. | ||
263 | The offset will be (0,0). | ||
264 | */ | ||
265 | -(id) initWithFile:(NSString*)filename; | ||
266 | |||
267 | /** Initializes an sprite with an image filename, and a rect. | ||
268 | The offset will be (0,0). | ||
269 | */ | ||
270 | -(id) initWithFile:(NSString*)filename rect:(CGRect)rect; | ||
271 | |||
272 | /** Initializes an sprite with a CGImageRef and a key | ||
273 | The key is used by the CCTextureCache to know if a texture was already created with this CGImage. | ||
274 | For example, a valid key is: @"sprite_frame_01". | ||
275 | If key is nil, then a new texture will be created each time by the CCTextureCache. | ||
276 | @since v0.99.0 | ||
277 | */ | ||
278 | -(id) initWithCGImage:(CGImageRef)image key:(NSString*)key; | ||
279 | |||
280 | /** Initializes an sprite with an CCSpriteBatchNode and a rect in points | ||
281 | */ | ||
282 | -(id) initWithBatchNode:(CCSpriteBatchNode*)batchNode rect:(CGRect)rect; | ||
283 | |||
284 | /** Initializes an sprite with an CCSpriteBatchNode and a rect in pixels | ||
285 | @since v0.99.5 | ||
286 | */ | ||
287 | -(id) initWithBatchNode:(CCSpriteBatchNode*)batchNode rectInPixels:(CGRect)rect; | ||
288 | |||
289 | |||
290 | |||
291 | #pragma mark CCSprite - BatchNode methods | ||
292 | |||
293 | /** updates the quad according the the rotation, position, scale values. | ||
294 | */ | ||
295 | -(void)updateTransform; | ||
296 | |||
297 | /** updates the texture rect of the CCSprite in points. | ||
298 | */ | ||
299 | -(void) setTextureRect:(CGRect) rect; | ||
300 | /** updates the texture rect, rectRotated and untrimmed size of the CCSprite in pixels | ||
301 | */ | ||
302 | -(void) setTextureRectInPixels:(CGRect)rect rotated:(BOOL)rotated untrimmedSize:(CGSize)size; | ||
303 | |||
304 | /** tell the sprite to use self-render. | ||
305 | @since v0.99.0 | ||
306 | */ | ||
307 | -(void) useSelfRender; | ||
308 | |||
309 | /** tell the sprite to use sprite batch node | ||
310 | @since v0.99.0 | ||
311 | */ | ||
312 | -(void) useBatchNode:(CCSpriteBatchNode*)batchNode; | ||
313 | |||
314 | |||
315 | #pragma mark CCSprite - Frames | ||
316 | |||
317 | /** sets a new display frame to the CCSprite. */ | ||
318 | -(void) setDisplayFrame:(CCSpriteFrame*)newFrame; | ||
319 | |||
320 | /** returns whether or not a CCSpriteFrame is being displayed */ | ||
321 | -(BOOL) isFrameDisplayed:(CCSpriteFrame*)frame; | ||
322 | |||
323 | /** returns the current displayed frame. */ | ||
324 | -(CCSpriteFrame*) displayedFrame; | ||
325 | |||
326 | #pragma mark CCSprite - Animation | ||
327 | |||
328 | /** changes the display frame based on an animation and an index. | ||
329 | @deprecated Will be removed in 1.0.1. Use setDisplayFrameWithAnimationName:index instead | ||
330 | */ | ||
331 | -(void) setDisplayFrame: (NSString*) animationName index:(int) frameIndex DEPRECATED_ATTRIBUTE; | ||
332 | |||
333 | /** changes the display frame with animation name and index. | ||
334 | The animation name will be get from the CCAnimationCache | ||
335 | @since v0.99.5 | ||
336 | */ | ||
337 | -(void) setDisplayFrameWithAnimationName:(NSString*)animationName index:(int) frameIndex; | ||
338 | |||
339 | /** returns an Animation given it's name. | ||
340 | |||
341 | @deprecated Use CCAnimationCache instead. Will be removed in 1.0.1 | ||
342 | */ | ||
343 | -(CCAnimation*)animationByName: (NSString*) animationName DEPRECATED_ATTRIBUTE; | ||
344 | |||
345 | /** adds an Animation to the Sprite. | ||
346 | |||
347 | @deprecated Use CCAnimationCache instead. Will be removed in 1.0.1 | ||
348 | */ | ||
349 | -(void) addAnimation: (CCAnimation*) animation DEPRECATED_ATTRIBUTE; | ||
350 | |||
351 | @end | ||
diff --git a/libs/cocos2d/CCSprite.m b/libs/cocos2d/CCSprite.m new file mode 100755 index 0000000..37f06d2 --- /dev/null +++ b/libs/cocos2d/CCSprite.m | |||
@@ -0,0 +1,1029 @@ | |||
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 | #import <Availability.h> | ||
28 | |||
29 | #import "ccConfig.h" | ||
30 | #import "CCSpriteBatchNode.h" | ||
31 | #import "CCSprite.h" | ||
32 | #import "CCSpriteFrame.h" | ||
33 | #import "CCSpriteFrameCache.h" | ||
34 | #import "CCAnimation.h" | ||
35 | #import "CCAnimationCache.h" | ||
36 | #import "CCTextureCache.h" | ||
37 | #import "Support/CGPointExtension.h" | ||
38 | #import "CCDrawingPrimitives.h" | ||
39 | |||
40 | #pragma mark - | ||
41 | #pragma mark CCSprite | ||
42 | |||
43 | #if CC_SPRITEBATCHNODE_RENDER_SUBPIXEL | ||
44 | #define RENDER_IN_SUBPIXEL | ||
45 | #else | ||
46 | #define RENDER_IN_SUBPIXEL(__A__) ( (int)(__A__)) | ||
47 | #endif | ||
48 | |||
49 | // XXX: Optmization | ||
50 | struct transformValues_ { | ||
51 | CGPoint pos; // position x and y | ||
52 | CGPoint scale; // scale x and y | ||
53 | float rotation; | ||
54 | CGPoint skew; // skew x and y | ||
55 | CGPoint ap; // anchor point in pixels | ||
56 | BOOL visible; | ||
57 | }; | ||
58 | |||
59 | @interface CCSprite (Private) | ||
60 | -(void)updateTextureCoords:(CGRect)rect; | ||
61 | -(void)updateBlendFunc; | ||
62 | -(void) initAnimationDictionary; | ||
63 | -(void) getTransformValues:(struct transformValues_*)tv; // optimization | ||
64 | @end | ||
65 | |||
66 | @implementation CCSprite | ||
67 | |||
68 | @synthesize dirty = dirty_; | ||
69 | @synthesize quad = quad_; | ||
70 | @synthesize atlasIndex = atlasIndex_; | ||
71 | @synthesize textureRect = rect_; | ||
72 | @synthesize textureRectRotated = rectRotated_; | ||
73 | @synthesize blendFunc = blendFunc_; | ||
74 | @synthesize usesBatchNode = usesBatchNode_; | ||
75 | @synthesize textureAtlas = textureAtlas_; | ||
76 | @synthesize batchNode = batchNode_; | ||
77 | @synthesize honorParentTransform = honorParentTransform_; | ||
78 | @synthesize offsetPositionInPixels = offsetPositionInPixels_; | ||
79 | |||
80 | |||
81 | +(id)spriteWithTexture:(CCTexture2D*)texture | ||
82 | { | ||
83 | return [[[self alloc] initWithTexture:texture] autorelease]; | ||
84 | } | ||
85 | |||
86 | +(id)spriteWithTexture:(CCTexture2D*)texture rect:(CGRect)rect | ||
87 | { | ||
88 | return [[[self alloc] initWithTexture:texture rect:rect] autorelease]; | ||
89 | } | ||
90 | |||
91 | +(id)spriteWithFile:(NSString*)filename | ||
92 | { | ||
93 | return [[[self alloc] initWithFile:filename] autorelease]; | ||
94 | } | ||
95 | |||
96 | +(id)spriteWithFile:(NSString*)filename rect:(CGRect)rect | ||
97 | { | ||
98 | return [[[self alloc] initWithFile:filename rect:rect] autorelease]; | ||
99 | } | ||
100 | |||
101 | +(id)spriteWithSpriteFrame:(CCSpriteFrame*)spriteFrame | ||
102 | { | ||
103 | return [[[self alloc] initWithSpriteFrame:spriteFrame] autorelease]; | ||
104 | } | ||
105 | |||
106 | +(id)spriteWithSpriteFrameName:(NSString*)spriteFrameName | ||
107 | { | ||
108 | CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:spriteFrameName]; | ||
109 | |||
110 | NSAssert1(frame!=nil, @"Invalid spriteFrameName: %@", spriteFrameName); | ||
111 | return [self spriteWithSpriteFrame:frame]; | ||
112 | } | ||
113 | |||
114 | +(id)spriteWithCGImage:(CGImageRef)image key:(NSString*)key | ||
115 | { | ||
116 | return [[[self alloc] initWithCGImage:image key:key] autorelease]; | ||
117 | } | ||
118 | |||
119 | +(id) spriteWithBatchNode:(CCSpriteBatchNode*)batchNode rect:(CGRect)rect | ||
120 | { | ||
121 | return [[[self alloc] initWithBatchNode:batchNode rect:rect] autorelease]; | ||
122 | } | ||
123 | |||
124 | -(id) init | ||
125 | { | ||
126 | if( (self=[super init]) ) { | ||
127 | dirty_ = recursiveDirty_ = NO; | ||
128 | |||
129 | // by default use "Self Render". | ||
130 | // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" | ||
131 | [self useSelfRender]; | ||
132 | |||
133 | opacityModifyRGB_ = YES; | ||
134 | opacity_ = 255; | ||
135 | color_ = colorUnmodified_ = ccWHITE; | ||
136 | |||
137 | blendFunc_.src = CC_BLEND_SRC; | ||
138 | blendFunc_.dst = CC_BLEND_DST; | ||
139 | |||
140 | // update texture (calls updateBlendFunc) | ||
141 | [self setTexture:nil]; | ||
142 | |||
143 | // clean the Quad | ||
144 | bzero(&quad_, sizeof(quad_)); | ||
145 | |||
146 | flipY_ = flipX_ = NO; | ||
147 | |||
148 | // lazy alloc | ||
149 | animations_ = nil; | ||
150 | |||
151 | // default transform anchor: center | ||
152 | anchorPoint_ = ccp(0.5f, 0.5f); | ||
153 | |||
154 | // zwoptex default values | ||
155 | offsetPositionInPixels_ = CGPointZero; | ||
156 | |||
157 | honorParentTransform_ = CC_HONOR_PARENT_TRANSFORM_ALL; | ||
158 | hasChildren_ = NO; | ||
159 | |||
160 | // Atlas: Color | ||
161 | ccColor4B tmpColor = {255,255,255,255}; | ||
162 | quad_.bl.colors = tmpColor; | ||
163 | quad_.br.colors = tmpColor; | ||
164 | quad_.tl.colors = tmpColor; | ||
165 | quad_.tr.colors = tmpColor; | ||
166 | |||
167 | // Atlas: Vertex | ||
168 | |||
169 | // updated in "useSelfRender" | ||
170 | |||
171 | // Atlas: TexCoords | ||
172 | [self setTextureRectInPixels:CGRectZero rotated:NO untrimmedSize:CGSizeZero]; | ||
173 | |||
174 | // updateMethod selector | ||
175 | updateMethod = (__typeof__(updateMethod))[self methodForSelector:@selector(updateTransform)]; | ||
176 | } | ||
177 | |||
178 | return self; | ||
179 | } | ||
180 | |||
181 | -(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect | ||
182 | { | ||
183 | NSAssert(texture!=nil, @"Invalid texture for sprite"); | ||
184 | // IMPORTANT: [self init] and not [super init]; | ||
185 | if( (self = [self init]) ) | ||
186 | { | ||
187 | [self setTexture:texture]; | ||
188 | [self setTextureRect:rect]; | ||
189 | } | ||
190 | return self; | ||
191 | } | ||
192 | |||
193 | -(id) initWithTexture:(CCTexture2D*)texture | ||
194 | { | ||
195 | NSAssert(texture!=nil, @"Invalid texture for sprite"); | ||
196 | |||
197 | CGRect rect = CGRectZero; | ||
198 | rect.size = texture.contentSize; | ||
199 | return [self initWithTexture:texture rect:rect]; | ||
200 | } | ||
201 | |||
202 | -(id) initWithFile:(NSString*)filename | ||
203 | { | ||
204 | NSAssert(filename!=nil, @"Invalid filename for sprite"); | ||
205 | |||
206 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage: filename]; | ||
207 | if( texture ) { | ||
208 | CGRect rect = CGRectZero; | ||
209 | rect.size = texture.contentSize; | ||
210 | return [self initWithTexture:texture rect:rect]; | ||
211 | } | ||
212 | |||
213 | [self release]; | ||
214 | return nil; | ||
215 | } | ||
216 | |||
217 | -(id) initWithFile:(NSString*)filename rect:(CGRect)rect | ||
218 | { | ||
219 | NSAssert(filename!=nil, @"Invalid filename for sprite"); | ||
220 | |||
221 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage: filename]; | ||
222 | if( texture ) | ||
223 | return [self initWithTexture:texture rect:rect]; | ||
224 | |||
225 | [self release]; | ||
226 | return nil; | ||
227 | } | ||
228 | |||
229 | - (id) initWithSpriteFrame:(CCSpriteFrame*)spriteFrame | ||
230 | { | ||
231 | NSAssert(spriteFrame!=nil, @"Invalid spriteFrame for sprite"); | ||
232 | |||
233 | id ret = [self initWithTexture:spriteFrame.texture rect:spriteFrame.rect]; | ||
234 | [self setDisplayFrame:spriteFrame]; | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | -(id)initWithSpriteFrameName:(NSString*)spriteFrameName | ||
239 | { | ||
240 | NSAssert(spriteFrameName!=nil, @"Invalid spriteFrameName for sprite"); | ||
241 | |||
242 | CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:spriteFrameName]; | ||
243 | return [self initWithSpriteFrame:frame]; | ||
244 | } | ||
245 | |||
246 | // XXX: deprecated | ||
247 | - (id) initWithCGImage: (CGImageRef)image | ||
248 | { | ||
249 | NSAssert(image!=nil, @"Invalid CGImageRef for sprite"); | ||
250 | |||
251 | // XXX: possible bug. See issue #349. New API should be added | ||
252 | NSString *key = [NSString stringWithFormat:@"%08X",(unsigned long)image]; | ||
253 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addCGImage:image forKey:key]; | ||
254 | |||
255 | CGRect rect = CGRectZero; | ||
256 | rect.size = texture.contentSize; | ||
257 | |||
258 | return [self initWithTexture:texture rect:rect]; | ||
259 | } | ||
260 | |||
261 | - (id) initWithCGImage:(CGImageRef)image key:(NSString*)key | ||
262 | { | ||
263 | NSAssert(image!=nil, @"Invalid CGImageRef for sprite"); | ||
264 | |||
265 | // XXX: possible bug. See issue #349. New API should be added | ||
266 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addCGImage:image forKey:key]; | ||
267 | |||
268 | CGRect rect = CGRectZero; | ||
269 | rect.size = texture.contentSize; | ||
270 | |||
271 | return [self initWithTexture:texture rect:rect]; | ||
272 | } | ||
273 | |||
274 | -(id) initWithBatchNode:(CCSpriteBatchNode*)batchNode rect:(CGRect)rect | ||
275 | { | ||
276 | id ret = [self initWithTexture:batchNode.texture rect:rect]; | ||
277 | [self useBatchNode:batchNode]; | ||
278 | |||
279 | return ret; | ||
280 | } | ||
281 | |||
282 | -(id) initWithBatchNode:(CCSpriteBatchNode*)batchNode rectInPixels:(CGRect)rect | ||
283 | { | ||
284 | id ret = [self initWithTexture:batchNode.texture]; | ||
285 | [self setTextureRectInPixels:rect rotated:NO untrimmedSize:rect.size]; | ||
286 | [self useBatchNode:batchNode]; | ||
287 | |||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | - (NSString*) description | ||
292 | { | ||
293 | return [NSString stringWithFormat:@"<%@ = %08X | Rect = (%.2f,%.2f,%.2f,%.2f) | tag = %i | atlasIndex = %i>", [self class], self, | ||
294 | rect_.origin.x, rect_.origin.y, rect_.size.width, rect_.size.height, | ||
295 | tag_, | ||
296 | atlasIndex_ | ||
297 | ]; | ||
298 | } | ||
299 | |||
300 | - (void) dealloc | ||
301 | { | ||
302 | [texture_ release]; | ||
303 | [animations_ release]; | ||
304 | [super dealloc]; | ||
305 | } | ||
306 | |||
307 | -(void) useSelfRender | ||
308 | { | ||
309 | atlasIndex_ = CCSpriteIndexNotInitialized; | ||
310 | usesBatchNode_ = NO; | ||
311 | textureAtlas_ = nil; | ||
312 | batchNode_ = nil; | ||
313 | dirty_ = recursiveDirty_ = NO; | ||
314 | |||
315 | float x1 = 0 + offsetPositionInPixels_.x; | ||
316 | float y1 = 0 + offsetPositionInPixels_.y; | ||
317 | float x2 = x1 + rectInPixels_.size.width; | ||
318 | float y2 = y1 + rectInPixels_.size.height; | ||
319 | quad_.bl.vertices = (ccVertex3F) { x1, y1, 0 }; | ||
320 | quad_.br.vertices = (ccVertex3F) { x2, y1, 0 }; | ||
321 | quad_.tl.vertices = (ccVertex3F) { x1, y2, 0 }; | ||
322 | quad_.tr.vertices = (ccVertex3F) { x2, y2, 0 }; | ||
323 | } | ||
324 | |||
325 | -(void) useBatchNode:(CCSpriteBatchNode*)batchNode | ||
326 | { | ||
327 | usesBatchNode_ = YES; | ||
328 | textureAtlas_ = [batchNode textureAtlas]; // weak ref | ||
329 | batchNode_ = batchNode; // weak ref | ||
330 | } | ||
331 | |||
332 | -(void) initAnimationDictionary | ||
333 | { | ||
334 | animations_ = [[NSMutableDictionary alloc] initWithCapacity:2]; | ||
335 | } | ||
336 | |||
337 | -(void)setTextureRect:(CGRect)rect | ||
338 | { | ||
339 | CGRect rectInPixels = CC_RECT_POINTS_TO_PIXELS( rect ); | ||
340 | [self setTextureRectInPixels:rectInPixels rotated:NO untrimmedSize:rectInPixels.size]; | ||
341 | } | ||
342 | |||
343 | -(void)setTextureRectInPixels:(CGRect)rect rotated:(BOOL)rotated untrimmedSize:(CGSize)untrimmedSize | ||
344 | { | ||
345 | rectInPixels_ = rect; | ||
346 | rect_ = CC_RECT_PIXELS_TO_POINTS( rect ); | ||
347 | rectRotated_ = rotated; | ||
348 | |||
349 | [self setContentSizeInPixels:untrimmedSize]; | ||
350 | [self updateTextureCoords:rectInPixels_]; | ||
351 | |||
352 | CGPoint relativeOffsetInPixels = unflippedOffsetPositionFromCenter_; | ||
353 | |||
354 | // issue #732 | ||
355 | if( flipX_ ) | ||
356 | relativeOffsetInPixels.x = -relativeOffsetInPixels.x; | ||
357 | if( flipY_ ) | ||
358 | relativeOffsetInPixels.y = -relativeOffsetInPixels.y; | ||
359 | |||
360 | offsetPositionInPixels_.x = relativeOffsetInPixels.x + (contentSizeInPixels_.width - rectInPixels_.size.width) / 2; | ||
361 | offsetPositionInPixels_.y = relativeOffsetInPixels.y + (contentSizeInPixels_.height - rectInPixels_.size.height) / 2; | ||
362 | |||
363 | |||
364 | // rendering using batch node | ||
365 | if( usesBatchNode_ ) { | ||
366 | // update dirty_, don't update recursiveDirty_ | ||
367 | dirty_ = YES; | ||
368 | } | ||
369 | |||
370 | // self rendering | ||
371 | else | ||
372 | { | ||
373 | // Atlas: Vertex | ||
374 | float x1 = 0 + offsetPositionInPixels_.x; | ||
375 | float y1 = 0 + offsetPositionInPixels_.y; | ||
376 | float x2 = x1 + rectInPixels_.size.width; | ||
377 | float y2 = y1 + rectInPixels_.size.height; | ||
378 | |||
379 | // Don't update Z. | ||
380 | quad_.bl.vertices = (ccVertex3F) { x1, y1, 0 }; | ||
381 | quad_.br.vertices = (ccVertex3F) { x2, y1, 0 }; | ||
382 | quad_.tl.vertices = (ccVertex3F) { x1, y2, 0 }; | ||
383 | quad_.tr.vertices = (ccVertex3F) { x2, y2, 0 }; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | -(void)updateTextureCoords:(CGRect)rect | ||
388 | { | ||
389 | CCTexture2D *tex = (usesBatchNode_)?[textureAtlas_ texture]:texture_; | ||
390 | if(!tex) | ||
391 | return; | ||
392 | |||
393 | float atlasWidth = (float)tex.pixelsWide; | ||
394 | float atlasHeight = (float)tex.pixelsHigh; | ||
395 | |||
396 | float left,right,top,bottom; | ||
397 | |||
398 | if(rectRotated_){ | ||
399 | #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
400 | left = (2*rect.origin.x+1)/(2*atlasWidth); | ||
401 | right = left+(rect.size.height*2-2)/(2*atlasWidth); | ||
402 | top = (2*rect.origin.y+1)/(2*atlasHeight); | ||
403 | bottom = top+(rect.size.width*2-2)/(2*atlasHeight); | ||
404 | #else | ||
405 | left = rect.origin.x/atlasWidth; | ||
406 | right = left+(rect.size.height/atlasWidth); | ||
407 | top = rect.origin.y/atlasHeight; | ||
408 | bottom = top+(rect.size.width/atlasHeight); | ||
409 | #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
410 | |||
411 | if( flipX_) | ||
412 | CC_SWAP(top,bottom); | ||
413 | if( flipY_) | ||
414 | CC_SWAP(left,right); | ||
415 | |||
416 | quad_.bl.texCoords.u = left; | ||
417 | quad_.bl.texCoords.v = top; | ||
418 | quad_.br.texCoords.u = left; | ||
419 | quad_.br.texCoords.v = bottom; | ||
420 | quad_.tl.texCoords.u = right; | ||
421 | quad_.tl.texCoords.v = top; | ||
422 | quad_.tr.texCoords.u = right; | ||
423 | quad_.tr.texCoords.v = bottom; | ||
424 | } else { | ||
425 | #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
426 | left = (2*rect.origin.x+1)/(2*atlasWidth); | ||
427 | right = left + (rect.size.width*2-2)/(2*atlasWidth); | ||
428 | top = (2*rect.origin.y+1)/(2*atlasHeight); | ||
429 | bottom = top + (rect.size.height*2-2)/(2*atlasHeight); | ||
430 | #else | ||
431 | left = rect.origin.x/atlasWidth; | ||
432 | right = left + rect.size.width/atlasWidth; | ||
433 | top = rect.origin.y/atlasHeight; | ||
434 | bottom = top + rect.size.height/atlasHeight; | ||
435 | #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
436 | |||
437 | if( flipX_) | ||
438 | CC_SWAP(left,right); | ||
439 | if( flipY_) | ||
440 | CC_SWAP(top,bottom); | ||
441 | |||
442 | quad_.bl.texCoords.u = left; | ||
443 | quad_.bl.texCoords.v = bottom; | ||
444 | quad_.br.texCoords.u = right; | ||
445 | quad_.br.texCoords.v = bottom; | ||
446 | quad_.tl.texCoords.u = left; | ||
447 | quad_.tl.texCoords.v = top; | ||
448 | quad_.tr.texCoords.u = right; | ||
449 | quad_.tr.texCoords.v = top; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | -(void)updateTransform | ||
454 | { | ||
455 | NSAssert( usesBatchNode_, @"updateTransform is only valid when CCSprite is being renderd using an CCSpriteBatchNode"); | ||
456 | |||
457 | // optimization. Quick return if not dirty | ||
458 | if( ! dirty_ ) | ||
459 | return; | ||
460 | |||
461 | CGAffineTransform matrix; | ||
462 | |||
463 | // Optimization: if it is not visible, then do nothing | ||
464 | if( ! visible_ ) { | ||
465 | quad_.br.vertices = quad_.tl.vertices = quad_.tr.vertices = quad_.bl.vertices = (ccVertex3F){0,0,0}; | ||
466 | [textureAtlas_ updateQuad:&quad_ atIndex:atlasIndex_]; | ||
467 | dirty_ = recursiveDirty_ = NO; | ||
468 | return ; | ||
469 | } | ||
470 | |||
471 | |||
472 | // Optimization: If parent is batchnode, or parent is nil | ||
473 | // build Affine transform manually | ||
474 | if( ! parent_ || parent_ == batchNode_ ) { | ||
475 | |||
476 | float radians = -CC_DEGREES_TO_RADIANS(rotation_); | ||
477 | float c = cosf(radians); | ||
478 | float s = sinf(radians); | ||
479 | |||
480 | matrix = CGAffineTransformMake( c * scaleX_, s * scaleX_, | ||
481 | -s * scaleY_, c * scaleY_, | ||
482 | positionInPixels_.x, positionInPixels_.y); | ||
483 | if( skewX_ || skewY_ ) { | ||
484 | CGAffineTransform skewMatrix = CGAffineTransformMake(1.0f, tanf(CC_DEGREES_TO_RADIANS(skewY_)), | ||
485 | tanf(CC_DEGREES_TO_RADIANS(skewX_)), 1.0f, | ||
486 | 0.0f, 0.0f); | ||
487 | matrix = CGAffineTransformConcat(skewMatrix, matrix); | ||
488 | } | ||
489 | matrix = CGAffineTransformTranslate(matrix, -anchorPointInPixels_.x, -anchorPointInPixels_.y); | ||
490 | |||
491 | |||
492 | } else { // parent_ != batchNode_ | ||
493 | |||
494 | // else do affine transformation according to the HonorParentTransform | ||
495 | |||
496 | matrix = CGAffineTransformIdentity; | ||
497 | ccHonorParentTransform prevHonor = CC_HONOR_PARENT_TRANSFORM_ALL; | ||
498 | |||
499 | for (CCNode *p = self ; p && p != batchNode_ ; p = p.parent) { | ||
500 | |||
501 | // Might happen. Issue #1053 | ||
502 | NSAssert( [p isKindOfClass:[CCSprite class]], @"CCSprite should be a CCSprite subclass. Probably you initialized an sprite with a batchnode, but you didn't add it to the batch node." ); | ||
503 | |||
504 | struct transformValues_ tv; | ||
505 | [(CCSprite*)p getTransformValues: &tv]; | ||
506 | |||
507 | // If any of the parents are not visible, then don't draw this node | ||
508 | if( ! tv.visible ) { | ||
509 | quad_.br.vertices = quad_.tl.vertices = quad_.tr.vertices = quad_.bl.vertices = (ccVertex3F){0,0,0}; | ||
510 | [textureAtlas_ updateQuad:&quad_ atIndex:atlasIndex_]; | ||
511 | dirty_ = recursiveDirty_ = NO; | ||
512 | return; | ||
513 | } | ||
514 | CGAffineTransform newMatrix = CGAffineTransformIdentity; | ||
515 | |||
516 | // 2nd: Translate, Skew, Rotate, Scale | ||
517 | if( prevHonor & CC_HONOR_PARENT_TRANSFORM_TRANSLATE ) | ||
518 | newMatrix = CGAffineTransformTranslate(newMatrix, tv.pos.x, tv.pos.y); | ||
519 | if( prevHonor & CC_HONOR_PARENT_TRANSFORM_ROTATE ) | ||
520 | newMatrix = CGAffineTransformRotate(newMatrix, -CC_DEGREES_TO_RADIANS(tv.rotation)); | ||
521 | if ( prevHonor & CC_HONOR_PARENT_TRANSFORM_SKEW ) { | ||
522 | CGAffineTransform skew = CGAffineTransformMake(1.0f, tanf(CC_DEGREES_TO_RADIANS(tv.skew.y)), tanf(CC_DEGREES_TO_RADIANS(tv.skew.x)), 1.0f, 0.0f, 0.0f); | ||
523 | // apply the skew to the transform | ||
524 | newMatrix = CGAffineTransformConcat(skew, newMatrix); | ||
525 | } | ||
526 | if( prevHonor & CC_HONOR_PARENT_TRANSFORM_SCALE ) { | ||
527 | newMatrix = CGAffineTransformScale(newMatrix, tv.scale.x, tv.scale.y); | ||
528 | } | ||
529 | |||
530 | // 3rd: Translate anchor point | ||
531 | newMatrix = CGAffineTransformTranslate(newMatrix, -tv.ap.x, -tv.ap.y); | ||
532 | |||
533 | // 4th: Matrix multiplication | ||
534 | matrix = CGAffineTransformConcat( matrix, newMatrix); | ||
535 | |||
536 | prevHonor = [(CCSprite*)p honorParentTransform]; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | |||
541 | // | ||
542 | // calculate the Quad based on the Affine Matrix | ||
543 | // | ||
544 | |||
545 | CGSize size = rectInPixels_.size; | ||
546 | |||
547 | float x1 = offsetPositionInPixels_.x; | ||
548 | float y1 = offsetPositionInPixels_.y; | ||
549 | |||
550 | float x2 = x1 + size.width; | ||
551 | float y2 = y1 + size.height; | ||
552 | float x = matrix.tx; | ||
553 | float y = matrix.ty; | ||
554 | |||
555 | float cr = matrix.a; | ||
556 | float sr = matrix.b; | ||
557 | float cr2 = matrix.d; | ||
558 | float sr2 = -matrix.c; | ||
559 | float ax = x1 * cr - y1 * sr2 + x; | ||
560 | float ay = x1 * sr + y1 * cr2 + y; | ||
561 | |||
562 | float bx = x2 * cr - y1 * sr2 + x; | ||
563 | float by = x2 * sr + y1 * cr2 + y; | ||
564 | |||
565 | float cx = x2 * cr - y2 * sr2 + x; | ||
566 | float cy = x2 * sr + y2 * cr2 + y; | ||
567 | |||
568 | float dx = x1 * cr - y2 * sr2 + x; | ||
569 | float dy = x1 * sr + y2 * cr2 + y; | ||
570 | |||
571 | quad_.bl.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(ax), RENDER_IN_SUBPIXEL(ay), vertexZ_ }; | ||
572 | quad_.br.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(bx), RENDER_IN_SUBPIXEL(by), vertexZ_ }; | ||
573 | quad_.tl.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(dx), RENDER_IN_SUBPIXEL(dy), vertexZ_ }; | ||
574 | quad_.tr.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(cx), RENDER_IN_SUBPIXEL(cy), vertexZ_ }; | ||
575 | |||
576 | [textureAtlas_ updateQuad:&quad_ atIndex:atlasIndex_]; | ||
577 | dirty_ = recursiveDirty_ = NO; | ||
578 | } | ||
579 | |||
580 | // XXX: Optimization: instead of calling 5 times the parent sprite to obtain: position, scale.x, scale.y, anchorpoint and rotation, | ||
581 | // this fuction return the 5 values in 1 single call | ||
582 | -(void) getTransformValues:(struct transformValues_*) tv | ||
583 | { | ||
584 | tv->pos = positionInPixels_; | ||
585 | tv->scale.x = scaleX_; | ||
586 | tv->scale.y = scaleY_; | ||
587 | tv->rotation = rotation_; | ||
588 | tv->skew.x = skewX_; | ||
589 | tv->skew.y = skewY_; | ||
590 | tv->ap = anchorPointInPixels_; | ||
591 | tv->visible = visible_; | ||
592 | } | ||
593 | |||
594 | #pragma mark CCSprite - draw | ||
595 | |||
596 | -(void) draw | ||
597 | { | ||
598 | [super draw]; | ||
599 | |||
600 | NSAssert(!usesBatchNode_, @"If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); | ||
601 | |||
602 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
603 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
604 | // Unneeded states: - | ||
605 | |||
606 | BOOL newBlend = blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST; | ||
607 | if( newBlend ) | ||
608 | glBlendFunc( blendFunc_.src, blendFunc_.dst ); | ||
609 | |||
610 | #define kQuadSize sizeof(quad_.bl) | ||
611 | glBindTexture(GL_TEXTURE_2D, [texture_ name]); | ||
612 | |||
613 | long offset = (long)&quad_; | ||
614 | |||
615 | // vertex | ||
616 | NSInteger diff = offsetof( ccV3F_C4B_T2F, vertices); | ||
617 | glVertexPointer(3, GL_FLOAT, kQuadSize, (void*) (offset + diff) ); | ||
618 | |||
619 | // color | ||
620 | diff = offsetof( ccV3F_C4B_T2F, colors); | ||
621 | glColorPointer(4, GL_UNSIGNED_BYTE, kQuadSize, (void*)(offset + diff)); | ||
622 | |||
623 | // tex coords | ||
624 | diff = offsetof( ccV3F_C4B_T2F, texCoords); | ||
625 | glTexCoordPointer(2, GL_FLOAT, kQuadSize, (void*)(offset + diff)); | ||
626 | |||
627 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
628 | |||
629 | if( newBlend ) | ||
630 | glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); | ||
631 | |||
632 | #if CC_SPRITE_DEBUG_DRAW == 1 | ||
633 | // draw bounding box | ||
634 | CGSize s = self.contentSize; | ||
635 | CGPoint vertices[4] = { | ||
636 | ccp(0,0), ccp(s.width,0), | ||
637 | ccp(s.width,s.height), ccp(0,s.height) | ||
638 | }; | ||
639 | ccDrawPoly(vertices, 4, YES); | ||
640 | #elif CC_SPRITE_DEBUG_DRAW == 2 | ||
641 | // draw texture box | ||
642 | CGSize s = self.textureRect.size; | ||
643 | CGPoint offsetPix = self.offsetPositionInPixels; | ||
644 | CGPoint vertices[4] = { | ||
645 | ccp(offsetPix.x,offsetPix.y), ccp(offsetPix.x+s.width,offsetPix.y), | ||
646 | ccp(offsetPix.x+s.width,offsetPix.y+s.height), ccp(offsetPix.x,offsetPix.y+s.height) | ||
647 | }; | ||
648 | ccDrawPoly(vertices, 4, YES); | ||
649 | #endif // CC_SPRITE_DEBUG_DRAW | ||
650 | |||
651 | } | ||
652 | |||
653 | #pragma mark CCSprite - CCNode overrides | ||
654 | |||
655 | -(void) addChild:(CCSprite*)child z:(NSInteger)z tag:(NSInteger) aTag | ||
656 | { | ||
657 | NSAssert( child != nil, @"Argument must be non-nil"); | ||
658 | |||
659 | [super addChild:child z:z tag:aTag]; | ||
660 | |||
661 | if( usesBatchNode_ ) { | ||
662 | NSAssert( [child isKindOfClass:[CCSprite class]], @"CCSprite only supports CCSprites as children when using CCSpriteBatchNode"); | ||
663 | NSAssert( child.texture.name == textureAtlas_.texture.name, @"CCSprite is not using the same texture id"); | ||
664 | |||
665 | NSUInteger index = [batchNode_ atlasIndexForChild:child atZ:z]; | ||
666 | [batchNode_ insertChild:child inAtlasAtIndex:index]; | ||
667 | } | ||
668 | |||
669 | hasChildren_ = YES; | ||
670 | } | ||
671 | |||
672 | -(void) reorderChild:(CCSprite*)child z:(NSInteger)z | ||
673 | { | ||
674 | NSAssert( child != nil, @"Child must be non-nil"); | ||
675 | NSAssert( [children_ containsObject:child], @"Child doesn't belong to Sprite" ); | ||
676 | |||
677 | if( z == child.zOrder ) | ||
678 | return; | ||
679 | |||
680 | if( usesBatchNode_ ) { | ||
681 | // XXX: Instead of removing/adding, it is more efficient to reorder manually | ||
682 | [child retain]; | ||
683 | [self removeChild:child cleanup:NO]; | ||
684 | [self addChild:child z:z]; | ||
685 | [child release]; | ||
686 | } | ||
687 | |||
688 | else | ||
689 | [super reorderChild:child z:z]; | ||
690 | } | ||
691 | |||
692 | -(void)removeChild: (CCSprite *)sprite cleanup:(BOOL)doCleanup | ||
693 | { | ||
694 | if( usesBatchNode_ ) | ||
695 | [batchNode_ removeSpriteFromAtlas:sprite]; | ||
696 | |||
697 | [super removeChild:sprite cleanup:doCleanup]; | ||
698 | |||
699 | hasChildren_ = ( [children_ count] > 0 ); | ||
700 | } | ||
701 | |||
702 | -(void)removeAllChildrenWithCleanup:(BOOL)doCleanup | ||
703 | { | ||
704 | if( usesBatchNode_ ) { | ||
705 | CCSprite *child; | ||
706 | CCARRAY_FOREACH(children_, child) | ||
707 | [batchNode_ removeSpriteFromAtlas:child]; | ||
708 | } | ||
709 | |||
710 | [super removeAllChildrenWithCleanup:doCleanup]; | ||
711 | |||
712 | hasChildren_ = NO; | ||
713 | } | ||
714 | |||
715 | // | ||
716 | // CCNode property overloads | ||
717 | // used only when parent is CCSpriteBatchNode | ||
718 | // | ||
719 | #pragma mark CCSprite - property overloads | ||
720 | |||
721 | |||
722 | -(void) setDirtyRecursively:(BOOL)b | ||
723 | { | ||
724 | dirty_ = recursiveDirty_ = b; | ||
725 | // recursively set dirty | ||
726 | if( hasChildren_ ) { | ||
727 | CCSprite *child; | ||
728 | CCARRAY_FOREACH(children_, child) | ||
729 | [child setDirtyRecursively:YES]; | ||
730 | } | ||
731 | } | ||
732 | |||
733 | // XXX HACK: optimization | ||
734 | #define SET_DIRTY_RECURSIVELY() { \ | ||
735 | if( usesBatchNode_ && ! recursiveDirty_ ) { \ | ||
736 | dirty_ = recursiveDirty_ = YES; \ | ||
737 | if( hasChildren_) \ | ||
738 | [self setDirtyRecursively:YES]; \ | ||
739 | } \ | ||
740 | } | ||
741 | |||
742 | -(void)setPosition:(CGPoint)pos | ||
743 | { | ||
744 | [super setPosition:pos]; | ||
745 | SET_DIRTY_RECURSIVELY(); | ||
746 | } | ||
747 | |||
748 | -(void)setPositionInPixels:(CGPoint)pos | ||
749 | { | ||
750 | [super setPositionInPixels:pos]; | ||
751 | SET_DIRTY_RECURSIVELY(); | ||
752 | } | ||
753 | |||
754 | -(void)setRotation:(float)rot | ||
755 | { | ||
756 | [super setRotation:rot]; | ||
757 | SET_DIRTY_RECURSIVELY(); | ||
758 | } | ||
759 | |||
760 | -(void)setSkewX:(float)sx | ||
761 | { | ||
762 | [super setSkewX:sx]; | ||
763 | SET_DIRTY_RECURSIVELY(); | ||
764 | } | ||
765 | |||
766 | -(void)setSkewY:(float)sy | ||
767 | { | ||
768 | [super setSkewY:sy]; | ||
769 | SET_DIRTY_RECURSIVELY(); | ||
770 | } | ||
771 | |||
772 | -(void)setScaleX:(float) sx | ||
773 | { | ||
774 | [super setScaleX:sx]; | ||
775 | SET_DIRTY_RECURSIVELY(); | ||
776 | } | ||
777 | |||
778 | -(void)setScaleY:(float) sy | ||
779 | { | ||
780 | [super setScaleY:sy]; | ||
781 | SET_DIRTY_RECURSIVELY(); | ||
782 | } | ||
783 | |||
784 | -(void)setScale:(float) s | ||
785 | { | ||
786 | [super setScale:s]; | ||
787 | SET_DIRTY_RECURSIVELY(); | ||
788 | } | ||
789 | |||
790 | -(void) setVertexZ:(float)z | ||
791 | { | ||
792 | [super setVertexZ:z]; | ||
793 | SET_DIRTY_RECURSIVELY(); | ||
794 | } | ||
795 | |||
796 | -(void)setAnchorPoint:(CGPoint)anchor | ||
797 | { | ||
798 | [super setAnchorPoint:anchor]; | ||
799 | SET_DIRTY_RECURSIVELY(); | ||
800 | } | ||
801 | |||
802 | -(void)setIsRelativeAnchorPoint:(BOOL)relative | ||
803 | { | ||
804 | NSAssert( ! usesBatchNode_, @"relativeTransformAnchor is invalid in CCSprite"); | ||
805 | [super setIsRelativeAnchorPoint:relative]; | ||
806 | } | ||
807 | |||
808 | -(void)setVisible:(BOOL)v | ||
809 | { | ||
810 | [super setVisible:v]; | ||
811 | SET_DIRTY_RECURSIVELY(); | ||
812 | } | ||
813 | |||
814 | -(void)setFlipX:(BOOL)b | ||
815 | { | ||
816 | if( flipX_ != b ) { | ||
817 | flipX_ = b; | ||
818 | [self setTextureRectInPixels:rectInPixels_ rotated:rectRotated_ untrimmedSize:contentSizeInPixels_]; | ||
819 | } | ||
820 | } | ||
821 | -(BOOL) flipX | ||
822 | { | ||
823 | return flipX_; | ||
824 | } | ||
825 | |||
826 | -(void) setFlipY:(BOOL)b | ||
827 | { | ||
828 | if( flipY_ != b ) { | ||
829 | flipY_ = b; | ||
830 | [self setTextureRectInPixels:rectInPixels_ rotated:rectRotated_ untrimmedSize:contentSizeInPixels_]; | ||
831 | } | ||
832 | } | ||
833 | -(BOOL) flipY | ||
834 | { | ||
835 | return flipY_; | ||
836 | } | ||
837 | |||
838 | // | ||
839 | // RGBA protocol | ||
840 | // | ||
841 | #pragma mark CCSprite - RGBA protocol | ||
842 | -(void) updateColor | ||
843 | { | ||
844 | ccColor4B color4 = {color_.r, color_.g, color_.b, opacity_ }; | ||
845 | |||
846 | quad_.bl.colors = color4; | ||
847 | quad_.br.colors = color4; | ||
848 | quad_.tl.colors = color4; | ||
849 | quad_.tr.colors = color4; | ||
850 | |||
851 | // renders using Sprite Manager | ||
852 | if( usesBatchNode_ ) { | ||
853 | if( atlasIndex_ != CCSpriteIndexNotInitialized) | ||
854 | [textureAtlas_ updateQuad:&quad_ atIndex:atlasIndex_]; | ||
855 | else | ||
856 | // no need to set it recursively | ||
857 | // update dirty_, don't update recursiveDirty_ | ||
858 | dirty_ = YES; | ||
859 | } | ||
860 | // self render | ||
861 | // do nothing | ||
862 | } | ||
863 | |||
864 | -(GLubyte) opacity | ||
865 | { | ||
866 | return opacity_; | ||
867 | } | ||
868 | |||
869 | -(void) setOpacity:(GLubyte) anOpacity | ||
870 | { | ||
871 | opacity_ = anOpacity; | ||
872 | |||
873 | // special opacity for premultiplied textures | ||
874 | if( opacityModifyRGB_ ) | ||
875 | [self setColor: colorUnmodified_]; | ||
876 | |||
877 | [self updateColor]; | ||
878 | } | ||
879 | |||
880 | - (ccColor3B) color | ||
881 | { | ||
882 | if(opacityModifyRGB_) | ||
883 | return colorUnmodified_; | ||
884 | |||
885 | return color_; | ||
886 | } | ||
887 | |||
888 | -(void) setColor:(ccColor3B)color3 | ||
889 | { | ||
890 | color_ = colorUnmodified_ = color3; | ||
891 | |||
892 | if( opacityModifyRGB_ ){ | ||
893 | color_.r = color3.r * opacity_/255; | ||
894 | color_.g = color3.g * opacity_/255; | ||
895 | color_.b = color3.b * opacity_/255; | ||
896 | } | ||
897 | |||
898 | [self updateColor]; | ||
899 | } | ||
900 | |||
901 | -(void) setOpacityModifyRGB:(BOOL)modify | ||
902 | { | ||
903 | ccColor3B oldColor = self.color; | ||
904 | opacityModifyRGB_ = modify; | ||
905 | self.color = oldColor; | ||
906 | } | ||
907 | |||
908 | -(BOOL) doesOpacityModifyRGB | ||
909 | { | ||
910 | return opacityModifyRGB_; | ||
911 | } | ||
912 | |||
913 | // | ||
914 | // Frames | ||
915 | // | ||
916 | #pragma mark CCSprite - Frames | ||
917 | |||
918 | -(void) setDisplayFrame:(CCSpriteFrame*)frame | ||
919 | { | ||
920 | unflippedOffsetPositionFromCenter_ = frame.offsetInPixels; | ||
921 | |||
922 | CCTexture2D *newTexture = [frame texture]; | ||
923 | // update texture before updating texture rect | ||
924 | if ( newTexture.name != texture_.name ) | ||
925 | [self setTexture: newTexture]; | ||
926 | |||
927 | // update rect | ||
928 | rectRotated_ = frame.rotated; | ||
929 | [self setTextureRectInPixels:frame.rectInPixels rotated:frame.rotated untrimmedSize:frame.originalSizeInPixels]; | ||
930 | } | ||
931 | |||
932 | // XXX deprecated | ||
933 | -(void) setDisplayFrame: (NSString*) animationName index:(int) frameIndex | ||
934 | { | ||
935 | if( ! animations_ ) | ||
936 | [self initAnimationDictionary]; | ||
937 | |||
938 | CCAnimation *a = [animations_ objectForKey: animationName]; | ||
939 | CCSpriteFrame *frame = [[a frames] objectAtIndex:frameIndex]; | ||
940 | |||
941 | NSAssert( frame, @"CCSprite#setDisplayFrame. Invalid frame"); | ||
942 | |||
943 | [self setDisplayFrame:frame]; | ||
944 | } | ||
945 | |||
946 | -(void) setDisplayFrameWithAnimationName: (NSString*) animationName index:(int) frameIndex | ||
947 | { | ||
948 | NSAssert( animationName, @"CCSprite#setDisplayFrameWithAnimationName. animationName must not be nil"); | ||
949 | |||
950 | CCAnimation *a = [[CCAnimationCache sharedAnimationCache] animationByName:animationName]; | ||
951 | |||
952 | NSAssert( a, @"CCSprite#setDisplayFrameWithAnimationName: Frame not found"); | ||
953 | |||
954 | CCSpriteFrame *frame = [[a frames] objectAtIndex:frameIndex]; | ||
955 | |||
956 | NSAssert( frame, @"CCSprite#setDisplayFrame. Invalid frame"); | ||
957 | |||
958 | [self setDisplayFrame:frame]; | ||
959 | } | ||
960 | |||
961 | |||
962 | -(BOOL) isFrameDisplayed:(CCSpriteFrame*)frame | ||
963 | { | ||
964 | CGRect r = [frame rect]; | ||
965 | return ( CGRectEqualToRect(r, rect_) && | ||
966 | frame.texture.name == self.texture.name ); | ||
967 | } | ||
968 | |||
969 | -(CCSpriteFrame*) displayedFrame | ||
970 | { | ||
971 | return [CCSpriteFrame frameWithTexture:texture_ | ||
972 | rectInPixels:rectInPixels_ | ||
973 | rotated:rectRotated_ | ||
974 | offset:unflippedOffsetPositionFromCenter_ | ||
975 | originalSize:contentSizeInPixels_]; | ||
976 | } | ||
977 | |||
978 | -(void) addAnimation: (CCAnimation*) anim | ||
979 | { | ||
980 | // lazy alloc | ||
981 | if( ! animations_ ) | ||
982 | [self initAnimationDictionary]; | ||
983 | |||
984 | [animations_ setObject:anim forKey:[anim name]]; | ||
985 | } | ||
986 | |||
987 | -(CCAnimation*)animationByName: (NSString*) animationName | ||
988 | { | ||
989 | NSAssert( animationName != nil, @"animationName parameter must be non nil"); | ||
990 | return [animations_ objectForKey:animationName]; | ||
991 | } | ||
992 | |||
993 | #pragma mark CCSprite - CocosNodeTexture protocol | ||
994 | |||
995 | -(void) updateBlendFunc | ||
996 | { | ||
997 | NSAssert( ! usesBatchNode_, @"CCSprite: updateBlendFunc doesn't work when the sprite is rendered using a CCSpriteBatchNode"); | ||
998 | |||
999 | // it's possible to have an untextured sprite | ||
1000 | if( !texture_ || ! [texture_ hasPremultipliedAlpha] ) { | ||
1001 | blendFunc_.src = GL_SRC_ALPHA; | ||
1002 | blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; | ||
1003 | [self setOpacityModifyRGB:NO]; | ||
1004 | } else { | ||
1005 | blendFunc_.src = CC_BLEND_SRC; | ||
1006 | blendFunc_.dst = CC_BLEND_DST; | ||
1007 | [self setOpacityModifyRGB:YES]; | ||
1008 | } | ||
1009 | } | ||
1010 | |||
1011 | -(void) setTexture:(CCTexture2D*)texture | ||
1012 | { | ||
1013 | NSAssert( ! usesBatchNode_, @"CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteBatchNode"); | ||
1014 | |||
1015 | // accept texture==nil as argument | ||
1016 | NSAssert( !texture || [texture isKindOfClass:[CCTexture2D class]], @"setTexture expects a CCTexture2D. Invalid argument"); | ||
1017 | |||
1018 | [texture_ release]; | ||
1019 | texture_ = [texture retain]; | ||
1020 | |||
1021 | [self updateBlendFunc]; | ||
1022 | } | ||
1023 | |||
1024 | -(CCTexture2D*) texture | ||
1025 | { | ||
1026 | return texture_; | ||
1027 | } | ||
1028 | |||
1029 | @end | ||
diff --git a/libs/cocos2d/CCSpriteBatchNode.h b/libs/cocos2d/CCSpriteBatchNode.h new file mode 100755 index 0000000..0342e24 --- /dev/null +++ b/libs/cocos2d/CCSpriteBatchNode.h | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (C) 2009 Matt Oswald | ||
5 | * | ||
6 | * Copyright (c) 2009-2010 Ricardo Quesada | ||
7 | * Copyright (c) 2011 Zynga Inc. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | |||
30 | #import "CCNode.h" | ||
31 | #import "CCProtocols.h" | ||
32 | #import "CCTextureAtlas.h" | ||
33 | #import "ccMacros.h" | ||
34 | |||
35 | #pragma mark CCSpriteBatchNode | ||
36 | |||
37 | @class CCSprite; | ||
38 | |||
39 | /** CCSpriteBatchNode is like a batch node: if it contains children, it will draw them in 1 single OpenGL call | ||
40 | * (often known as "batch draw"). | ||
41 | * | ||
42 | * A CCSpriteBatchNode can reference one and only one texture (one image file, one texture atlas). | ||
43 | * Only the CCSprites that are contained in that texture can be added to the CCSpriteBatchNode. | ||
44 | * All CCSprites added to a CCSpriteBatchNode are drawn in one OpenGL ES draw call. | ||
45 | * If the CCSprites are not added to a CCSpriteBatchNode then an OpenGL ES draw call will be needed for each one, which is less efficient. | ||
46 | * | ||
47 | * | ||
48 | * Limitations: | ||
49 | * - The only object that is accepted as child (or grandchild, grand-grandchild, etc...) is CCSprite or any subclass of CCSprite. eg: particles, labels and layer can't be added to a CCSpriteBatchNode. | ||
50 | * - Either all its children are Aliased or Antialiased. It can't be a mix. This is because "alias" is a property of the texture, and all the sprites share the same texture. | ||
51 | * | ||
52 | * @since v0.7.1 | ||
53 | */ | ||
54 | @interface CCSpriteBatchNode : CCNode <CCTextureProtocol> | ||
55 | { | ||
56 | CCTextureAtlas *textureAtlas_; | ||
57 | ccBlendFunc blendFunc_; | ||
58 | |||
59 | // all descendants: chlidren, gran children, etc... | ||
60 | CCArray *descendants_; | ||
61 | } | ||
62 | |||
63 | /** returns the TextureAtlas that is used */ | ||
64 | @property (nonatomic,readwrite,retain) CCTextureAtlas * textureAtlas; | ||
65 | |||
66 | /** conforms to CCTextureProtocol protocol */ | ||
67 | @property (nonatomic,readwrite) ccBlendFunc blendFunc; | ||
68 | |||
69 | /** descendants (children, gran children, etc) */ | ||
70 | @property (nonatomic,readonly) CCArray *descendants; | ||
71 | |||
72 | /** creates a CCSpriteBatchNode with a texture2d and a default capacity of 29 children. | ||
73 | The capacity will be increased in 33% in runtime if it run out of space. | ||
74 | */ | ||
75 | +(id)batchNodeWithTexture:(CCTexture2D *)tex; | ||
76 | +(id)spriteSheetWithTexture:(CCTexture2D *)tex DEPRECATED_ATTRIBUTE; | ||
77 | |||
78 | /** creates a CCSpriteBatchNode with a texture2d and capacity of children. | ||
79 | The capacity will be increased in 33% in runtime if it run out of space. | ||
80 | */ | ||
81 | +(id)batchNodeWithTexture:(CCTexture2D *)tex capacity:(NSUInteger)capacity; | ||
82 | +(id)spriteSheetWithTexture:(CCTexture2D *)tex capacity:(NSUInteger)capacity DEPRECATED_ATTRIBUTE; | ||
83 | |||
84 | /** creates a CCSpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) with a default capacity of 29 children. | ||
85 | The capacity will be increased in 33% in runtime if it run out of space. | ||
86 | The file will be loaded using the TextureMgr. | ||
87 | */ | ||
88 | +(id)batchNodeWithFile:(NSString*) fileImage; | ||
89 | +(id)spriteSheetWithFile:(NSString*) fileImage DEPRECATED_ATTRIBUTE; | ||
90 | |||
91 | /** creates a CCSpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) and capacity of children. | ||
92 | The capacity will be increased in 33% in runtime if it run out of space. | ||
93 | The file will be loaded using the TextureMgr. | ||
94 | */ | ||
95 | +(id)batchNodeWithFile:(NSString*)fileImage capacity:(NSUInteger)capacity; | ||
96 | +(id)spriteSheetWithFile:(NSString*)fileImage capacity:(NSUInteger)capacity DEPRECATED_ATTRIBUTE; | ||
97 | |||
98 | /** initializes a CCSpriteBatchNode with a texture2d and capacity of children. | ||
99 | The capacity will be increased in 33% in runtime if it run out of space. | ||
100 | */ | ||
101 | -(id)initWithTexture:(CCTexture2D *)tex capacity:(NSUInteger)capacity; | ||
102 | /** initializes a CCSpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) and a capacity of children. | ||
103 | The capacity will be increased in 33% in runtime if it run out of space. | ||
104 | The file will be loaded using the TextureMgr. | ||
105 | */ | ||
106 | -(id)initWithFile:(NSString*)fileImage capacity:(NSUInteger)capacity; | ||
107 | |||
108 | -(void) increaseAtlasCapacity; | ||
109 | |||
110 | /** creates an sprite with a rect in the CCSpriteBatchNode. | ||
111 | It's the same as: | ||
112 | - create an standard CCSsprite | ||
113 | - set the usingSpriteSheet = YES | ||
114 | - set the textureAtlas to the same texture Atlas as the CCSpriteBatchNode | ||
115 | @deprecated Use [CCSprite spriteWithBatchNode:rect:] instead; | ||
116 | */ | ||
117 | -(CCSprite*) createSpriteWithRect:(CGRect)rect DEPRECATED_ATTRIBUTE; | ||
118 | |||
119 | /** initializes a previously created sprite with a rect. This sprite will have the same texture as the CCSpriteBatchNode. | ||
120 | It's the same as: | ||
121 | - initialize an standard CCSsprite | ||
122 | - set the usingBatchNode = YES | ||
123 | - set the textureAtlas to the same texture Atlas as the CCSpriteBatchNode | ||
124 | @since v0.99.0 | ||
125 | @deprecated Use [CCSprite initWithBatchNode:rect:] instead; | ||
126 | */ | ||
127 | -(void) initSprite:(CCSprite*)sprite rect:(CGRect)rect DEPRECATED_ATTRIBUTE; | ||
128 | |||
129 | /** removes a child given a certain index. It will also cleanup the running actions depending on the cleanup parameter. | ||
130 | @warning Removing a child from a CCSpriteBatchNode is very slow | ||
131 | */ | ||
132 | -(void)removeChildAtIndex:(NSUInteger)index cleanup:(BOOL)doCleanup; | ||
133 | |||
134 | /** removes a child given a reference. It will also cleanup the running actions depending on the cleanup parameter. | ||
135 | @warning Removing a child from a CCSpriteBatchNode is very slow | ||
136 | */ | ||
137 | -(void)removeChild: (CCSprite *)sprite cleanup:(BOOL)doCleanup; | ||
138 | |||
139 | -(void) insertChild:(CCSprite*)child inAtlasAtIndex:(NSUInteger)index; | ||
140 | -(void) removeSpriteFromAtlas:(CCSprite*)sprite; | ||
141 | |||
142 | -(NSUInteger) rebuildIndexInOrder:(CCSprite*)parent atlasIndex:(NSUInteger)index; | ||
143 | -(NSUInteger) atlasIndexForChild:(CCSprite*)sprite atZ:(NSInteger)z; | ||
144 | |||
145 | @end | ||
diff --git a/libs/cocos2d/CCSpriteBatchNode.m b/libs/cocos2d/CCSpriteBatchNode.m new file mode 100755 index 0000000..7c8b05b --- /dev/null +++ b/libs/cocos2d/CCSpriteBatchNode.m | |||
@@ -0,0 +1,503 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (C) 2009 Matt Oswald | ||
5 | * | ||
6 | * Copyright (c) 2009-2010 Ricardo Quesada | ||
7 | * Copyright (c) 2011 Zynga Inc. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | |||
30 | #import "ccConfig.h" | ||
31 | #import "CCSprite.h" | ||
32 | #import "CCSpriteBatchNode.h" | ||
33 | #import "CCGrid.h" | ||
34 | #import "CCDrawingPrimitives.h" | ||
35 | #import "CCTextureCache.h" | ||
36 | #import "Support/CGPointExtension.h" | ||
37 | |||
38 | const NSUInteger defaultCapacity = 29; | ||
39 | |||
40 | #pragma mark - | ||
41 | #pragma mark CCSpriteBatchNode | ||
42 | |||
43 | static SEL selUpdate = NULL; | ||
44 | |||
45 | @interface CCSpriteBatchNode (private) | ||
46 | -(void) updateBlendFunc; | ||
47 | @end | ||
48 | |||
49 | @implementation CCSpriteBatchNode | ||
50 | |||
51 | @synthesize textureAtlas = textureAtlas_; | ||
52 | @synthesize blendFunc = blendFunc_; | ||
53 | @synthesize descendants = descendants_; | ||
54 | |||
55 | |||
56 | +(void) initialize | ||
57 | { | ||
58 | if ( self == [CCSpriteBatchNode class] ) { | ||
59 | selUpdate = @selector(updateTransform); | ||
60 | } | ||
61 | } | ||
62 | /* | ||
63 | * creation with CCTexture2D | ||
64 | */ | ||
65 | +(id)batchNodeWithTexture:(CCTexture2D *)tex | ||
66 | { | ||
67 | return [[[self alloc] initWithTexture:tex capacity:defaultCapacity] autorelease]; | ||
68 | } | ||
69 | +(id)spriteSheetWithTexture:(CCTexture2D *)tex // XXX DEPRECATED | ||
70 | { | ||
71 | return [self batchNodeWithTexture:tex]; | ||
72 | } | ||
73 | |||
74 | +(id)batchNodeWithTexture:(CCTexture2D *)tex capacity:(NSUInteger)capacity | ||
75 | { | ||
76 | return [[[self alloc] initWithTexture:tex capacity:capacity] autorelease]; | ||
77 | } | ||
78 | +(id)spriteSheetWithTexture:(CCTexture2D *)tex capacity:(NSUInteger)capacity // XXX DEPRECATED | ||
79 | { | ||
80 | return [self batchNodeWithTexture:tex capacity:capacity]; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * creation with File Image | ||
85 | */ | ||
86 | +(id)batchNodeWithFile:(NSString*)fileImage capacity:(NSUInteger)capacity | ||
87 | { | ||
88 | return [[[self alloc] initWithFile:fileImage capacity:capacity] autorelease]; | ||
89 | } | ||
90 | +(id)spriteSheetWithFile:(NSString*)fileImage capacity:(NSUInteger)capacity // XXX DEPRECATED | ||
91 | { | ||
92 | return [self batchNodeWithFile:fileImage capacity:capacity]; | ||
93 | } | ||
94 | |||
95 | +(id)batchNodeWithFile:(NSString*) imageFile | ||
96 | { | ||
97 | return [[[self alloc] initWithFile:imageFile capacity:defaultCapacity] autorelease]; | ||
98 | } | ||
99 | +(id)spriteSheetWithFile:(NSString*) imageFile // XXX DEPRECATED | ||
100 | { | ||
101 | return [self batchNodeWithFile:imageFile]; | ||
102 | } | ||
103 | |||
104 | |||
105 | /* | ||
106 | * init with CCTexture2D | ||
107 | */ | ||
108 | -(id)initWithTexture:(CCTexture2D *)tex capacity:(NSUInteger)capacity | ||
109 | { | ||
110 | if( (self=[super init])) { | ||
111 | |||
112 | blendFunc_.src = CC_BLEND_SRC; | ||
113 | blendFunc_.dst = CC_BLEND_DST; | ||
114 | textureAtlas_ = [[CCTextureAtlas alloc] initWithTexture:tex capacity:capacity]; | ||
115 | |||
116 | [self updateBlendFunc]; | ||
117 | |||
118 | // no lazy alloc in this node | ||
119 | children_ = [[CCArray alloc] initWithCapacity:capacity]; | ||
120 | descendants_ = [[CCArray alloc] initWithCapacity:capacity]; | ||
121 | } | ||
122 | |||
123 | return self; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * init with FileImage | ||
128 | */ | ||
129 | -(id)initWithFile:(NSString *)fileImage capacity:(NSUInteger)capacity | ||
130 | { | ||
131 | CCTexture2D *tex = [[CCTextureCache sharedTextureCache] addImage:fileImage]; | ||
132 | return [self initWithTexture:tex capacity:capacity]; | ||
133 | } | ||
134 | |||
135 | - (NSString*) description | ||
136 | { | ||
137 | return [NSString stringWithFormat:@"<%@ = %08X | Tag = %i>", [self class], self, tag_ ]; | ||
138 | } | ||
139 | |||
140 | -(void)dealloc | ||
141 | { | ||
142 | [textureAtlas_ release]; | ||
143 | [descendants_ release]; | ||
144 | |||
145 | [super dealloc]; | ||
146 | } | ||
147 | |||
148 | #pragma mark CCSpriteBatchNode - composition | ||
149 | |||
150 | // override visit. | ||
151 | // Don't call visit on it's children | ||
152 | -(void) visit | ||
153 | { | ||
154 | |||
155 | // CAREFUL: | ||
156 | // This visit is almost identical to CocosNode#visit | ||
157 | // with the exception that it doesn't call visit on it's children | ||
158 | // | ||
159 | // The alternative is to have a void CCSprite#visit, but | ||
160 | // although this is less mantainable, is faster | ||
161 | // | ||
162 | if (!visible_) | ||
163 | return; | ||
164 | |||
165 | glPushMatrix(); | ||
166 | |||
167 | if ( grid_ && grid_.active) { | ||
168 | [grid_ beforeDraw]; | ||
169 | [self transformAncestors]; | ||
170 | } | ||
171 | |||
172 | [self transform]; | ||
173 | |||
174 | [self draw]; | ||
175 | |||
176 | if ( grid_ && grid_.active) | ||
177 | [grid_ afterDraw:self]; | ||
178 | |||
179 | glPopMatrix(); | ||
180 | } | ||
181 | |||
182 | // XXX deprecated | ||
183 | -(CCSprite*) createSpriteWithRect:(CGRect)rect | ||
184 | { | ||
185 | CCSprite *sprite = [CCSprite spriteWithTexture:textureAtlas_.texture rect:rect]; | ||
186 | [sprite useBatchNode:self]; | ||
187 | |||
188 | return sprite; | ||
189 | } | ||
190 | |||
191 | // XXX deprecated | ||
192 | -(void) initSprite:(CCSprite*)sprite rect:(CGRect)rect | ||
193 | { | ||
194 | [sprite initWithTexture:textureAtlas_.texture rect:rect]; | ||
195 | [sprite useBatchNode:self]; | ||
196 | } | ||
197 | |||
198 | // override addChild: | ||
199 | -(void) addChild:(CCSprite*)child z:(NSInteger)z tag:(NSInteger) aTag | ||
200 | { | ||
201 | NSAssert( child != nil, @"Argument must be non-nil"); | ||
202 | NSAssert( [child isKindOfClass:[CCSprite class]], @"CCSpriteBatchNode only supports CCSprites as children"); | ||
203 | NSAssert( child.texture.name == textureAtlas_.texture.name, @"CCSprite is not using the same texture id"); | ||
204 | |||
205 | [super addChild:child z:z tag:aTag]; | ||
206 | |||
207 | NSUInteger index = [self atlasIndexForChild:child atZ:z]; | ||
208 | [self insertChild:child inAtlasAtIndex:index]; | ||
209 | } | ||
210 | |||
211 | // override reorderChild | ||
212 | -(void) reorderChild:(CCSprite*)child z:(NSInteger)z | ||
213 | { | ||
214 | NSAssert( child != nil, @"Child must be non-nil"); | ||
215 | NSAssert( [children_ containsObject:child], @"Child doesn't belong to Sprite" ); | ||
216 | |||
217 | if( z == child.zOrder ) | ||
218 | return; | ||
219 | |||
220 | // XXX: Instead of removing/adding, it is more efficient to reorder manually | ||
221 | [child retain]; | ||
222 | [self removeChild:child cleanup:NO]; | ||
223 | [self addChild:child z:z]; | ||
224 | [child release]; | ||
225 | } | ||
226 | |||
227 | // override removeChild: | ||
228 | -(void)removeChild: (CCSprite *)sprite cleanup:(BOOL)doCleanup | ||
229 | { | ||
230 | // explicit nil handling | ||
231 | if (sprite == nil) | ||
232 | return; | ||
233 | |||
234 | NSAssert([children_ containsObject:sprite], @"CCSpriteBatchNode doesn't contain the sprite. Can't remove it"); | ||
235 | |||
236 | // cleanup before removing | ||
237 | [self removeSpriteFromAtlas:sprite]; | ||
238 | |||
239 | [super removeChild:sprite cleanup:doCleanup]; | ||
240 | } | ||
241 | |||
242 | -(void)removeChildAtIndex:(NSUInteger)index cleanup:(BOOL)doCleanup | ||
243 | { | ||
244 | [self removeChild:(CCSprite *)[children_ objectAtIndex:index] cleanup:doCleanup]; | ||
245 | } | ||
246 | |||
247 | -(void)removeAllChildrenWithCleanup:(BOOL)doCleanup | ||
248 | { | ||
249 | // Invalidate atlas index. issue #569 | ||
250 | [children_ makeObjectsPerformSelector:@selector(useSelfRender)]; | ||
251 | |||
252 | [super removeAllChildrenWithCleanup:doCleanup]; | ||
253 | |||
254 | [descendants_ removeAllObjects]; | ||
255 | [textureAtlas_ removeAllQuads]; | ||
256 | } | ||
257 | |||
258 | #pragma mark CCSpriteBatchNode - draw | ||
259 | -(void) draw | ||
260 | { | ||
261 | [super draw]; | ||
262 | |||
263 | // Optimization: Fast Dispatch | ||
264 | if( textureAtlas_.totalQuads == 0 ) | ||
265 | return; | ||
266 | |||
267 | CCSprite *child; | ||
268 | ccArray *array = descendants_->data; | ||
269 | |||
270 | NSUInteger i = array->num; | ||
271 | id *arr = array->arr; | ||
272 | |||
273 | if( i > 0 ) { | ||
274 | |||
275 | while (i-- > 0) { | ||
276 | child = *arr++; | ||
277 | |||
278 | // fast dispatch | ||
279 | child->updateMethod(child, selUpdate); | ||
280 | |||
281 | #if CC_SPRITEBATCHNODE_DEBUG_DRAW | ||
282 | //Issue #528 | ||
283 | CGRect rect = [child boundingBox]; | ||
284 | CGPoint vertices[4]={ | ||
285 | ccp(rect.origin.x,rect.origin.y), | ||
286 | ccp(rect.origin.x+rect.size.width,rect.origin.y), | ||
287 | ccp(rect.origin.x+rect.size.width,rect.origin.y+rect.size.height), | ||
288 | ccp(rect.origin.x,rect.origin.y+rect.size.height), | ||
289 | }; | ||
290 | ccDrawPoly(vertices, 4, YES); | ||
291 | #endif // CC_SPRITEBATCHNODE_DEBUG_DRAW | ||
292 | } | ||
293 | } | ||
294 | |||
295 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
296 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
297 | // Unneeded states: - | ||
298 | |||
299 | BOOL newBlend = blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST; | ||
300 | if( newBlend ) | ||
301 | glBlendFunc( blendFunc_.src, blendFunc_.dst ); | ||
302 | |||
303 | [textureAtlas_ drawQuads]; | ||
304 | if( newBlend ) | ||
305 | glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); | ||
306 | } | ||
307 | |||
308 | #pragma mark CCSpriteBatchNode - private | ||
309 | -(void) increaseAtlasCapacity | ||
310 | { | ||
311 | // if we're going beyond the current TextureAtlas's capacity, | ||
312 | // all the previously initialized sprites will need to redo their texture coords | ||
313 | // this is likely computationally expensive | ||
314 | NSUInteger quantity = (textureAtlas_.capacity + 1) * 4 / 3; | ||
315 | |||
316 | CCLOG(@"cocos2d: CCSpriteBatchNode: resizing TextureAtlas capacity from [%lu] to [%lu].", | ||
317 | (long)textureAtlas_.capacity, | ||
318 | (long)quantity); | ||
319 | |||
320 | |||
321 | if( ! [textureAtlas_ resizeCapacity:quantity] ) { | ||
322 | // serious problems | ||
323 | CCLOG(@"cocos2d: WARNING: Not enough memory to resize the atlas"); | ||
324 | NSAssert(NO,@"XXX: SpriteSheet#increaseAtlasCapacity SHALL handle this assert"); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | |||
329 | #pragma mark CCSpriteBatchNode - Atlas Index Stuff | ||
330 | |||
331 | -(NSUInteger) rebuildIndexInOrder:(CCSprite*)node atlasIndex:(NSUInteger)index | ||
332 | { | ||
333 | CCSprite *sprite; | ||
334 | CCARRAY_FOREACH(node.children, sprite){ | ||
335 | if( sprite.zOrder < 0 ) | ||
336 | index = [self rebuildIndexInOrder:sprite atlasIndex:index]; | ||
337 | } | ||
338 | |||
339 | // ignore self (batch node) | ||
340 | if( ! [node isEqual:self]) { | ||
341 | node.atlasIndex = index; | ||
342 | index++; | ||
343 | } | ||
344 | |||
345 | CCARRAY_FOREACH(node.children, sprite){ | ||
346 | if( sprite.zOrder >= 0 ) | ||
347 | index = [self rebuildIndexInOrder:sprite atlasIndex:index]; | ||
348 | } | ||
349 | |||
350 | return index; | ||
351 | } | ||
352 | |||
353 | -(NSUInteger) highestAtlasIndexInChild:(CCSprite*)sprite | ||
354 | { | ||
355 | CCArray *array = [sprite children]; | ||
356 | NSUInteger count = [array count]; | ||
357 | if( count == 0 ) | ||
358 | return sprite.atlasIndex; | ||
359 | else | ||
360 | return [self highestAtlasIndexInChild:[array lastObject]]; | ||
361 | } | ||
362 | |||
363 | -(NSUInteger) lowestAtlasIndexInChild:(CCSprite*)sprite | ||
364 | { | ||
365 | CCArray *array = [sprite children]; | ||
366 | NSUInteger count = [array count]; | ||
367 | if( count == 0 ) | ||
368 | return sprite.atlasIndex; | ||
369 | else | ||
370 | return [self lowestAtlasIndexInChild:[array objectAtIndex:0] ]; | ||
371 | } | ||
372 | |||
373 | |||
374 | -(NSUInteger)atlasIndexForChild:(CCSprite*)sprite atZ:(NSInteger)z | ||
375 | { | ||
376 | CCArray *brothers = [[sprite parent] children]; | ||
377 | NSUInteger childIndex = [brothers indexOfObject:sprite]; | ||
378 | |||
379 | // ignore parent Z if parent is batchnode | ||
380 | BOOL ignoreParent = ( sprite.parent == self ); | ||
381 | CCSprite *previous = nil; | ||
382 | if( childIndex > 0 ) | ||
383 | previous = [brothers objectAtIndex:childIndex-1]; | ||
384 | |||
385 | // first child of the sprite sheet | ||
386 | if( ignoreParent ) { | ||
387 | if( childIndex == 0 ) | ||
388 | return 0; | ||
389 | // else | ||
390 | return [self highestAtlasIndexInChild: previous] + 1; | ||
391 | } | ||
392 | |||
393 | // parent is a CCSprite, so, it must be taken into account | ||
394 | |||
395 | // first child of an CCSprite ? | ||
396 | if( childIndex == 0 ) | ||
397 | { | ||
398 | CCSprite *p = (CCSprite*) sprite.parent; | ||
399 | |||
400 | // less than parent and brothers | ||
401 | if( z < 0 ) | ||
402 | return p.atlasIndex; | ||
403 | else | ||
404 | return p.atlasIndex+1; | ||
405 | |||
406 | } else { | ||
407 | // previous & sprite belong to the same branch | ||
408 | if( ( previous.zOrder < 0 && z < 0 )|| (previous.zOrder >= 0 && z >= 0) ) | ||
409 | return [self highestAtlasIndexInChild:previous] + 1; | ||
410 | |||
411 | // else (previous < 0 and sprite >= 0 ) | ||
412 | CCSprite *p = (CCSprite*) sprite.parent; | ||
413 | return p.atlasIndex + 1; | ||
414 | } | ||
415 | |||
416 | NSAssert( NO, @"Should not happen. Error calculating Z on Batch Node"); | ||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | #pragma mark CCSpriteBatchNode - add / remove / reorder helper methods | ||
421 | // add child helper | ||
422 | -(void) insertChild:(CCSprite*)sprite inAtlasAtIndex:(NSUInteger)index | ||
423 | { | ||
424 | [sprite useBatchNode:self]; | ||
425 | [sprite setAtlasIndex:index]; | ||
426 | [sprite setDirty: YES]; | ||
427 | |||
428 | if(textureAtlas_.totalQuads == textureAtlas_.capacity) | ||
429 | [self increaseAtlasCapacity]; | ||
430 | |||
431 | ccV3F_C4B_T2F_Quad quad = [sprite quad]; | ||
432 | [textureAtlas_ insertQuad:&quad atIndex:index]; | ||
433 | |||
434 | ccArray *descendantsData = descendants_->data; | ||
435 | |||
436 | ccArrayInsertObjectAtIndex(descendantsData, sprite, index); | ||
437 | |||
438 | // update indices | ||
439 | NSUInteger i = index+1; | ||
440 | CCSprite *child; | ||
441 | for(; i<descendantsData->num; i++){ | ||
442 | child = descendantsData->arr[i]; | ||
443 | child.atlasIndex = child.atlasIndex + 1; | ||
444 | } | ||
445 | |||
446 | // add children recursively | ||
447 | CCARRAY_FOREACH(sprite.children, child){ | ||
448 | NSUInteger idx = [self atlasIndexForChild:child atZ: child.zOrder]; | ||
449 | [self insertChild:child inAtlasAtIndex:idx]; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | // remove child helper | ||
454 | -(void) removeSpriteFromAtlas:(CCSprite*)sprite | ||
455 | { | ||
456 | // remove from TextureAtlas | ||
457 | [textureAtlas_ removeQuadAtIndex:sprite.atlasIndex]; | ||
458 | |||
459 | // Cleanup sprite. It might be reused (issue #569) | ||
460 | [sprite useSelfRender]; | ||
461 | |||
462 | ccArray *descendantsData = descendants_->data; | ||
463 | NSUInteger index = ccArrayGetIndexOfObject(descendantsData, sprite); | ||
464 | if( index != NSNotFound ) { | ||
465 | ccArrayRemoveObjectAtIndex(descendantsData, index); | ||
466 | |||
467 | // update all sprites beyond this one | ||
468 | NSUInteger count = descendantsData->num; | ||
469 | |||
470 | for(; index < count; index++) | ||
471 | { | ||
472 | CCSprite *s = descendantsData->arr[index]; | ||
473 | s.atlasIndex = s.atlasIndex - 1; | ||
474 | } | ||
475 | } | ||
476 | |||
477 | // remove children recursively | ||
478 | CCSprite *child; | ||
479 | CCARRAY_FOREACH(sprite.children, child) | ||
480 | [self removeSpriteFromAtlas:child]; | ||
481 | } | ||
482 | |||
483 | #pragma mark CCSpriteBatchNode - CocosNodeTexture protocol | ||
484 | |||
485 | -(void) updateBlendFunc | ||
486 | { | ||
487 | if( ! [textureAtlas_.texture hasPremultipliedAlpha] ) { | ||
488 | blendFunc_.src = GL_SRC_ALPHA; | ||
489 | blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; | ||
490 | } | ||
491 | } | ||
492 | |||
493 | -(void) setTexture:(CCTexture2D*)texture | ||
494 | { | ||
495 | textureAtlas_.texture = texture; | ||
496 | [self updateBlendFunc]; | ||
497 | } | ||
498 | |||
499 | -(CCTexture2D*) texture | ||
500 | { | ||
501 | return textureAtlas_.texture; | ||
502 | } | ||
503 | @end | ||
diff --git a/libs/cocos2d/CCSpriteFrame.h b/libs/cocos2d/CCSpriteFrame.h new file mode 100755 index 0000000..983aeed --- /dev/null +++ b/libs/cocos2d/CCSpriteFrame.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2011 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 | #import <Foundation/Foundation.h> | ||
28 | #import "CCNode.h" | ||
29 | #import "CCProtocols.h" | ||
30 | |||
31 | /** A CCSpriteFrame has: | ||
32 | - texture: A CCTexture2D that will be used by the CCSprite | ||
33 | - rectangle: A rectangle of the texture | ||
34 | |||
35 | |||
36 | You can modify the frame of a CCSprite by doing: | ||
37 | |||
38 | CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:texture rect:rect offset:offset]; | ||
39 | [sprite setDisplayFrame:frame]; | ||
40 | */ | ||
41 | @interface CCSpriteFrame : NSObject <NSCopying> | ||
42 | { | ||
43 | CGRect rect_; | ||
44 | CGRect rectInPixels_; | ||
45 | BOOL rotated_; | ||
46 | CGPoint offsetInPixels_; | ||
47 | CGSize originalSizeInPixels_; | ||
48 | CCTexture2D *texture_; | ||
49 | } | ||
50 | /** rect of the frame in points. If it is updated, then rectInPixels will be updated too. */ | ||
51 | @property (nonatomic,readwrite) CGRect rect; | ||
52 | |||
53 | /** rect of the frame in pixels. If it is updated, then rect (points) will be udpated too. */ | ||
54 | @property (nonatomic,readwrite) CGRect rectInPixels; | ||
55 | |||
56 | /** whether or not the rect of the frame is rotated ( x = x+width, y = y+height, width = height, height = width ) */ | ||
57 | @property (nonatomic,readwrite) BOOL rotated; | ||
58 | |||
59 | /** offset of the frame in pixels */ | ||
60 | @property (nonatomic,readwrite) CGPoint offsetInPixels; | ||
61 | |||
62 | /** original size of the trimmed image in pixels */ | ||
63 | @property (nonatomic,readwrite) CGSize originalSizeInPixels; | ||
64 | |||
65 | /** texture of the frame */ | ||
66 | @property (nonatomic, retain, readwrite) CCTexture2D *texture; | ||
67 | |||
68 | /** Create a CCSpriteFrame with a texture, rect in points. | ||
69 | It is assumed that the frame was not trimmed. | ||
70 | */ | ||
71 | +(id) frameWithTexture:(CCTexture2D*)texture rect:(CGRect)rect; | ||
72 | |||
73 | /** Create a CCSpriteFrame with a texture, rect, rotated, offset and originalSize in pixels. | ||
74 | The originalSize is the size in points of the frame before being trimmed. | ||
75 | */ | ||
76 | +(id) frameWithTexture:(CCTexture2D*)texture rectInPixels:(CGRect)rect rotated:(BOOL)rotated offset:(CGPoint)offset originalSize:(CGSize)originalSize; | ||
77 | |||
78 | |||
79 | /** Initializes a CCSpriteFrame with a texture, rect in points; | ||
80 | It is assumed that the frame was not trimmed. | ||
81 | */ | ||
82 | -(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect; | ||
83 | |||
84 | /** Initializes a CCSpriteFrame with a texture, rect, rotated, offset and originalSize in pixels. | ||
85 | The originalSize is the size in points of the frame before being trimmed. | ||
86 | */ | ||
87 | -(id) initWithTexture:(CCTexture2D*)texture rectInPixels:(CGRect)rect rotated:(BOOL)rotated offset:(CGPoint)offset originalSize:(CGSize)originalSize; | ||
88 | |||
89 | @end | ||
90 | |||
diff --git a/libs/cocos2d/CCSpriteFrame.m b/libs/cocos2d/CCSpriteFrame.m new file mode 100755 index 0000000..e9ebd04 --- /dev/null +++ b/libs/cocos2d/CCSpriteFrame.m | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2008-2011 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 | #import "CCTextureCache.h" | ||
29 | #import "CCSpriteFrame.h" | ||
30 | #import "ccMacros.h" | ||
31 | |||
32 | @implementation CCSpriteFrame | ||
33 | @synthesize rotated = rotated_, offsetInPixels = offsetInPixels_, texture = texture_; | ||
34 | @synthesize originalSizeInPixels=originalSizeInPixels_; | ||
35 | |||
36 | +(id) frameWithTexture:(CCTexture2D*)texture rect:(CGRect)rect | ||
37 | { | ||
38 | return [[[self alloc] initWithTexture:texture rect:rect] autorelease]; | ||
39 | } | ||
40 | |||
41 | +(id) frameWithTexture:(CCTexture2D*)texture rectInPixels:(CGRect)rect rotated:(BOOL)rotated offset:(CGPoint)offset originalSize:(CGSize)originalSize | ||
42 | { | ||
43 | return [[[self alloc] initWithTexture:texture rectInPixels:rect rotated:rotated offset:offset originalSize:originalSize] autorelease]; | ||
44 | } | ||
45 | |||
46 | -(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect | ||
47 | { | ||
48 | CGRect rectInPixels = CC_RECT_POINTS_TO_PIXELS( rect ); | ||
49 | return [self initWithTexture:texture rectInPixels:rectInPixels rotated:NO offset:CGPointZero originalSize:rectInPixels.size]; | ||
50 | } | ||
51 | |||
52 | -(id) initWithTexture:(CCTexture2D*)texture rectInPixels:(CGRect)rect rotated:(BOOL)rotated offset:(CGPoint)offset originalSize:(CGSize)originalSize | ||
53 | { | ||
54 | if( (self=[super init]) ) { | ||
55 | self.texture = texture; | ||
56 | rectInPixels_ = rect; | ||
57 | rect_ = CC_RECT_PIXELS_TO_POINTS( rect ); | ||
58 | rotated_ = rotated; | ||
59 | offsetInPixels_ = offset; | ||
60 | originalSizeInPixels_ = originalSize; | ||
61 | } | ||
62 | return self; | ||
63 | } | ||
64 | |||
65 | - (NSString*) description | ||
66 | { | ||
67 | return [NSString stringWithFormat:@"<%@ = %08X | TextureName=%d, Rect = (%.2f,%.2f,%.2f,%.2f)> rotated:%d", [self class], self, | ||
68 | texture_.name, | ||
69 | rect_.origin.x, | ||
70 | rect_.origin.y, | ||
71 | rect_.size.width, | ||
72 | rect_.size.height, | ||
73 | rotated_ | ||
74 | ]; | ||
75 | } | ||
76 | |||
77 | - (void) dealloc | ||
78 | { | ||
79 | CCLOGINFO( @"cocos2d: deallocing %@",self); | ||
80 | [texture_ release]; | ||
81 | [super dealloc]; | ||
82 | } | ||
83 | |||
84 | -(id) copyWithZone: (NSZone*) zone | ||
85 | { | ||
86 | CCSpriteFrame *copy = [[[self class] allocWithZone: zone] initWithTexture:texture_ rectInPixels:rectInPixels_ rotated:rotated_ offset:offsetInPixels_ originalSize:originalSizeInPixels_]; | ||
87 | return copy; | ||
88 | } | ||
89 | |||
90 | -(CGRect) rect | ||
91 | { | ||
92 | return rect_; | ||
93 | } | ||
94 | |||
95 | -(CGRect) rectInPixels | ||
96 | { | ||
97 | return rectInPixels_; | ||
98 | } | ||
99 | |||
100 | -(void) setRect:(CGRect)rect | ||
101 | { | ||
102 | rect_ = rect; | ||
103 | rectInPixels_ = CC_RECT_POINTS_TO_PIXELS( rect_ ); | ||
104 | } | ||
105 | |||
106 | -(void) setRectInPixels:(CGRect)rectInPixels | ||
107 | { | ||
108 | rectInPixels_ = rectInPixels; | ||
109 | rect_ = CC_RECT_PIXELS_TO_POINTS(rectInPixels); | ||
110 | } | ||
111 | @end | ||
diff --git a/libs/cocos2d/CCSpriteFrameCache.h b/libs/cocos2d/CCSpriteFrameCache.h new file mode 100755 index 0000000..d3119a6 --- /dev/null +++ b/libs/cocos2d/CCSpriteFrameCache.h | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Jason Booth | ||
5 | * | ||
6 | * Copyright (c) 2009 Robert J Payne | ||
7 | * | ||
8 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
9 | * Copyright (c) 2011 Zynga Inc. | ||
10 | * | ||
11 | * | ||
12 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
13 | * of this software and associated documentation files (the "Software"), to deal | ||
14 | * in the Software without restriction, including without limitation the rights | ||
15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
16 | * copies of the Software, and to permit persons to whom the Software is | ||
17 | * furnished to do so, subject to the following conditions: | ||
18 | * | ||
19 | * The above copyright notice and this permission notice shall be included in | ||
20 | * all copies or substantial portions of the Software. | ||
21 | * | ||
22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
28 | * THE SOFTWARE. | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | |||
33 | /* | ||
34 | * To create sprite frames and texture atlas, use this tool: | ||
35 | * http://zwoptex.zwopple.com/ | ||
36 | */ | ||
37 | |||
38 | #import <Foundation/Foundation.h> | ||
39 | |||
40 | #import "CCSpriteFrame.h" | ||
41 | #import "CCTexture2D.h" | ||
42 | |||
43 | @class CCSprite; | ||
44 | |||
45 | /** Singleton that handles the loading of the sprite frames. | ||
46 | It saves in a cache the sprite frames. | ||
47 | @since v0.9 | ||
48 | */ | ||
49 | @interface CCSpriteFrameCache : NSObject | ||
50 | { | ||
51 | NSMutableDictionary *spriteFrames_; | ||
52 | NSMutableDictionary *spriteFramesAliases_; | ||
53 | } | ||
54 | |||
55 | /** Retruns ths shared instance of the Sprite Frame cache */ | ||
56 | + (CCSpriteFrameCache *) sharedSpriteFrameCache; | ||
57 | |||
58 | /** Purges the cache. It releases all the Sprite Frames and the retained instance. | ||
59 | */ | ||
60 | +(void)purgeSharedSpriteFrameCache; | ||
61 | |||
62 | |||
63 | /** Adds multiple Sprite Frames with a dictionary. The texture will be associated with the created sprite frames. | ||
64 | */ | ||
65 | -(void) addSpriteFramesWithDictionary:(NSDictionary*)dictionary texture:(CCTexture2D*)texture; | ||
66 | |||
67 | /** Adds multiple Sprite Frames from a plist file. | ||
68 | * A texture will be loaded automatically. The texture name will composed by replacing the .plist suffix with .png | ||
69 | * If you want to use another texture, you should use the addSpriteFramesWithFile:texture method. | ||
70 | */ | ||
71 | -(void) addSpriteFramesWithFile:(NSString*)plist; | ||
72 | |||
73 | /** Adds multiple Sprite Frames from a plist file. The texture will be associated with the created sprite frames. | ||
74 | */ | ||
75 | -(void) addSpriteFramesWithFile:(NSString*)plist texture:(CCTexture2D*)texture; | ||
76 | |||
77 | /** Adds multiple Sprite Frames from a plist file. The texture will be associated with the created sprite frames. | ||
78 | @since v0.99.5 | ||
79 | */ | ||
80 | -(void) addSpriteFramesWithFile:(NSString*)plist textureFile:(NSString*)textureFileName; | ||
81 | |||
82 | /** Adds an sprite frame with a given name. | ||
83 | If the name already exists, then the contents of the old name will be replaced with the new one. | ||
84 | */ | ||
85 | -(void) addSpriteFrame:(CCSpriteFrame*)frame name:(NSString*)frameName; | ||
86 | |||
87 | |||
88 | /** Purges the dictionary of loaded sprite frames. | ||
89 | * Call this method if you receive the "Memory Warning". | ||
90 | * In the short term: it will free some resources preventing your app from being killed. | ||
91 | * In the medium term: it will allocate more resources. | ||
92 | * In the long term: it will be the same. | ||
93 | */ | ||
94 | -(void) removeSpriteFrames; | ||
95 | |||
96 | /** Removes unused sprite frames. | ||
97 | * Sprite Frames that have a retain count of 1 will be deleted. | ||
98 | * It is convinient to call this method after when starting a new Scene. | ||
99 | */ | ||
100 | -(void) removeUnusedSpriteFrames; | ||
101 | |||
102 | /** Deletes an sprite frame from the sprite frame cache. | ||
103 | */ | ||
104 | -(void) removeSpriteFrameByName:(NSString*)name; | ||
105 | |||
106 | /** Removes multiple Sprite Frames from a plist file. | ||
107 | * Sprite Frames stored in this file will be removed. | ||
108 | * It is convinient to call this method when a specific texture needs to be removed. | ||
109 | * @since v0.99.5 | ||
110 | */ | ||
111 | - (void) removeSpriteFramesFromFile:(NSString*) plist; | ||
112 | |||
113 | /** Removes multiple Sprite Frames from NSDictionary. | ||
114 | * @since v0.99.5 | ||
115 | */ | ||
116 | - (void) removeSpriteFramesFromDictionary:(NSDictionary*) dictionary; | ||
117 | |||
118 | /** Removes all Sprite Frames associated with the specified textures. | ||
119 | * It is convinient to call this method when a specific texture needs to be removed. | ||
120 | * @since v0.995. | ||
121 | */ | ||
122 | - (void) removeSpriteFramesFromTexture:(CCTexture2D*) texture; | ||
123 | |||
124 | /** Returns an Sprite Frame that was previously added. | ||
125 | If the name is not found it will return nil. | ||
126 | You should retain the returned copy if you are going to use it. | ||
127 | */ | ||
128 | -(CCSpriteFrame*) spriteFrameByName:(NSString*)name; | ||
129 | |||
130 | /** Creates an sprite with the name of an sprite frame. | ||
131 | The created sprite will contain the texture, rect and offset of the sprite frame. | ||
132 | It returns an autorelease object. | ||
133 | @deprecated use [CCSprite spriteWithSpriteFrameName:name]. This method will be removed on final v0.9 | ||
134 | */ | ||
135 | -(CCSprite*) createSpriteWithFrameName:(NSString*)name DEPRECATED_ATTRIBUTE; | ||
136 | |||
137 | @end | ||
diff --git a/libs/cocos2d/CCSpriteFrameCache.m b/libs/cocos2d/CCSpriteFrameCache.m new file mode 100755 index 0000000..f154c3d --- /dev/null +++ b/libs/cocos2d/CCSpriteFrameCache.m | |||
@@ -0,0 +1,347 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Jason Booth | ||
5 | * | ||
6 | * Copyright (c) 2009 Robert J Payne | ||
7 | * | ||
8 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
9 | * Copyright (c) 2011 Zynga Inc. | ||
10 | * | ||
11 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
12 | * of this software and associated documentation files (the "Software"), to deal | ||
13 | * in the Software without restriction, including without limitation the rights | ||
14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
15 | * copies of the Software, and to permit persons to whom the Software is | ||
16 | * furnished to do so, subject to the following conditions: | ||
17 | * | ||
18 | * The above copyright notice and this permission notice shall be included in | ||
19 | * all copies or substantial portions of the Software. | ||
20 | * | ||
21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
27 | * THE SOFTWARE. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | /* | ||
32 | * To create sprite frames and texture atlas, use this tool: | ||
33 | * http://zwoptex.zwopple.com/ | ||
34 | */ | ||
35 | |||
36 | #import "Platforms/CCNS.h" | ||
37 | #import "ccMacros.h" | ||
38 | #import "CCTextureCache.h" | ||
39 | #import "CCSpriteFrameCache.h" | ||
40 | #import "CCSpriteFrame.h" | ||
41 | #import "CCSprite.h" | ||
42 | #import "Support/CCFileUtils.h" | ||
43 | |||
44 | |||
45 | @implementation CCSpriteFrameCache | ||
46 | |||
47 | #pragma mark CCSpriteFrameCache - Alloc, Init & Dealloc | ||
48 | |||
49 | static CCSpriteFrameCache *sharedSpriteFrameCache_=nil; | ||
50 | |||
51 | + (CCSpriteFrameCache *)sharedSpriteFrameCache | ||
52 | { | ||
53 | if (!sharedSpriteFrameCache_) | ||
54 | sharedSpriteFrameCache_ = [[CCSpriteFrameCache alloc] init]; | ||
55 | |||
56 | return sharedSpriteFrameCache_; | ||
57 | } | ||
58 | |||
59 | +(id)alloc | ||
60 | { | ||
61 | NSAssert(sharedSpriteFrameCache_ == nil, @"Attempted to allocate a second instance of a singleton."); | ||
62 | return [super alloc]; | ||
63 | } | ||
64 | |||
65 | +(void)purgeSharedSpriteFrameCache | ||
66 | { | ||
67 | [sharedSpriteFrameCache_ release]; | ||
68 | sharedSpriteFrameCache_ = nil; | ||
69 | } | ||
70 | |||
71 | -(id) init | ||
72 | { | ||
73 | if( (self=[super init]) ) { | ||
74 | spriteFrames_ = [[NSMutableDictionary alloc] initWithCapacity: 100]; | ||
75 | spriteFramesAliases_ = [[NSMutableDictionary alloc] initWithCapacity:10]; | ||
76 | } | ||
77 | |||
78 | return self; | ||
79 | } | ||
80 | |||
81 | - (NSString*) description | ||
82 | { | ||
83 | return [NSString stringWithFormat:@"<%@ = %08X | num of sprite frames = %i>", [self class], self, [spriteFrames_ count]]; | ||
84 | } | ||
85 | |||
86 | -(void) dealloc | ||
87 | { | ||
88 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
89 | |||
90 | [spriteFrames_ release]; | ||
91 | [spriteFramesAliases_ release]; | ||
92 | [super dealloc]; | ||
93 | } | ||
94 | |||
95 | #pragma mark CCSpriteFrameCache - loading sprite frames | ||
96 | |||
97 | -(void) addSpriteFramesWithDictionary:(NSDictionary*)dictionary texture:(CCTexture2D*)texture | ||
98 | { | ||
99 | /* | ||
100 | Supported Zwoptex Formats: | ||
101 | ZWTCoordinatesFormatOptionXMLLegacy = 0, // Flash Version | ||
102 | ZWTCoordinatesFormatOptionXML1_0 = 1, // Desktop Version 0.0 - 0.4b | ||
103 | ZWTCoordinatesFormatOptionXML1_1 = 2, // Desktop Version 1.0.0 - 1.0.1 | ||
104 | ZWTCoordinatesFormatOptionXML1_2 = 3, // Desktop Version 1.0.2+ | ||
105 | */ | ||
106 | NSDictionary *metadataDict = [dictionary objectForKey:@"metadata"]; | ||
107 | NSDictionary *framesDict = [dictionary objectForKey:@"frames"]; | ||
108 | |||
109 | int format = 0; | ||
110 | |||
111 | // get the format | ||
112 | if(metadataDict != nil) | ||
113 | format = [[metadataDict objectForKey:@"format"] intValue]; | ||
114 | |||
115 | // check the format | ||
116 | NSAssert( format >= 0 && format <= 3, @"cocos2d: WARNING: format is not supported for CCSpriteFrameCache addSpriteFramesWithDictionary:texture:"); | ||
117 | |||
118 | |||
119 | // add real frames | ||
120 | for(NSString *frameDictKey in framesDict) { | ||
121 | NSDictionary *frameDict = [framesDict objectForKey:frameDictKey]; | ||
122 | CCSpriteFrame *spriteFrame; | ||
123 | if(format == 0) { | ||
124 | float x = [[frameDict objectForKey:@"x"] floatValue]; | ||
125 | float y = [[frameDict objectForKey:@"y"] floatValue]; | ||
126 | float w = [[frameDict objectForKey:@"width"] floatValue]; | ||
127 | float h = [[frameDict objectForKey:@"height"] floatValue]; | ||
128 | float ox = [[frameDict objectForKey:@"offsetX"] floatValue]; | ||
129 | float oy = [[frameDict objectForKey:@"offsetY"] floatValue]; | ||
130 | int ow = [[frameDict objectForKey:@"originalWidth"] intValue]; | ||
131 | int oh = [[frameDict objectForKey:@"originalHeight"] intValue]; | ||
132 | // check ow/oh | ||
133 | if(!ow || !oh) | ||
134 | CCLOG(@"cocos2d: WARNING: originalWidth/Height not found on the CCSpriteFrame. AnchorPoint won't work as expected. Regenerate the .plist"); | ||
135 | |||
136 | // abs ow/oh | ||
137 | ow = abs(ow); | ||
138 | oh = abs(oh); | ||
139 | // create frame | ||
140 | |||
141 | spriteFrame = [[CCSpriteFrame alloc] initWithTexture:texture | ||
142 | rectInPixels:CGRectMake(x, y, w, h) | ||
143 | rotated:NO | ||
144 | offset:CGPointMake(ox, oy) | ||
145 | originalSize:CGSizeMake(ow, oh)]; | ||
146 | } else if(format == 1 || format == 2) { | ||
147 | CGRect frame = CCRectFromString([frameDict objectForKey:@"frame"]); | ||
148 | BOOL rotated = NO; | ||
149 | |||
150 | // rotation | ||
151 | if(format == 2) | ||
152 | rotated = [[frameDict objectForKey:@"rotated"] boolValue]; | ||
153 | |||
154 | CGPoint offset = CCPointFromString([frameDict objectForKey:@"offset"]); | ||
155 | CGSize sourceSize = CCSizeFromString([frameDict objectForKey:@"sourceSize"]); | ||
156 | |||
157 | // create frame | ||
158 | spriteFrame = [[CCSpriteFrame alloc] initWithTexture:texture | ||
159 | rectInPixels:frame | ||
160 | rotated:rotated | ||
161 | offset:offset | ||
162 | originalSize:sourceSize]; | ||
163 | } else if(format == 3) { | ||
164 | // get values | ||
165 | CGSize spriteSize = CCSizeFromString([frameDict objectForKey:@"spriteSize"]); | ||
166 | CGPoint spriteOffset = CCPointFromString([frameDict objectForKey:@"spriteOffset"]); | ||
167 | CGSize spriteSourceSize = CCSizeFromString([frameDict objectForKey:@"spriteSourceSize"]); | ||
168 | CGRect textureRect = CCRectFromString([frameDict objectForKey:@"textureRect"]); | ||
169 | BOOL textureRotated = [[frameDict objectForKey:@"textureRotated"] boolValue]; | ||
170 | |||
171 | // get aliases | ||
172 | NSArray *aliases = [frameDict objectForKey:@"aliases"]; | ||
173 | for(NSString *alias in aliases) { | ||
174 | if( [spriteFramesAliases_ objectForKey:alias] ) | ||
175 | CCLOG(@"cocos2d: WARNING: an alias with name %@ already exists",alias); | ||
176 | |||
177 | [spriteFramesAliases_ setObject:frameDictKey forKey:alias]; | ||
178 | } | ||
179 | |||
180 | // create frame | ||
181 | spriteFrame = [[CCSpriteFrame alloc] initWithTexture:texture | ||
182 | rectInPixels:CGRectMake(textureRect.origin.x, textureRect.origin.y, spriteSize.width, spriteSize.height) | ||
183 | rotated:textureRotated | ||
184 | offset:spriteOffset | ||
185 | originalSize:spriteSourceSize]; | ||
186 | } | ||
187 | |||
188 | // add sprite frame | ||
189 | [spriteFrames_ setObject:spriteFrame forKey:frameDictKey]; | ||
190 | [spriteFrame release]; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | -(void) addSpriteFramesWithFile:(NSString*)plist texture:(CCTexture2D*)texture | ||
195 | { | ||
196 | NSString *path = [CCFileUtils fullPathFromRelativePath:plist]; | ||
197 | NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; | ||
198 | |||
199 | [self addSpriteFramesWithDictionary:dict texture:texture]; | ||
200 | } | ||
201 | |||
202 | -(void) addSpriteFramesWithFile:(NSString*)plist textureFile:(NSString*)textureFileName | ||
203 | { | ||
204 | NSAssert( textureFileName, @"Invalid texture file name"); | ||
205 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage:textureFileName]; | ||
206 | |||
207 | if( texture ) | ||
208 | [self addSpriteFramesWithFile:plist texture:texture]; | ||
209 | else | ||
210 | CCLOG(@"cocos2d: CCSpriteFrameCache: couldn't load texture file. File not found: %@", textureFileName); | ||
211 | } | ||
212 | |||
213 | -(void) addSpriteFramesWithFile:(NSString*)plist | ||
214 | { | ||
215 | NSString *path = [CCFileUtils fullPathFromRelativePath:plist]; | ||
216 | NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; | ||
217 | |||
218 | NSString *texturePath = nil; | ||
219 | NSDictionary *metadataDict = [dict objectForKey:@"metadata"]; | ||
220 | if( metadataDict ) | ||
221 | // try to read texture file name from meta data | ||
222 | texturePath = [metadataDict objectForKey:@"textureFileName"]; | ||
223 | |||
224 | |||
225 | if( texturePath ) | ||
226 | { | ||
227 | // build texture path relative to plist file | ||
228 | NSString *textureBase = [plist stringByDeletingLastPathComponent]; | ||
229 | texturePath = [textureBase stringByAppendingPathComponent:texturePath]; | ||
230 | } else { | ||
231 | // build texture path by replacing file extension | ||
232 | texturePath = [plist stringByDeletingPathExtension]; | ||
233 | texturePath = [texturePath stringByAppendingPathExtension:@"png"]; | ||
234 | |||
235 | CCLOG(@"cocos2d: CCSpriteFrameCache: Trying to use file '%@' as texture", texturePath); | ||
236 | } | ||
237 | |||
238 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage:texturePath]; | ||
239 | |||
240 | if( texture ) | ||
241 | [self addSpriteFramesWithDictionary:dict texture:texture]; | ||
242 | |||
243 | else | ||
244 | CCLOG(@"cocos2d: CCSpriteFrameCache: Couldn't load texture"); | ||
245 | } | ||
246 | |||
247 | -(void) addSpriteFrame:(CCSpriteFrame*)frame name:(NSString*)frameName | ||
248 | { | ||
249 | [spriteFrames_ setObject:frame forKey:frameName]; | ||
250 | } | ||
251 | |||
252 | #pragma mark CCSpriteFrameCache - removing | ||
253 | |||
254 | -(void) removeSpriteFrames | ||
255 | { | ||
256 | [spriteFrames_ removeAllObjects]; | ||
257 | [spriteFramesAliases_ removeAllObjects]; | ||
258 | } | ||
259 | |||
260 | -(void) removeUnusedSpriteFrames | ||
261 | { | ||
262 | NSArray *keys = [spriteFrames_ allKeys]; | ||
263 | for( id key in keys ) { | ||
264 | id value = [spriteFrames_ objectForKey:key]; | ||
265 | if( [value retainCount] == 1 ) { | ||
266 | CCLOG(@"cocos2d: CCSpriteFrameCache: removing unused frame: %@", key); | ||
267 | [spriteFrames_ removeObjectForKey:key]; | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | -(void) removeSpriteFrameByName:(NSString*)name | ||
273 | { | ||
274 | // explicit nil handling | ||
275 | if( ! name ) | ||
276 | return; | ||
277 | |||
278 | // Is this an alias ? | ||
279 | NSString *key = [spriteFramesAliases_ objectForKey:name]; | ||
280 | |||
281 | if( key ) { | ||
282 | [spriteFrames_ removeObjectForKey:key]; | ||
283 | [spriteFramesAliases_ removeObjectForKey:name]; | ||
284 | |||
285 | } else | ||
286 | [spriteFrames_ removeObjectForKey:name]; | ||
287 | } | ||
288 | |||
289 | - (void) removeSpriteFramesFromFile:(NSString*) plist | ||
290 | { | ||
291 | NSString *path = [CCFileUtils fullPathFromRelativePath:plist]; | ||
292 | NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; | ||
293 | |||
294 | [self removeSpriteFramesFromDictionary:dict]; | ||
295 | } | ||
296 | |||
297 | - (void) removeSpriteFramesFromDictionary:(NSDictionary*) dictionary | ||
298 | { | ||
299 | NSDictionary *framesDict = [dictionary objectForKey:@"frames"]; | ||
300 | NSMutableArray *keysToRemove=[NSMutableArray array]; | ||
301 | |||
302 | for(NSString *frameDictKey in framesDict) | ||
303 | { | ||
304 | if ([spriteFrames_ objectForKey:frameDictKey]!=nil) | ||
305 | [keysToRemove addObject:frameDictKey]; | ||
306 | } | ||
307 | [spriteFrames_ removeObjectsForKeys:keysToRemove]; | ||
308 | } | ||
309 | |||
310 | - (void) removeSpriteFramesFromTexture:(CCTexture2D*) texture | ||
311 | { | ||
312 | NSMutableArray *keysToRemove=[NSMutableArray array]; | ||
313 | |||
314 | for (NSString *spriteFrameKey in spriteFrames_) | ||
315 | { | ||
316 | if ([[spriteFrames_ valueForKey:spriteFrameKey] texture] == texture) | ||
317 | [keysToRemove addObject:spriteFrameKey]; | ||
318 | |||
319 | } | ||
320 | [spriteFrames_ removeObjectsForKeys:keysToRemove]; | ||
321 | } | ||
322 | |||
323 | #pragma mark CCSpriteFrameCache - getting | ||
324 | |||
325 | -(CCSpriteFrame*) spriteFrameByName:(NSString*)name | ||
326 | { | ||
327 | CCSpriteFrame *frame = [spriteFrames_ objectForKey:name]; | ||
328 | if( ! frame ) { | ||
329 | // try alias dictionary | ||
330 | NSString *key = [spriteFramesAliases_ objectForKey:name]; | ||
331 | frame = [spriteFrames_ objectForKey:key]; | ||
332 | |||
333 | if( ! frame ) | ||
334 | CCLOG(@"cocos2d: CCSpriteFrameCache: Frame '%@' not found", name); | ||
335 | } | ||
336 | |||
337 | return frame; | ||
338 | } | ||
339 | |||
340 | #pragma mark CCSpriteFrameCache - sprite creation | ||
341 | |||
342 | -(CCSprite*) createSpriteWithFrameName:(NSString*)name | ||
343 | { | ||
344 | CCSpriteFrame *frame = [spriteFrames_ objectForKey:name]; | ||
345 | return [CCSprite spriteWithSpriteFrame:frame]; | ||
346 | } | ||
347 | @end | ||
diff --git a/libs/cocos2d/CCTMXLayer.h b/libs/cocos2d/CCTMXLayer.h new file mode 100755 index 0000000..477a380 --- /dev/null +++ b/libs/cocos2d/CCTMXLayer.h | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009-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 | * TMX Tiled Map support: | ||
27 | * http://www.mapeditor.org | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | |||
32 | #import "CCAtlasNode.h" | ||
33 | #import "CCSpriteBatchNode.h" | ||
34 | |||
35 | |||
36 | @class CCTMXMapInfo; | ||
37 | @class CCTMXLayerInfo; | ||
38 | @class CCTMXTilesetInfo; | ||
39 | |||
40 | /** CCTMXLayer represents the TMX layer. | ||
41 | |||
42 | It is a subclass of CCSpriteBatchNode. By default the tiles are rendered using a CCTextureAtlas. | ||
43 | If you mofify a tile on runtime, then, that tile will become a CCSprite, otherwise no CCSprite objects are created. | ||
44 | The benefits of using CCSprite objects as tiles are: | ||
45 | - tiles (CCSprite) can be rotated/scaled/moved with a nice API | ||
46 | |||
47 | If the layer contains a property named "cc_vertexz" with an integer (in can be positive or negative), | ||
48 | then all the tiles belonging to the layer will use that value as their OpenGL vertex Z for depth. | ||
49 | |||
50 | On the other hand, if the "cc_vertexz" property has the "automatic" value, then the tiles will use an automatic vertex Z value. | ||
51 | Also before drawing the tiles, GL_ALPHA_TEST will be enabled, and disabled after drawing them. The used alpha func will be: | ||
52 | |||
53 | glAlphaFunc( GL_GREATER, value ) | ||
54 | |||
55 | "value" by default is 0, but you can change it from Tiled by adding the "cc_alpha_func" property to the layer. | ||
56 | The value 0 should work for most cases, but if you have tiles that are semi-transparent, then you might want to use a differnt | ||
57 | value, like 0.5. | ||
58 | |||
59 | For further information, please see the programming guide: | ||
60 | |||
61 | http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:tiled_maps | ||
62 | |||
63 | @since v0.8.1 | ||
64 | */ | ||
65 | @interface CCTMXLayer : CCSpriteBatchNode | ||
66 | { | ||
67 | CCTMXTilesetInfo *tileset_; | ||
68 | NSString *layerName_; | ||
69 | CGSize layerSize_; | ||
70 | CGSize mapTileSize_; | ||
71 | uint32_t *tiles_; // GID are 32 bit | ||
72 | NSUInteger layerOrientation_; | ||
73 | NSMutableArray *properties_; | ||
74 | |||
75 | unsigned char opacity_; // TMX Layer supports opacity | ||
76 | |||
77 | NSUInteger minGID_; | ||
78 | NSUInteger maxGID_; | ||
79 | |||
80 | // Only used when vertexZ is used | ||
81 | NSInteger vertexZvalue_; | ||
82 | BOOL useAutomaticVertexZ_; | ||
83 | float alphaFuncValue_; | ||
84 | |||
85 | // used for optimization | ||
86 | CCSprite *reusedTile_; | ||
87 | ccCArray *atlasIndexArray_; | ||
88 | } | ||
89 | /** name of the layer */ | ||
90 | @property (nonatomic,readwrite,retain) NSString *layerName; | ||
91 | /** size of the layer in tiles */ | ||
92 | @property (nonatomic,readwrite) CGSize layerSize; | ||
93 | /** size of the map's tile (could be differnt from the tile's size) */ | ||
94 | @property (nonatomic,readwrite) CGSize mapTileSize; | ||
95 | /** pointer to the map of tiles */ | ||
96 | @property (nonatomic,readwrite) uint32_t *tiles; | ||
97 | /** Tilset information for the layer */ | ||
98 | @property (nonatomic,readwrite,retain) CCTMXTilesetInfo *tileset; | ||
99 | /** Layer orientation, which is the same as the map orientation */ | ||
100 | @property (nonatomic,readwrite) NSUInteger layerOrientation; | ||
101 | /** properties from the layer. They can be added using Tiled */ | ||
102 | @property (nonatomic,readwrite,retain) NSMutableArray *properties; | ||
103 | |||
104 | /** creates a CCTMXLayer with an tileset info, a layer info and a map info */ | ||
105 | +(id) layerWithTilesetInfo:(CCTMXTilesetInfo*)tilesetInfo layerInfo:(CCTMXLayerInfo*)layerInfo mapInfo:(CCTMXMapInfo*)mapInfo; | ||
106 | /** initializes a CCTMXLayer with a tileset info, a layer info and a map info */ | ||
107 | -(id) initWithTilesetInfo:(CCTMXTilesetInfo*)tilesetInfo layerInfo:(CCTMXLayerInfo*)layerInfo mapInfo:(CCTMXMapInfo*)mapInfo; | ||
108 | |||
109 | /** dealloc the map that contains the tile position from memory. | ||
110 | Unless you want to know at runtime the tiles positions, you can safely call this method. | ||
111 | If you are going to call [layer tileGIDAt:] then, don't release the map | ||
112 | */ | ||
113 | -(void) releaseMap; | ||
114 | |||
115 | /** returns the tile (CCSprite) at a given a tile coordinate. | ||
116 | The returned CCSprite will be already added to the CCTMXLayer. Don't add it again. | ||
117 | The CCSprite can be treated like any other CCSprite: rotated, scaled, translated, opacity, color, etc. | ||
118 | You can remove either by calling: | ||
119 | - [layer removeChild:sprite cleanup:cleanup]; | ||
120 | - or [layer removeTileAt:ccp(x,y)]; | ||
121 | */ | ||
122 | -(CCSprite*) tileAt:(CGPoint)tileCoordinate; | ||
123 | |||
124 | /** returns the tile gid at a given tile coordinate. | ||
125 | if it returns 0, it means that the tile is empty. | ||
126 | This method requires the the tile map has not been previously released (eg. don't call [layer releaseMap]) | ||
127 | */ | ||
128 | -(uint32_t) tileGIDAt:(CGPoint)tileCoordinate; | ||
129 | |||
130 | /** sets the tile gid (gid = tile global id) at a given tile coordinate. | ||
131 | The Tile GID can be obtained by using the method "tileGIDAt" or by using the TMX editor -> Tileset Mgr +1. | ||
132 | If a tile is already placed at that position, then it will be removed. | ||
133 | */ | ||
134 | -(void) setTileGID:(uint32_t)gid at:(CGPoint)tileCoordinate; | ||
135 | |||
136 | /** removes a tile at given tile coordinate */ | ||
137 | -(void) removeTileAt:(CGPoint)tileCoordinate; | ||
138 | |||
139 | /** returns the position in pixels of a given tile coordinate */ | ||
140 | -(CGPoint) positionAt:(CGPoint)tileCoordinate; | ||
141 | |||
142 | /** return the value for the specific property name */ | ||
143 | -(id) propertyNamed:(NSString *)propertyName; | ||
144 | |||
145 | /** Creates the tiles */ | ||
146 | -(void) setupTiles; | ||
147 | |||
148 | /** CCTMXLayer doesn't support adding a CCSprite manually. | ||
149 | @warning addchild:z:tag: is not supported on CCTMXLayer. Instead of setTileGID:at:/tileAt: | ||
150 | */ | ||
151 | -(void) addChild: (CCNode*)node z:(NSInteger)z tag:(NSInteger)tag; | ||
152 | @end | ||
diff --git a/libs/cocos2d/CCTMXLayer.m b/libs/cocos2d/CCTMXLayer.m new file mode 100755 index 0000000..bb2ba60 --- /dev/null +++ b/libs/cocos2d/CCTMXLayer.m | |||
@@ -0,0 +1,670 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009-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 | * TMX Tiled Map support: | ||
27 | * http://www.mapeditor.org | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #import "CCTMXLayer.h" | ||
32 | #import "CCTMXTiledMap.h" | ||
33 | #import "CCTMXXMLParser.h" | ||
34 | #import "CCSprite.h" | ||
35 | #import "CCSpriteBatchNode.h" | ||
36 | #import "CCTextureCache.h" | ||
37 | #import "Support/CGPointExtension.h" | ||
38 | |||
39 | #pragma mark - | ||
40 | #pragma mark CCSpriteBatchNode Extension | ||
41 | |||
42 | @interface CCSpriteBatchNode (TMXTiledMapExtensions) | ||
43 | -(id) addSpriteWithoutQuad:(CCSprite*)child z:(NSUInteger)z tag:(NSInteger)aTag; | ||
44 | -(void) addQuadFromSprite:(CCSprite*)sprite quadIndex:(NSUInteger)index; | ||
45 | @end | ||
46 | |||
47 | /* IMPORTANT XXX IMPORTNAT: | ||
48 | * These 2 methods can't be part of CCTMXLayer since they call [super add...], and CCSpriteBatchNode#add SHALL not be called | ||
49 | */ | ||
50 | @implementation CCSpriteBatchNode (TMXTiledMapExtension) | ||
51 | |||
52 | /* Adds a quad into the texture atlas but it won't be added into the children array. | ||
53 | This method should be called only when you are dealing with very big AtlasSrite and when most of the CCSprite won't be updated. | ||
54 | For example: a tile map (CCTMXMap) or a label with lots of characgers (CCLabelBMFont) | ||
55 | */ | ||
56 | -(void) addQuadFromSprite:(CCSprite*)sprite quadIndex:(NSUInteger)index | ||
57 | { | ||
58 | NSAssert( sprite != nil, @"Argument must be non-nil"); | ||
59 | NSAssert( [sprite isKindOfClass:[CCSprite class]], @"CCSpriteBatchNode only supports CCSprites as children"); | ||
60 | |||
61 | |||
62 | while(index >= textureAtlas_.capacity || textureAtlas_.capacity == textureAtlas_.totalQuads ) | ||
63 | [self increaseAtlasCapacity]; | ||
64 | |||
65 | // | ||
66 | // update the quad directly. Don't add the sprite to the scene graph | ||
67 | // | ||
68 | |||
69 | [sprite useBatchNode:self]; | ||
70 | [sprite setAtlasIndex:index]; | ||
71 | |||
72 | ccV3F_C4B_T2F_Quad quad = [sprite quad]; | ||
73 | [textureAtlas_ insertQuad:&quad atIndex:index]; | ||
74 | |||
75 | // XXX: updateTransform will update the textureAtlas too using updateQuad. | ||
76 | // XXX: so, it should be AFTER the insertQuad | ||
77 | [sprite setDirty:YES]; | ||
78 | [sprite updateTransform]; | ||
79 | } | ||
80 | |||
81 | /* This is the opposite of "addQuadFromSprite. | ||
82 | It add the sprite to the children and descendants array, but it doesn't update add it to the texture atlas | ||
83 | */ | ||
84 | -(id) addSpriteWithoutQuad:(CCSprite*)child z:(NSUInteger)z tag:(NSInteger)aTag | ||
85 | { | ||
86 | NSAssert( child != nil, @"Argument must be non-nil"); | ||
87 | NSAssert( [child isKindOfClass:[CCSprite class]], @"CCSpriteBatchNode only supports CCSprites as children"); | ||
88 | |||
89 | // quad index is Z | ||
90 | [child setAtlasIndex:z]; | ||
91 | |||
92 | // XXX: optimize with a binary search | ||
93 | int i=0; | ||
94 | for( CCSprite *c in descendants_ ) { | ||
95 | if( c.atlasIndex >= z ) | ||
96 | break; | ||
97 | i++; | ||
98 | } | ||
99 | [descendants_ insertObject:child atIndex:i]; | ||
100 | |||
101 | |||
102 | // IMPORTANT: Call super, and not self. Avoid adding it to the texture atlas array | ||
103 | [super addChild:child z:z tag:aTag]; | ||
104 | return self; | ||
105 | } | ||
106 | @end | ||
107 | |||
108 | |||
109 | #pragma mark - | ||
110 | #pragma mark CCTMXLayer | ||
111 | |||
112 | int compareInts (const void * a, const void * b); | ||
113 | |||
114 | |||
115 | @interface CCTMXLayer () | ||
116 | -(CGPoint) positionForIsoAt:(CGPoint)pos; | ||
117 | -(CGPoint) positionForOrthoAt:(CGPoint)pos; | ||
118 | -(CGPoint) positionForHexAt:(CGPoint)pos; | ||
119 | |||
120 | -(CGPoint) calculateLayerOffset:(CGPoint)offset; | ||
121 | |||
122 | /* optimization methos */ | ||
123 | -(CCSprite*) appendTileForGID:(uint32_t)gid at:(CGPoint)pos; | ||
124 | -(CCSprite*) insertTileForGID:(uint32_t)gid at:(CGPoint)pos; | ||
125 | -(CCSprite*) updateTileForGID:(uint32_t)gid at:(CGPoint)pos; | ||
126 | |||
127 | /* The layer recognizes some special properties, like cc_vertez */ | ||
128 | -(void) parseInternalProperties; | ||
129 | |||
130 | -(NSInteger) vertexZForPos:(CGPoint)pos; | ||
131 | |||
132 | // index | ||
133 | -(NSUInteger) atlasIndexForExistantZ:(NSUInteger)z; | ||
134 | -(NSUInteger) atlasIndexForNewZ:(NSUInteger)z; | ||
135 | @end | ||
136 | |||
137 | @implementation CCTMXLayer | ||
138 | @synthesize layerSize = layerSize_, layerName = layerName_, tiles = tiles_; | ||
139 | @synthesize tileset = tileset_; | ||
140 | @synthesize layerOrientation = layerOrientation_; | ||
141 | @synthesize mapTileSize = mapTileSize_; | ||
142 | @synthesize properties = properties_; | ||
143 | |||
144 | #pragma mark CCTMXLayer - init & alloc & dealloc | ||
145 | |||
146 | +(id) layerWithTilesetInfo:(CCTMXTilesetInfo*)tilesetInfo layerInfo:(CCTMXLayerInfo*)layerInfo mapInfo:(CCTMXMapInfo*)mapInfo | ||
147 | { | ||
148 | return [[[self alloc] initWithTilesetInfo:tilesetInfo layerInfo:layerInfo mapInfo:mapInfo] autorelease]; | ||
149 | } | ||
150 | |||
151 | -(id) initWithTilesetInfo:(CCTMXTilesetInfo*)tilesetInfo layerInfo:(CCTMXLayerInfo*)layerInfo mapInfo:(CCTMXMapInfo*)mapInfo | ||
152 | { | ||
153 | // XXX: is 35% a good estimate ? | ||
154 | CGSize size = layerInfo.layerSize; | ||
155 | float totalNumberOfTiles = size.width * size.height; | ||
156 | float capacity = totalNumberOfTiles * 0.35f + 1; // 35 percent is occupied ? | ||
157 | |||
158 | CCTexture2D *tex = nil; | ||
159 | if( tilesetInfo ) | ||
160 | tex = [[CCTextureCache sharedTextureCache] addImage:tilesetInfo.sourceImage]; | ||
161 | |||
162 | if((self = [super initWithTexture:tex capacity:capacity])) { | ||
163 | |||
164 | // layerInfo | ||
165 | self.layerName = layerInfo.name; | ||
166 | layerSize_ = layerInfo.layerSize; | ||
167 | tiles_ = layerInfo.tiles; | ||
168 | minGID_ = layerInfo.minGID; | ||
169 | maxGID_ = layerInfo.maxGID; | ||
170 | opacity_ = layerInfo.opacity; | ||
171 | self.properties = [NSMutableDictionary dictionaryWithDictionary:layerInfo.properties]; | ||
172 | |||
173 | // tilesetInfo | ||
174 | self.tileset = tilesetInfo; | ||
175 | |||
176 | // mapInfo | ||
177 | mapTileSize_ = mapInfo.tileSize; | ||
178 | layerOrientation_ = mapInfo.orientation; | ||
179 | |||
180 | // offset (after layer orientation is set); | ||
181 | CGPoint offset = [self calculateLayerOffset:layerInfo.offset]; | ||
182 | [self setPositionInPixels:offset]; | ||
183 | |||
184 | atlasIndexArray_ = ccCArrayNew(totalNumberOfTiles); | ||
185 | |||
186 | [self setContentSizeInPixels: CGSizeMake( layerSize_.width * mapTileSize_.width, layerSize_.height * mapTileSize_.height )]; | ||
187 | |||
188 | useAutomaticVertexZ_= NO; | ||
189 | vertexZvalue_ = 0; | ||
190 | alphaFuncValue_ = 0; | ||
191 | |||
192 | } | ||
193 | return self; | ||
194 | } | ||
195 | |||
196 | - (void) dealloc | ||
197 | { | ||
198 | [layerName_ release]; | ||
199 | [tileset_ release]; | ||
200 | [reusedTile_ release]; | ||
201 | [properties_ release]; | ||
202 | |||
203 | if( atlasIndexArray_ ) { | ||
204 | ccCArrayFree(atlasIndexArray_); | ||
205 | atlasIndexArray_ = NULL; | ||
206 | } | ||
207 | |||
208 | if( tiles_ ) { | ||
209 | free(tiles_); | ||
210 | tiles_ = NULL; | ||
211 | } | ||
212 | |||
213 | [super dealloc]; | ||
214 | } | ||
215 | |||
216 | -(void) releaseMap | ||
217 | { | ||
218 | if( tiles_) { | ||
219 | free( tiles_); | ||
220 | tiles_ = NULL; | ||
221 | } | ||
222 | |||
223 | if( atlasIndexArray_ ) { | ||
224 | ccCArrayFree(atlasIndexArray_); | ||
225 | atlasIndexArray_ = NULL; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | #pragma mark CCTMXLayer - setup Tiles | ||
230 | |||
231 | -(void) setupTiles | ||
232 | { | ||
233 | // Optimization: quick hack that sets the image size on the tileset | ||
234 | tileset_.imageSize = [textureAtlas_.texture contentSizeInPixels]; | ||
235 | |||
236 | // By default all the tiles are aliased | ||
237 | // pros: | ||
238 | // - easier to render | ||
239 | // cons: | ||
240 | // - difficult to scale / rotate / etc. | ||
241 | [textureAtlas_.texture setAliasTexParameters]; | ||
242 | |||
243 | CFByteOrder o = CFByteOrderGetCurrent(); | ||
244 | |||
245 | // Parse cocos2d properties | ||
246 | [self parseInternalProperties]; | ||
247 | |||
248 | for( NSUInteger y=0; y < layerSize_.height; y++ ) { | ||
249 | for( NSUInteger x=0; x < layerSize_.width; x++ ) { | ||
250 | |||
251 | NSUInteger pos = x + layerSize_.width * y; | ||
252 | uint32_t gid = tiles_[ pos ]; | ||
253 | |||
254 | // gid are stored in little endian. | ||
255 | // if host is big endian, then swap | ||
256 | if( o == CFByteOrderBigEndian ) | ||
257 | gid = CFSwapInt32( gid ); | ||
258 | |||
259 | // XXX: gid == 0 --> empty tile | ||
260 | if( gid != 0 ) { | ||
261 | [self appendTileForGID:gid at:ccp(x,y)]; | ||
262 | |||
263 | // Optimization: update min and max GID rendered by the layer | ||
264 | minGID_ = MIN(gid, minGID_); | ||
265 | maxGID_ = MAX(gid, maxGID_); | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | |||
270 | NSAssert( maxGID_ >= tileset_.firstGid && | ||
271 | minGID_ >= tileset_.firstGid, @"TMX: Only 1 tilset per layer is supported"); | ||
272 | } | ||
273 | |||
274 | #pragma mark CCTMXLayer - Properties | ||
275 | |||
276 | -(id) propertyNamed:(NSString *)propertyName | ||
277 | { | ||
278 | return [properties_ valueForKey:propertyName]; | ||
279 | } | ||
280 | |||
281 | -(void) parseInternalProperties | ||
282 | { | ||
283 | // if cc_vertex=automatic, then tiles will be rendered using vertexz | ||
284 | |||
285 | NSString *vertexz = [self propertyNamed:@"cc_vertexz"]; | ||
286 | if( vertexz ) { | ||
287 | if( [vertexz isEqualToString:@"automatic"] ) | ||
288 | useAutomaticVertexZ_ = YES; | ||
289 | else | ||
290 | vertexZvalue_ = [vertexz intValue]; | ||
291 | } | ||
292 | |||
293 | NSString *alphaFuncVal = [self propertyNamed:@"cc_alpha_func"]; | ||
294 | alphaFuncValue_ = [alphaFuncVal floatValue]; | ||
295 | } | ||
296 | |||
297 | #pragma mark CCTMXLayer - obtaining tiles/gids | ||
298 | |||
299 | -(CCSprite*) tileAt:(CGPoint)pos | ||
300 | { | ||
301 | NSAssert( pos.x < layerSize_.width && pos.y < layerSize_.height && pos.x >=0 && pos.y >=0, @"TMXLayer: invalid position"); | ||
302 | NSAssert( tiles_ && atlasIndexArray_, @"TMXLayer: the tiles map has been released"); | ||
303 | |||
304 | CCSprite *tile = nil; | ||
305 | uint32_t gid = [self tileGIDAt:pos]; | ||
306 | |||
307 | // if GID == 0, then no tile is present | ||
308 | if( gid ) { | ||
309 | int z = pos.x + pos.y * layerSize_.width; | ||
310 | tile = (CCSprite*) [self getChildByTag:z]; | ||
311 | |||
312 | // tile not created yet. create it | ||
313 | if( ! tile ) { | ||
314 | CGRect rect = [tileset_ rectForGID:gid]; | ||
315 | tile = [[CCSprite alloc] initWithBatchNode:self rectInPixels:rect]; | ||
316 | [tile setPositionInPixels: [self positionAt:pos]]; | ||
317 | [tile setVertexZ: [self vertexZForPos:pos]]; | ||
318 | tile.anchorPoint = CGPointZero; | ||
319 | [tile setOpacity:opacity_]; | ||
320 | |||
321 | NSUInteger indexForZ = [self atlasIndexForExistantZ:z]; | ||
322 | [self addSpriteWithoutQuad:tile z:indexForZ tag:z]; | ||
323 | [tile release]; | ||
324 | } | ||
325 | } | ||
326 | return tile; | ||
327 | } | ||
328 | |||
329 | -(uint32_t) tileGIDAt:(CGPoint)pos | ||
330 | { | ||
331 | NSAssert( pos.x < layerSize_.width && pos.y < layerSize_.height && pos.x >=0 && pos.y >=0, @"TMXLayer: invalid position"); | ||
332 | NSAssert( tiles_ && atlasIndexArray_, @"TMXLayer: the tiles map has been released"); | ||
333 | |||
334 | NSInteger idx = pos.x + pos.y * layerSize_.width; | ||
335 | return tiles_[ idx ]; | ||
336 | } | ||
337 | |||
338 | #pragma mark CCTMXLayer - adding helper methods | ||
339 | |||
340 | -(CCSprite*) insertTileForGID:(uint32_t)gid at:(CGPoint)pos | ||
341 | { | ||
342 | CGRect rect = [tileset_ rectForGID:gid]; | ||
343 | |||
344 | NSInteger z = pos.x + pos.y * layerSize_.width; | ||
345 | |||
346 | if( ! reusedTile_ ) | ||
347 | reusedTile_ = [[CCSprite alloc] initWithBatchNode:self rectInPixels:rect]; | ||
348 | else | ||
349 | [reusedTile_ initWithBatchNode:self rectInPixels:rect]; | ||
350 | |||
351 | [reusedTile_ setPositionInPixels: [self positionAt:pos]]; | ||
352 | [reusedTile_ setVertexZ: [self vertexZForPos:pos]]; | ||
353 | reusedTile_.anchorPoint = CGPointZero; | ||
354 | [reusedTile_ setOpacity:opacity_]; | ||
355 | |||
356 | // get atlas index | ||
357 | NSUInteger indexForZ = [self atlasIndexForNewZ:z]; | ||
358 | |||
359 | // Optimization: add the quad without adding a child | ||
360 | [self addQuadFromSprite:reusedTile_ quadIndex:indexForZ]; | ||
361 | |||
362 | // insert it into the local atlasindex array | ||
363 | ccCArrayInsertValueAtIndex(atlasIndexArray_, (void*)z, indexForZ); | ||
364 | |||
365 | // update possible children | ||
366 | CCSprite *sprite; | ||
367 | CCARRAY_FOREACH(children_, sprite) { | ||
368 | NSUInteger ai = [sprite atlasIndex]; | ||
369 | if( ai >= indexForZ) | ||
370 | [sprite setAtlasIndex: ai+1]; | ||
371 | } | ||
372 | |||
373 | tiles_[z] = gid; | ||
374 | |||
375 | return reusedTile_; | ||
376 | } | ||
377 | |||
378 | -(CCSprite*) updateTileForGID:(uint32_t)gid at:(CGPoint)pos | ||
379 | { | ||
380 | CGRect rect = [tileset_ rectForGID:gid]; | ||
381 | |||
382 | int z = pos.x + pos.y * layerSize_.width; | ||
383 | |||
384 | if( ! reusedTile_ ) | ||
385 | reusedTile_ = [[CCSprite alloc] initWithBatchNode:self rectInPixels:rect]; | ||
386 | else | ||
387 | [reusedTile_ initWithBatchNode:self rectInPixels:rect]; | ||
388 | |||
389 | [reusedTile_ setPositionInPixels: [self positionAt:pos]]; | ||
390 | [reusedTile_ setVertexZ: [self vertexZForPos:pos]]; | ||
391 | reusedTile_.anchorPoint = CGPointZero; | ||
392 | [reusedTile_ setOpacity:opacity_]; | ||
393 | |||
394 | // get atlas index | ||
395 | NSUInteger indexForZ = [self atlasIndexForExistantZ:z]; | ||
396 | |||
397 | [reusedTile_ setAtlasIndex:indexForZ]; | ||
398 | [reusedTile_ setDirty:YES]; | ||
399 | [reusedTile_ updateTransform]; | ||
400 | tiles_[z] = gid; | ||
401 | |||
402 | return reusedTile_; | ||
403 | } | ||
404 | |||
405 | |||
406 | // used only when parsing the map. useless after the map was parsed | ||
407 | // since lot's of assumptions are no longer true | ||
408 | -(CCSprite*) appendTileForGID:(uint32_t)gid at:(CGPoint)pos | ||
409 | { | ||
410 | CGRect rect = [tileset_ rectForGID:gid]; | ||
411 | |||
412 | NSInteger z = pos.x + pos.y * layerSize_.width; | ||
413 | |||
414 | if( ! reusedTile_ ) | ||
415 | reusedTile_ = [[CCSprite alloc] initWithBatchNode:self rectInPixels:rect]; | ||
416 | else | ||
417 | [reusedTile_ initWithBatchNode:self rectInPixels:rect]; | ||
418 | |||
419 | [reusedTile_ setPositionInPixels: [self positionAt:pos]]; | ||
420 | [reusedTile_ setVertexZ: [self vertexZForPos:pos]]; | ||
421 | reusedTile_.anchorPoint = CGPointZero; | ||
422 | [reusedTile_ setOpacity:opacity_]; | ||
423 | |||
424 | // optimization: | ||
425 | // The difference between appendTileForGID and insertTileforGID is that append is faster, since | ||
426 | // it appends the tile at the end of the texture atlas | ||
427 | NSUInteger indexForZ = atlasIndexArray_->num; | ||
428 | |||
429 | |||
430 | // don't add it using the "standard" way. | ||
431 | [self addQuadFromSprite:reusedTile_ quadIndex:indexForZ]; | ||
432 | |||
433 | |||
434 | // append should be after addQuadFromSprite since it modifies the quantity values | ||
435 | ccCArrayInsertValueAtIndex(atlasIndexArray_, (void*)z, indexForZ); | ||
436 | |||
437 | return reusedTile_; | ||
438 | } | ||
439 | |||
440 | #pragma mark CCTMXLayer - atlasIndex and Z | ||
441 | |||
442 | int compareInts (const void * a, const void * b) | ||
443 | { | ||
444 | return ( *(int*)a - *(int*)b ); | ||
445 | } | ||
446 | |||
447 | -(NSUInteger) atlasIndexForExistantZ:(NSUInteger)z | ||
448 | { | ||
449 | NSInteger key = z; | ||
450 | NSInteger *item = bsearch((void*)&key, (void*)&atlasIndexArray_->arr[0], atlasIndexArray_->num, sizeof(void*), compareInts); | ||
451 | |||
452 | NSAssert( item, @"TMX atlas index not found. Shall not happen"); | ||
453 | |||
454 | NSUInteger index = ((NSInteger)item - (NSInteger)atlasIndexArray_->arr) / sizeof(void*); | ||
455 | return index; | ||
456 | } | ||
457 | |||
458 | -(NSUInteger)atlasIndexForNewZ:(NSUInteger)z | ||
459 | { | ||
460 | // XXX: This can be improved with a sort of binary search | ||
461 | NSUInteger i = 0; | ||
462 | for(i = 0; i< atlasIndexArray_->num; i++) { | ||
463 | NSUInteger val = (NSUInteger) atlasIndexArray_->arr[i]; | ||
464 | if( z < val ) | ||
465 | break; | ||
466 | } | ||
467 | return i; | ||
468 | } | ||
469 | |||
470 | #pragma mark CCTMXLayer - adding / remove tiles | ||
471 | |||
472 | -(void) setTileGID:(uint32_t)gid at:(CGPoint)pos | ||
473 | { | ||
474 | NSAssert( pos.x < layerSize_.width && pos.y < layerSize_.height && pos.x >=0 && pos.y >=0, @"TMXLayer: invalid position"); | ||
475 | NSAssert( tiles_ && atlasIndexArray_, @"TMXLayer: the tiles map has been released"); | ||
476 | NSAssert( gid == 0 || gid >= tileset_.firstGid, @"TMXLayer: invalid gid" ); | ||
477 | |||
478 | uint32_t currentGID = [self tileGIDAt:pos]; | ||
479 | |||
480 | if( currentGID != gid ) { | ||
481 | |||
482 | // setting gid=0 is equal to remove the tile | ||
483 | if( gid == 0 ) | ||
484 | [self removeTileAt:pos]; | ||
485 | |||
486 | // empty tile. create a new one | ||
487 | else if( currentGID == 0 ) | ||
488 | [self insertTileForGID:gid at:pos]; | ||
489 | |||
490 | // modifying an existing tile with a non-empty tile | ||
491 | else { | ||
492 | |||
493 | NSUInteger z = pos.x + pos.y * layerSize_.width; | ||
494 | id sprite = [self getChildByTag:z]; | ||
495 | if( sprite ) { | ||
496 | CGRect rect = [tileset_ rectForGID:gid]; | ||
497 | [sprite setTextureRectInPixels:rect rotated:NO untrimmedSize:rect.size]; | ||
498 | tiles_[z] = gid; | ||
499 | } else | ||
500 | [self updateTileForGID:gid at:pos]; | ||
501 | } | ||
502 | } | ||
503 | } | ||
504 | |||
505 | -(void) addChild: (CCNode*)node z:(NSInteger)z tag:(NSInteger)tag | ||
506 | { | ||
507 | NSAssert(NO, @"addChild: is not supported on CCTMXLayer. Instead use setTileGID:at:/tileAt:"); | ||
508 | } | ||
509 | |||
510 | -(void) removeChild:(CCSprite*)sprite cleanup:(BOOL)cleanup | ||
511 | { | ||
512 | // allows removing nil objects | ||
513 | if( ! sprite ) | ||
514 | return; | ||
515 | |||
516 | NSAssert( [children_ containsObject:sprite], @"Tile does not belong to TMXLayer"); | ||
517 | |||
518 | NSUInteger atlasIndex = [sprite atlasIndex]; | ||
519 | NSUInteger zz = (NSUInteger) atlasIndexArray_->arr[atlasIndex]; | ||
520 | tiles_[zz] = 0; | ||
521 | ccCArrayRemoveValueAtIndex(atlasIndexArray_, atlasIndex); | ||
522 | [super removeChild:sprite cleanup:cleanup]; | ||
523 | } | ||
524 | |||
525 | -(void) removeTileAt:(CGPoint)pos | ||
526 | { | ||
527 | NSAssert( pos.x < layerSize_.width && pos.y < layerSize_.height && pos.x >=0 && pos.y >=0, @"TMXLayer: invalid position"); | ||
528 | NSAssert( tiles_ && atlasIndexArray_, @"TMXLayer: the tiles map has been released"); | ||
529 | |||
530 | uint32_t gid = [self tileGIDAt:pos]; | ||
531 | |||
532 | if( gid ) { | ||
533 | |||
534 | NSUInteger z = pos.x + pos.y * layerSize_.width; | ||
535 | NSUInteger atlasIndex = [self atlasIndexForExistantZ:z]; | ||
536 | |||
537 | // remove tile from GID map | ||
538 | tiles_[z] = 0; | ||
539 | |||
540 | // remove tile from atlas position array | ||
541 | ccCArrayRemoveValueAtIndex(atlasIndexArray_, atlasIndex); | ||
542 | |||
543 | // remove it from sprites and/or texture atlas | ||
544 | id sprite = [self getChildByTag:z]; | ||
545 | if( sprite ) | ||
546 | [super removeChild:sprite cleanup:YES]; | ||
547 | else { | ||
548 | [textureAtlas_ removeQuadAtIndex:atlasIndex]; | ||
549 | |||
550 | // update possible children | ||
551 | CCARRAY_FOREACH(children_, sprite) { | ||
552 | NSUInteger ai = [sprite atlasIndex]; | ||
553 | if( ai >= atlasIndex) { | ||
554 | [sprite setAtlasIndex: ai-1]; | ||
555 | } | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | } | ||
560 | |||
561 | #pragma mark CCTMXLayer - obtaining positions, offset | ||
562 | |||
563 | -(CGPoint) calculateLayerOffset:(CGPoint)pos | ||
564 | { | ||
565 | CGPoint ret = CGPointZero; | ||
566 | switch( layerOrientation_ ) { | ||
567 | case CCTMXOrientationOrtho: | ||
568 | ret = ccp( pos.x * mapTileSize_.width, -pos.y *mapTileSize_.height); | ||
569 | break; | ||
570 | case CCTMXOrientationIso: | ||
571 | ret = ccp( (mapTileSize_.width /2) * (pos.x - pos.y), | ||
572 | (mapTileSize_.height /2 ) * (-pos.x - pos.y) ); | ||
573 | break; | ||
574 | case CCTMXOrientationHex: | ||
575 | NSAssert(CGPointEqualToPoint(pos, CGPointZero), @"offset for hexagonal map not implemented yet"); | ||
576 | break; | ||
577 | } | ||
578 | return ret; | ||
579 | } | ||
580 | |||
581 | -(CGPoint) positionAt:(CGPoint)pos | ||
582 | { | ||
583 | CGPoint ret = CGPointZero; | ||
584 | switch( layerOrientation_ ) { | ||
585 | case CCTMXOrientationOrtho: | ||
586 | ret = [self positionForOrthoAt:pos]; | ||
587 | break; | ||
588 | case CCTMXOrientationIso: | ||
589 | ret = [self positionForIsoAt:pos]; | ||
590 | break; | ||
591 | case CCTMXOrientationHex: | ||
592 | ret = [self positionForHexAt:pos]; | ||
593 | break; | ||
594 | } | ||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | -(CGPoint) positionForOrthoAt:(CGPoint)pos | ||
599 | { | ||
600 | CGPoint xy = { | ||
601 | pos.x * mapTileSize_.width, | ||
602 | (layerSize_.height - pos.y - 1) * mapTileSize_.height, | ||
603 | }; | ||
604 | return xy; | ||
605 | } | ||
606 | |||
607 | -(CGPoint) positionForIsoAt:(CGPoint)pos | ||
608 | { | ||
609 | CGPoint xy = { | ||
610 | mapTileSize_.width /2 * ( layerSize_.width + pos.x - pos.y - 1), | ||
611 | mapTileSize_.height /2 * (( layerSize_.height * 2 - pos.x - pos.y) - 2), | ||
612 | }; | ||
613 | return xy; | ||
614 | } | ||
615 | |||
616 | -(CGPoint) positionForHexAt:(CGPoint)pos | ||
617 | { | ||
618 | float diffY = 0; | ||
619 | if( (int)pos.x % 2 == 1 ) | ||
620 | diffY = -mapTileSize_.height/2 ; | ||
621 | |||
622 | CGPoint xy = { | ||
623 | pos.x * mapTileSize_.width*3/4, | ||
624 | (layerSize_.height - pos.y - 1) * mapTileSize_.height + diffY | ||
625 | }; | ||
626 | return xy; | ||
627 | } | ||
628 | |||
629 | -(NSInteger) vertexZForPos:(CGPoint)pos | ||
630 | { | ||
631 | NSInteger ret = 0; | ||
632 | NSUInteger maxVal = 0; | ||
633 | if( useAutomaticVertexZ_ ) { | ||
634 | switch( layerOrientation_ ) { | ||
635 | case CCTMXOrientationIso: | ||
636 | maxVal = layerSize_.width + layerSize_.height; | ||
637 | ret = -(maxVal - (pos.x + pos.y)); | ||
638 | break; | ||
639 | case CCTMXOrientationOrtho: | ||
640 | ret = -(layerSize_.height-pos.y); | ||
641 | break; | ||
642 | case CCTMXOrientationHex: | ||
643 | NSAssert(NO,@"TMX Hexa zOrder not supported"); | ||
644 | break; | ||
645 | default: | ||
646 | NSAssert(NO,@"TMX invalid value"); | ||
647 | break; | ||
648 | } | ||
649 | } else | ||
650 | ret = vertexZvalue_; | ||
651 | |||
652 | return ret; | ||
653 | } | ||
654 | |||
655 | #pragma mark CCTMXLayer - draw | ||
656 | |||
657 | -(void) draw | ||
658 | { | ||
659 | if( useAutomaticVertexZ_ ) { | ||
660 | glEnable(GL_ALPHA_TEST); | ||
661 | glAlphaFunc(GL_GREATER, alphaFuncValue_); | ||
662 | } | ||
663 | |||
664 | [super draw]; | ||
665 | |||
666 | if( useAutomaticVertexZ_ ) | ||
667 | glDisable(GL_ALPHA_TEST); | ||
668 | } | ||
669 | @end | ||
670 | |||
diff --git a/libs/cocos2d/CCTMXObjectGroup.h b/libs/cocos2d/CCTMXObjectGroup.h new file mode 100755 index 0000000..02feadf --- /dev/null +++ b/libs/cocos2d/CCTMXObjectGroup.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Neophit | ||
5 | * | ||
6 | * Copyright (c) 2010 Ricardo Quesada | ||
7 | * Copyright (c) 2011 Zynga Inc. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | * | ||
27 | * | ||
28 | * TMX Tiled Map support: | ||
29 | * http://www.mapeditor.org | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #import "CCNode.h" | ||
34 | |||
35 | |||
36 | @class CCTMXObjectGroup; | ||
37 | |||
38 | |||
39 | /** CCTMXObjectGroup represents the TMX object group. | ||
40 | @since v0.99.0 | ||
41 | */ | ||
42 | @interface CCTMXObjectGroup : NSObject | ||
43 | { | ||
44 | NSString *groupName_; | ||
45 | CGPoint positionOffset_; | ||
46 | NSMutableArray *objects_; | ||
47 | NSMutableDictionary *properties_; | ||
48 | } | ||
49 | |||
50 | /** name of the group */ | ||
51 | @property (nonatomic,readwrite,retain) NSString *groupName; | ||
52 | /** offset position of child objects */ | ||
53 | @property (nonatomic,readwrite,assign) CGPoint positionOffset; | ||
54 | /** array of the objects */ | ||
55 | @property (nonatomic,readwrite,retain) NSMutableArray *objects; | ||
56 | /** list of properties stored in a dictionary */ | ||
57 | @property (nonatomic,readwrite,retain) NSMutableDictionary *properties; | ||
58 | |||
59 | /** return the value for the specific property name */ | ||
60 | -(id) propertyNamed:(NSString *)propertyName; | ||
61 | |||
62 | /** return the dictionary for the specific object name. | ||
63 | It will return the 1st object found on the array for the given name. | ||
64 | */ | ||
65 | -(NSMutableDictionary*) objectNamed:(NSString *)objectName; | ||
66 | |||
67 | @end | ||
diff --git a/libs/cocos2d/CCTMXObjectGroup.m b/libs/cocos2d/CCTMXObjectGroup.m new file mode 100755 index 0000000..648cda4 --- /dev/null +++ b/libs/cocos2d/CCTMXObjectGroup.m | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Neophit | ||
5 | * | ||
6 | * Copyright (c) 2010 Ricardo Quesada | ||
7 | * Copyright (c) 2011 Zynga Inc. | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | * | ||
27 | * | ||
28 | * TMX Tiled Map support: | ||
29 | * http://www.mapeditor.org | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #import "CCTMXObjectGroup.h" | ||
34 | #import "CCTMXXMLParser.h" | ||
35 | #import "ccMacros.h" | ||
36 | #import "Support/CGPointExtension.h" | ||
37 | |||
38 | |||
39 | #pragma mark - | ||
40 | #pragma mark TMXObjectGroup | ||
41 | |||
42 | @implementation CCTMXObjectGroup | ||
43 | |||
44 | @synthesize groupName = groupName_; | ||
45 | @synthesize objects = objects_; | ||
46 | @synthesize positionOffset = positionOffset_; | ||
47 | @synthesize properties = properties_; | ||
48 | |||
49 | -(id) init | ||
50 | { | ||
51 | if (( self=[super init] )) { | ||
52 | self.groupName = nil; | ||
53 | self.positionOffset = CGPointZero; | ||
54 | self.objects = [NSMutableArray arrayWithCapacity:10]; | ||
55 | self.properties = [NSMutableDictionary dictionaryWithCapacity:5]; | ||
56 | } | ||
57 | return self; | ||
58 | } | ||
59 | |||
60 | -(void) dealloc | ||
61 | { | ||
62 | CCLOGINFO( @"cocos2d: deallocing %@", self ); | ||
63 | |||
64 | [groupName_ release]; | ||
65 | [objects_ release]; | ||
66 | [properties_ release]; | ||
67 | [super dealloc]; | ||
68 | } | ||
69 | |||
70 | -(NSMutableDictionary*) objectNamed:(NSString *)objectName | ||
71 | { | ||
72 | for( id object in objects_ ) { | ||
73 | if( [[object valueForKey:@"name"] isEqual:objectName] ) | ||
74 | return object; | ||
75 | } | ||
76 | |||
77 | // object not found | ||
78 | return nil; | ||
79 | } | ||
80 | |||
81 | -(id) propertyNamed:(NSString *)propertyName | ||
82 | { | ||
83 | return [properties_ valueForKey:propertyName]; | ||
84 | } | ||
85 | |||
86 | @end | ||
diff --git a/libs/cocos2d/CCTMXTiledMap.h b/libs/cocos2d/CCTMXTiledMap.h new file mode 100755 index 0000000..8f48da3 --- /dev/null +++ b/libs/cocos2d/CCTMXTiledMap.h | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009-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 | * TMX Tiled Map support: | ||
27 | * http://www.mapeditor.org | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #import "CCNode.h" | ||
32 | |||
33 | |||
34 | @class CCTMXLayer; | ||
35 | @class CCTMXObjectGroup; | ||
36 | |||
37 | /** Possible oritentations of the TMX map */ | ||
38 | enum | ||
39 | { | ||
40 | /** Orthogonal orientation */ | ||
41 | CCTMXOrientationOrtho, | ||
42 | |||
43 | /** Hexagonal orientation */ | ||
44 | CCTMXOrientationHex, | ||
45 | |||
46 | /** Isometric orientation */ | ||
47 | CCTMXOrientationIso, | ||
48 | }; | ||
49 | |||
50 | /** CCTMXTiledMap knows how to parse and render a TMX map. | ||
51 | |||
52 | It adds support for the TMX tiled map format used by http://www.mapeditor.org | ||
53 | It supports isometric, hexagonal and orthogonal tiles. | ||
54 | It also supports object groups, objects, and properties. | ||
55 | |||
56 | Features: | ||
57 | - Each tile will be treated as an CCSprite | ||
58 | - The sprites are created on demand. They will be created only when you call "[layer tileAt:]" | ||
59 | - Each tile can be rotated / moved / scaled / tinted / "opacitied", since each tile is a CCSprite | ||
60 | - Tiles can be added/removed in runtime | ||
61 | - The z-order of the tiles can be modified in runtime | ||
62 | - Each tile has an anchorPoint of (0,0) | ||
63 | - The anchorPoint of the TMXTileMap is (0,0) | ||
64 | - The TMX layers will be added as a child | ||
65 | - The TMX layers will be aliased by default | ||
66 | - The tileset image will be loaded using the CCTextureCache | ||
67 | - Each tile will have a unique tag | ||
68 | - Each tile will have a unique z value. top-left: z=1, bottom-right: z=max z | ||
69 | - Each object group will be treated as an NSMutableArray | ||
70 | - Object class which will contain all the properties in a dictionary | ||
71 | - Properties can be assigned to the Map, Layer, Object Group, and Object | ||
72 | |||
73 | Limitations: | ||
74 | - It only supports one tileset per layer. | ||
75 | - Embeded images are not supported | ||
76 | - It only supports the XML format (the JSON format is not supported) | ||
77 | |||
78 | Technical description: | ||
79 | Each layer is created using an CCTMXLayer (subclass of CCSpriteBatchNode). If you have 5 layers, then 5 CCTMXLayer will be created, | ||
80 | unless the layer visibility is off. In that case, the layer won't be created at all. | ||
81 | You can obtain the layers (CCTMXLayer objects) at runtime by: | ||
82 | - [map getChildByTag: tag_number]; // 0=1st layer, 1=2nd layer, 2=3rd layer, etc... | ||
83 | - [map layerNamed: name_of_the_layer]; | ||
84 | |||
85 | Each object group is created using a CCTMXObjectGroup which is a subclass of NSMutableArray. | ||
86 | You can obtain the object groups at runtime by: | ||
87 | - [map objectGroupNamed: name_of_the_object_group]; | ||
88 | |||
89 | Each object is a CCTMXObject. | ||
90 | |||
91 | Each property is stored as a key-value pair in an NSMutableDictionary. | ||
92 | You can obtain the properties at runtime by: | ||
93 | |||
94 | [map propertyNamed: name_of_the_property]; | ||
95 | [layer propertyNamed: name_of_the_property]; | ||
96 | [objectGroup propertyNamed: name_of_the_property]; | ||
97 | [object propertyNamed: name_of_the_property]; | ||
98 | |||
99 | @since v0.8.1 | ||
100 | */ | ||
101 | @interface CCTMXTiledMap : CCNode | ||
102 | { | ||
103 | CGSize mapSize_; | ||
104 | CGSize tileSize_; | ||
105 | int mapOrientation_; | ||
106 | NSMutableArray *objectGroups_; | ||
107 | NSMutableDictionary *properties_; | ||
108 | NSMutableDictionary *tileProperties_; | ||
109 | } | ||
110 | |||
111 | /** the map's size property measured in tiles */ | ||
112 | @property (nonatomic,readonly) CGSize mapSize; | ||
113 | /** the tiles's size property measured in pixels */ | ||
114 | @property (nonatomic,readonly) CGSize tileSize; | ||
115 | /** map orientation */ | ||
116 | @property (nonatomic,readonly) int mapOrientation; | ||
117 | /** object groups */ | ||
118 | @property (nonatomic,readwrite,retain) NSMutableArray *objectGroups; | ||
119 | /** properties */ | ||
120 | @property (nonatomic,readwrite,retain) NSMutableDictionary *properties; | ||
121 | |||
122 | /** creates a TMX Tiled Map with a TMX file.*/ | ||
123 | +(id) tiledMapWithTMXFile:(NSString*)tmxFile; | ||
124 | |||
125 | /** initializes a TMX Tiled Map with a TMX file */ | ||
126 | -(id) initWithTMXFile:(NSString*)tmxFile; | ||
127 | |||
128 | /** return the TMXLayer for the specific layer */ | ||
129 | -(CCTMXLayer*) layerNamed:(NSString *)layerName; | ||
130 | |||
131 | /** return the TMXObjectGroup for the secific group */ | ||
132 | -(CCTMXObjectGroup*) objectGroupNamed:(NSString *)groupName; | ||
133 | |||
134 | /** return the TMXObjectGroup for the secific group | ||
135 | @deprecated Use map#objectGroupNamed instead | ||
136 | */ | ||
137 | -(CCTMXObjectGroup*) groupNamed:(NSString *)groupName DEPRECATED_ATTRIBUTE; | ||
138 | |||
139 | /** return the value for the specific property name */ | ||
140 | -(id) propertyNamed:(NSString *)propertyName; | ||
141 | |||
142 | /** return properties dictionary for tile GID */ | ||
143 | -(NSDictionary*)propertiesForGID:(unsigned int)GID; | ||
144 | @end | ||
145 | |||
diff --git a/libs/cocos2d/CCTMXTiledMap.m b/libs/cocos2d/CCTMXTiledMap.m new file mode 100755 index 0000000..7f86c6a --- /dev/null +++ b/libs/cocos2d/CCTMXTiledMap.m | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009-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 | * TMX Tiled Map support: | ||
27 | * http://www.mapeditor.org | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #import "CCTMXTiledMap.h" | ||
32 | #import "CCTMXXMLParser.h" | ||
33 | #import "CCTMXLayer.h" | ||
34 | #import "CCTMXObjectGroup.h" | ||
35 | #import "CCSprite.h" | ||
36 | #import "CCTextureCache.h" | ||
37 | #import "Support/CGPointExtension.h" | ||
38 | |||
39 | |||
40 | #pragma mark - | ||
41 | #pragma mark CCTMXTiledMap | ||
42 | |||
43 | @interface CCTMXTiledMap (Private) | ||
44 | -(id) parseLayer:(CCTMXLayerInfo*)layer map:(CCTMXMapInfo*)mapInfo; | ||
45 | -(CCTMXTilesetInfo*) tilesetForLayer:(CCTMXLayerInfo*)layerInfo map:(CCTMXMapInfo*)mapInfo; | ||
46 | @end | ||
47 | |||
48 | @implementation CCTMXTiledMap | ||
49 | @synthesize mapSize = mapSize_; | ||
50 | @synthesize tileSize = tileSize_; | ||
51 | @synthesize mapOrientation = mapOrientation_; | ||
52 | @synthesize objectGroups = objectGroups_; | ||
53 | @synthesize properties = properties_; | ||
54 | |||
55 | +(id) tiledMapWithTMXFile:(NSString*)tmxFile | ||
56 | { | ||
57 | return [[[self alloc] initWithTMXFile:tmxFile] autorelease]; | ||
58 | } | ||
59 | |||
60 | -(id) initWithTMXFile:(NSString*)tmxFile | ||
61 | { | ||
62 | NSAssert(tmxFile != nil, @"TMXTiledMap: tmx file should not bi nil"); | ||
63 | |||
64 | if ((self=[super init])) { | ||
65 | |||
66 | [self setContentSize:CGSizeZero]; | ||
67 | |||
68 | CCTMXMapInfo *mapInfo = [CCTMXMapInfo formatWithTMXFile:tmxFile]; | ||
69 | |||
70 | NSAssert( [mapInfo.tilesets count] != 0, @"TMXTiledMap: Map not found. Please check the filename."); | ||
71 | |||
72 | mapSize_ = mapInfo.mapSize; | ||
73 | tileSize_ = mapInfo.tileSize; | ||
74 | mapOrientation_ = mapInfo.orientation; | ||
75 | objectGroups_ = [mapInfo.objectGroups retain]; | ||
76 | properties_ = [mapInfo.properties retain]; | ||
77 | tileProperties_ = [mapInfo.tileProperties retain]; | ||
78 | |||
79 | int idx=0; | ||
80 | |||
81 | for( CCTMXLayerInfo *layerInfo in mapInfo.layers ) { | ||
82 | |||
83 | if( layerInfo.visible ) { | ||
84 | CCNode *child = [self parseLayer:layerInfo map:mapInfo]; | ||
85 | [self addChild:child z:idx tag:idx]; | ||
86 | |||
87 | // update content size with the max size | ||
88 | CGSize childSize = [child contentSize]; | ||
89 | CGSize currentSize = [self contentSize]; | ||
90 | currentSize.width = MAX( currentSize.width, childSize.width ); | ||
91 | currentSize.height = MAX( currentSize.height, childSize.height ); | ||
92 | [self setContentSize:currentSize]; | ||
93 | |||
94 | idx++; | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | return self; | ||
100 | } | ||
101 | |||
102 | -(void) dealloc | ||
103 | { | ||
104 | [objectGroups_ release]; | ||
105 | [properties_ release]; | ||
106 | [tileProperties_ release]; | ||
107 | [super dealloc]; | ||
108 | } | ||
109 | |||
110 | // private | ||
111 | -(id) parseLayer:(CCTMXLayerInfo*)layerInfo map:(CCTMXMapInfo*)mapInfo | ||
112 | { | ||
113 | CCTMXTilesetInfo *tileset = [self tilesetForLayer:layerInfo map:mapInfo]; | ||
114 | CCTMXLayer *layer = [CCTMXLayer layerWithTilesetInfo:tileset layerInfo:layerInfo mapInfo:mapInfo]; | ||
115 | |||
116 | // tell the layerinfo to release the ownership of the tiles map. | ||
117 | layerInfo.ownTiles = NO; | ||
118 | |||
119 | [layer setupTiles]; | ||
120 | |||
121 | return layer; | ||
122 | } | ||
123 | |||
124 | -(CCTMXTilesetInfo*) tilesetForLayer:(CCTMXLayerInfo*)layerInfo map:(CCTMXMapInfo*)mapInfo | ||
125 | { | ||
126 | CFByteOrder o = CFByteOrderGetCurrent(); | ||
127 | |||
128 | CGSize size = layerInfo.layerSize; | ||
129 | |||
130 | id iter = [mapInfo.tilesets reverseObjectEnumerator]; | ||
131 | for( CCTMXTilesetInfo* tileset in iter) { | ||
132 | for( unsigned int y = 0; y < size.height; y++ ) { | ||
133 | for( unsigned int x = 0; x < size.width; x++ ) { | ||
134 | |||
135 | unsigned int pos = x + size.width * y; | ||
136 | unsigned int gid = layerInfo.tiles[ pos ]; | ||
137 | |||
138 | // gid are stored in little endian. | ||
139 | // if host is big endian, then swap | ||
140 | if( o == CFByteOrderBigEndian ) | ||
141 | gid = CFSwapInt32( gid ); | ||
142 | |||
143 | // XXX: gid == 0 --> empty tile | ||
144 | if( gid != 0 ) { | ||
145 | |||
146 | // Optimization: quick return | ||
147 | // if the layer is invalid (more than 1 tileset per layer) an assert will be thrown later | ||
148 | if( gid >= tileset.firstGid ) | ||
149 | return tileset; | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | // If all the tiles are 0, return empty tileset | ||
156 | CCLOG(@"cocos2d: Warning: TMX Layer '%@' has no tiles", layerInfo.name); | ||
157 | return nil; | ||
158 | } | ||
159 | |||
160 | |||
161 | // public | ||
162 | |||
163 | -(CCTMXLayer*) layerNamed:(NSString *)layerName | ||
164 | { | ||
165 | CCTMXLayer *layer; | ||
166 | CCARRAY_FOREACH(children_, layer) { | ||
167 | if([layer isKindOfClass:[CCTMXLayer class]]) | ||
168 | if([layer.layerName isEqual:layerName]) | ||
169 | return layer; | ||
170 | } | ||
171 | |||
172 | // layer not found | ||
173 | return nil; | ||
174 | } | ||
175 | |||
176 | -(CCTMXObjectGroup*) objectGroupNamed:(NSString *)groupName | ||
177 | { | ||
178 | for( CCTMXObjectGroup *objectGroup in objectGroups_ ) { | ||
179 | if( [objectGroup.groupName isEqual:groupName] ) | ||
180 | return objectGroup; | ||
181 | } | ||
182 | |||
183 | // objectGroup not found | ||
184 | return nil; | ||
185 | } | ||
186 | |||
187 | // XXX deprecated | ||
188 | -(CCTMXObjectGroup*) groupNamed:(NSString *)groupName | ||
189 | { | ||
190 | return [self objectGroupNamed:groupName]; | ||
191 | } | ||
192 | |||
193 | -(id) propertyNamed:(NSString *)propertyName | ||
194 | { | ||
195 | return [properties_ valueForKey:propertyName]; | ||
196 | } | ||
197 | -(NSDictionary*)propertiesForGID:(unsigned int)GID{ | ||
198 | return [tileProperties_ objectForKey:[NSNumber numberWithInt:GID]]; | ||
199 | } | ||
200 | @end | ||
201 | |||
diff --git a/libs/cocos2d/CCTMXXMLParser.h b/libs/cocos2d/CCTMXXMLParser.h new file mode 100755 index 0000000..18d7a8a --- /dev/null +++ b/libs/cocos2d/CCTMXXMLParser.h | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009-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 | * TMX Tiled Map support: | ||
27 | * http://www.mapeditor.org | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | /* | ||
32 | * Internal TMX parser | ||
33 | * | ||
34 | * IMPORTANT: These classed should not be documented using doxygen strings | ||
35 | * since the user should not use them. | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | |||
40 | #import <Availability.h> | ||
41 | #import <Foundation/Foundation.h> | ||
42 | |||
43 | enum { | ||
44 | TMXLayerAttribNone = 1 << 0, | ||
45 | TMXLayerAttribBase64 = 1 << 1, | ||
46 | TMXLayerAttribGzip = 1 << 2, | ||
47 | TMXLayerAttribZlib = 1 << 3, | ||
48 | }; | ||
49 | |||
50 | enum { | ||
51 | TMXPropertyNone, | ||
52 | TMXPropertyMap, | ||
53 | TMXPropertyLayer, | ||
54 | TMXPropertyObjectGroup, | ||
55 | TMXPropertyObject, | ||
56 | TMXPropertyTile | ||
57 | }; | ||
58 | |||
59 | /* CCTMXLayerInfo contains the information about the layers like: | ||
60 | - Layer name | ||
61 | - Layer size | ||
62 | - Layer opacity at creation time (it can be modified at runtime) | ||
63 | - Whether the layer is visible (if it's not visible, then the CocosNode won't be created) | ||
64 | |||
65 | This information is obtained from the TMX file. | ||
66 | */ | ||
67 | @interface CCTMXLayerInfo : NSObject | ||
68 | { | ||
69 | NSString *name_; | ||
70 | CGSize layerSize_; | ||
71 | unsigned int *tiles_; | ||
72 | BOOL visible_; | ||
73 | unsigned char opacity_; | ||
74 | BOOL ownTiles_; | ||
75 | unsigned int minGID_; | ||
76 | unsigned int maxGID_; | ||
77 | NSMutableDictionary *properties_; | ||
78 | CGPoint offset_; | ||
79 | } | ||
80 | |||
81 | @property (nonatomic,readwrite,retain) NSString *name; | ||
82 | @property (nonatomic,readwrite) CGSize layerSize; | ||
83 | @property (nonatomic,readwrite) unsigned int *tiles; | ||
84 | @property (nonatomic,readwrite) BOOL visible; | ||
85 | @property (nonatomic,readwrite) unsigned char opacity; | ||
86 | @property (nonatomic,readwrite) BOOL ownTiles; | ||
87 | @property (nonatomic,readwrite) unsigned int minGID; | ||
88 | @property (nonatomic,readwrite) unsigned int maxGID; | ||
89 | @property (nonatomic,readwrite,retain) NSMutableDictionary *properties; | ||
90 | @property (nonatomic,readwrite) CGPoint offset; | ||
91 | @end | ||
92 | |||
93 | /* CCTMXTilesetInfo contains the information about the tilesets like: | ||
94 | - Tileset name | ||
95 | - Tilset spacing | ||
96 | - Tileset margin | ||
97 | - size of the tiles | ||
98 | - Image used for the tiles | ||
99 | - Image size | ||
100 | |||
101 | This information is obtained from the TMX file. | ||
102 | */ | ||
103 | @interface CCTMXTilesetInfo : NSObject | ||
104 | { | ||
105 | NSString *name_; | ||
106 | unsigned int firstGid_; | ||
107 | CGSize tileSize_; | ||
108 | unsigned int spacing_; | ||
109 | unsigned int margin_; | ||
110 | |||
111 | // filename containing the tiles (should be spritesheet / texture atlas) | ||
112 | NSString *sourceImage_; | ||
113 | |||
114 | // size in pixels of the image | ||
115 | CGSize imageSize_; | ||
116 | } | ||
117 | @property (nonatomic,readwrite,retain) NSString *name; | ||
118 | @property (nonatomic,readwrite,assign) unsigned int firstGid; | ||
119 | @property (nonatomic,readwrite,assign) CGSize tileSize; | ||
120 | @property (nonatomic,readwrite,assign) unsigned int spacing; | ||
121 | @property (nonatomic,readwrite,assign) unsigned int margin; | ||
122 | @property (nonatomic,readwrite,retain) NSString *sourceImage; | ||
123 | @property (nonatomic,readwrite,assign) CGSize imageSize; | ||
124 | |||
125 | -(CGRect) rectForGID:(unsigned int)gid; | ||
126 | @end | ||
127 | |||
128 | /* CCTMXMapInfo contains the information about the map like: | ||
129 | - Map orientation (hexagonal, isometric or orthogonal) | ||
130 | - Tile size | ||
131 | - Map size | ||
132 | |||
133 | And it also contains: | ||
134 | - Layers (an array of TMXLayerInfo objects) | ||
135 | - Tilesets (an array of TMXTilesetInfo objects) | ||
136 | - ObjectGroups (an array of TMXObjectGroupInfo objects) | ||
137 | |||
138 | This information is obtained from the TMX file. | ||
139 | |||
140 | */ | ||
141 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
142 | #if defined(__IPHONE_4_0) | ||
143 | @interface CCTMXMapInfo : NSObject <NSXMLParserDelegate> | ||
144 | #else | ||
145 | @interface CCTMXMapInfo : NSObject | ||
146 | #endif | ||
147 | |||
148 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
149 | @interface CCTMXMapInfo : NSObject <NSXMLParserDelegate> | ||
150 | #endif | ||
151 | { | ||
152 | NSMutableString *currentString; | ||
153 | BOOL storingCharacters; | ||
154 | int layerAttribs; | ||
155 | int parentElement; | ||
156 | unsigned int parentGID_; | ||
157 | |||
158 | |||
159 | // tmx filename | ||
160 | NSString *filename_; | ||
161 | |||
162 | // map orientation | ||
163 | int orientation_; | ||
164 | |||
165 | // map width & height | ||
166 | CGSize mapSize_; | ||
167 | |||
168 | // tiles width & height | ||
169 | CGSize tileSize_; | ||
170 | |||
171 | // Layers | ||
172 | NSMutableArray *layers_; | ||
173 | |||
174 | // tilesets | ||
175 | NSMutableArray *tilesets_; | ||
176 | |||
177 | // ObjectGroups | ||
178 | NSMutableArray *objectGroups_; | ||
179 | |||
180 | // properties | ||
181 | NSMutableDictionary *properties_; | ||
182 | |||
183 | // tile properties | ||
184 | NSMutableDictionary *tileProperties_; | ||
185 | } | ||
186 | |||
187 | @property (nonatomic,readwrite,assign) int orientation; | ||
188 | @property (nonatomic,readwrite,assign) CGSize mapSize; | ||
189 | @property (nonatomic,readwrite,assign) CGSize tileSize; | ||
190 | @property (nonatomic,readwrite,retain) NSMutableArray *layers; | ||
191 | @property (nonatomic,readwrite,retain) NSMutableArray *tilesets; | ||
192 | @property (nonatomic,readwrite,retain) NSString *filename; | ||
193 | @property (nonatomic,readwrite,retain) NSMutableArray *objectGroups; | ||
194 | @property (nonatomic,readwrite,retain) NSMutableDictionary *properties; | ||
195 | @property (nonatomic,readwrite,retain) NSMutableDictionary *tileProperties; | ||
196 | |||
197 | /** creates a TMX Format with a tmx file */ | ||
198 | +(id) formatWithTMXFile:(NSString*)tmxFile; | ||
199 | /** initializes a TMX format witha tmx file */ | ||
200 | -(id) initWithTMXFile:(NSString*)tmxFile; | ||
201 | @end | ||
202 | |||
diff --git a/libs/cocos2d/CCTMXXMLParser.m b/libs/cocos2d/CCTMXXMLParser.m new file mode 100755 index 0000000..77cea0e --- /dev/null +++ b/libs/cocos2d/CCTMXXMLParser.m | |||
@@ -0,0 +1,456 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009-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 | * TMX Tiled Map support: | ||
27 | * http://www.mapeditor.org | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | |||
32 | #import <Foundation/Foundation.h> | ||
33 | #include <zlib.h> | ||
34 | |||
35 | #import "ccMacros.h" | ||
36 | #import "Support/CGPointExtension.h" | ||
37 | #import "CCTMXXMLParser.h" | ||
38 | #import "CCTMXTiledMap.h" | ||
39 | #import "CCTMXObjectGroup.h" | ||
40 | #import "Support/base64.h" | ||
41 | #import "Support/ZipUtils.h" | ||
42 | #import "Support/CCFileUtils.h" | ||
43 | |||
44 | #pragma mark - | ||
45 | #pragma mark TMXLayerInfo | ||
46 | |||
47 | |||
48 | @implementation CCTMXLayerInfo | ||
49 | |||
50 | @synthesize name = name_, layerSize = layerSize_, tiles = tiles_, visible = visible_, opacity = opacity_, ownTiles = ownTiles_, minGID = minGID_, maxGID = maxGID_, properties = properties_; | ||
51 | @synthesize offset = offset_; | ||
52 | -(id) init | ||
53 | { | ||
54 | if( (self=[super init])) { | ||
55 | ownTiles_ = YES; | ||
56 | minGID_ = 100000; | ||
57 | maxGID_ = 0; | ||
58 | self.name = nil; | ||
59 | tiles_ = NULL; | ||
60 | offset_ = CGPointZero; | ||
61 | self.properties = [NSMutableDictionary dictionaryWithCapacity:5]; | ||
62 | } | ||
63 | return self; | ||
64 | } | ||
65 | - (void) dealloc | ||
66 | { | ||
67 | CCLOGINFO(@"cocos2d: deallocing %@",self); | ||
68 | |||
69 | [name_ release]; | ||
70 | [properties_ release]; | ||
71 | |||
72 | if( ownTiles_ && tiles_ ) { | ||
73 | free( tiles_ ); | ||
74 | tiles_ = NULL; | ||
75 | } | ||
76 | [super dealloc]; | ||
77 | } | ||
78 | |||
79 | @end | ||
80 | |||
81 | #pragma mark - | ||
82 | #pragma mark TMXTilesetInfo | ||
83 | @implementation CCTMXTilesetInfo | ||
84 | |||
85 | @synthesize name = name_, firstGid = firstGid_, tileSize = tileSize_, spacing = spacing_, margin = margin_, sourceImage = sourceImage_, imageSize = imageSize_; | ||
86 | |||
87 | - (void) dealloc | ||
88 | { | ||
89 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
90 | [sourceImage_ release]; | ||
91 | [name_ release]; | ||
92 | [super dealloc]; | ||
93 | } | ||
94 | |||
95 | -(CGRect) rectForGID:(unsigned int)gid | ||
96 | { | ||
97 | CGRect rect; | ||
98 | rect.size = tileSize_; | ||
99 | |||
100 | gid = gid - firstGid_; | ||
101 | |||
102 | int max_x = (imageSize_.width - margin_*2 + spacing_) / (tileSize_.width + spacing_); | ||
103 | // int max_y = (imageSize.height - margin*2 + spacing) / (tileSize.height + spacing); | ||
104 | |||
105 | rect.origin.x = (gid % max_x) * (tileSize_.width + spacing_) + margin_; | ||
106 | rect.origin.y = (gid / max_x) * (tileSize_.height + spacing_) + margin_; | ||
107 | |||
108 | return rect; | ||
109 | } | ||
110 | @end | ||
111 | |||
112 | #pragma mark - | ||
113 | #pragma mark CCTMXMapInfo | ||
114 | |||
115 | @interface CCTMXMapInfo (Private) | ||
116 | /* initalises parsing of an XML file, either a tmx (Map) file or tsx (Tileset) file */ | ||
117 | -(void) parseXMLFile:(NSString *)xmlFilename; | ||
118 | @end | ||
119 | |||
120 | |||
121 | @implementation CCTMXMapInfo | ||
122 | |||
123 | @synthesize orientation = orientation_, mapSize = mapSize_, layers = layers_, tilesets = tilesets_, tileSize = tileSize_, filename = filename_, objectGroups = objectGroups_, properties = properties_; | ||
124 | @synthesize tileProperties = tileProperties_; | ||
125 | |||
126 | +(id) formatWithTMXFile:(NSString*)tmxFile | ||
127 | { | ||
128 | return [[[self alloc] initWithTMXFile:tmxFile] autorelease]; | ||
129 | } | ||
130 | |||
131 | -(id) initWithTMXFile:(NSString*)tmxFile | ||
132 | { | ||
133 | if( (self=[super init])) { | ||
134 | |||
135 | self.tilesets = [NSMutableArray arrayWithCapacity:4]; | ||
136 | self.layers = [NSMutableArray arrayWithCapacity:4]; | ||
137 | self.filename = tmxFile; | ||
138 | self.objectGroups = [NSMutableArray arrayWithCapacity:4]; | ||
139 | self.properties = [NSMutableDictionary dictionaryWithCapacity:5]; | ||
140 | self.tileProperties = [NSMutableDictionary dictionaryWithCapacity:5]; | ||
141 | |||
142 | // tmp vars | ||
143 | currentString = [[NSMutableString alloc] initWithCapacity:1024]; | ||
144 | storingCharacters = NO; | ||
145 | layerAttribs = TMXLayerAttribNone; | ||
146 | parentElement = TMXPropertyNone; | ||
147 | |||
148 | [self parseXMLFile:filename_]; | ||
149 | } | ||
150 | return self; | ||
151 | } | ||
152 | - (void) dealloc | ||
153 | { | ||
154 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
155 | [tilesets_ release]; | ||
156 | [layers_ release]; | ||
157 | [filename_ release]; | ||
158 | [currentString release]; | ||
159 | [objectGroups_ release]; | ||
160 | [properties_ release]; | ||
161 | [tileProperties_ release]; | ||
162 | [super dealloc]; | ||
163 | } | ||
164 | |||
165 | - (void) parseXMLFile:(NSString *)xmlFilename | ||
166 | { | ||
167 | NSURL *url = [NSURL fileURLWithPath:[CCFileUtils fullPathFromRelativePath:xmlFilename] ]; | ||
168 | NSData *data = [NSData dataWithContentsOfURL:url]; | ||
169 | NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; | ||
170 | |||
171 | // we'll do the parsing | ||
172 | [parser setDelegate:self]; | ||
173 | [parser setShouldProcessNamespaces:NO]; | ||
174 | [parser setShouldReportNamespacePrefixes:NO]; | ||
175 | [parser setShouldResolveExternalEntities:NO]; | ||
176 | [parser parse]; | ||
177 | |||
178 | NSAssert1( ! [parser parserError], @"Error parsing file: %@.", xmlFilename ); | ||
179 | |||
180 | [parser release]; | ||
181 | } | ||
182 | |||
183 | // the XML parser calls here with all the elements | ||
184 | -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict | ||
185 | { | ||
186 | if([elementName isEqualToString:@"map"]) { | ||
187 | NSString *version = [attributeDict valueForKey:@"version"]; | ||
188 | if( ! [version isEqualToString:@"1.0"] ) | ||
189 | CCLOG(@"cocos2d: TMXFormat: Unsupported TMX version: %@", version); | ||
190 | NSString *orientationStr = [attributeDict valueForKey:@"orientation"]; | ||
191 | if( [orientationStr isEqualToString:@"orthogonal"]) | ||
192 | orientation_ = CCTMXOrientationOrtho; | ||
193 | else if ( [orientationStr isEqualToString:@"isometric"]) | ||
194 | orientation_ = CCTMXOrientationIso; | ||
195 | else if( [orientationStr isEqualToString:@"hexagonal"]) | ||
196 | orientation_ = CCTMXOrientationHex; | ||
197 | else | ||
198 | CCLOG(@"cocos2d: TMXFomat: Unsupported orientation: %@", orientation_); | ||
199 | |||
200 | mapSize_.width = [[attributeDict valueForKey:@"width"] intValue]; | ||
201 | mapSize_.height = [[attributeDict valueForKey:@"height"] intValue]; | ||
202 | tileSize_.width = [[attributeDict valueForKey:@"tilewidth"] intValue]; | ||
203 | tileSize_.height = [[attributeDict valueForKey:@"tileheight"] intValue]; | ||
204 | |||
205 | // The parent element is now "map" | ||
206 | parentElement = TMXPropertyMap; | ||
207 | } else if([elementName isEqualToString:@"tileset"]) { | ||
208 | |||
209 | // If this is an external tileset then start parsing that | ||
210 | NSString *externalTilesetFilename = [attributeDict valueForKey:@"source"]; | ||
211 | if (externalTilesetFilename) { | ||
212 | // Tileset file will be relative to the map file. So we need to convert it to an absolute path | ||
213 | NSString *dir = [filename_ stringByDeletingLastPathComponent]; // Directory of map file | ||
214 | externalTilesetFilename = [dir stringByAppendingPathComponent:externalTilesetFilename]; // Append path to tileset file | ||
215 | |||
216 | [self parseXMLFile:externalTilesetFilename]; | ||
217 | } else { | ||
218 | |||
219 | CCTMXTilesetInfo *tileset = [CCTMXTilesetInfo new]; | ||
220 | tileset.name = [attributeDict valueForKey:@"name"]; | ||
221 | tileset.firstGid = [[attributeDict valueForKey:@"firstgid"] intValue]; | ||
222 | tileset.spacing = [[attributeDict valueForKey:@"spacing"] intValue]; | ||
223 | tileset.margin = [[attributeDict valueForKey:@"margin"] intValue]; | ||
224 | CGSize s; | ||
225 | s.width = [[attributeDict valueForKey:@"tilewidth"] intValue]; | ||
226 | s.height = [[attributeDict valueForKey:@"tileheight"] intValue]; | ||
227 | tileset.tileSize = s; | ||
228 | |||
229 | [tilesets_ addObject:tileset]; | ||
230 | [tileset release]; | ||
231 | } | ||
232 | |||
233 | }else if([elementName isEqualToString:@"tile"]){ | ||
234 | CCTMXTilesetInfo* info = [tilesets_ lastObject]; | ||
235 | NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:3]; | ||
236 | parentGID_ = [info firstGid] + [[attributeDict valueForKey:@"id"] intValue]; | ||
237 | [tileProperties_ setObject:dict forKey:[NSNumber numberWithInt:parentGID_]]; | ||
238 | |||
239 | parentElement = TMXPropertyTile; | ||
240 | |||
241 | }else if([elementName isEqualToString:@"layer"]) { | ||
242 | CCTMXLayerInfo *layer = [CCTMXLayerInfo new]; | ||
243 | layer.name = [attributeDict valueForKey:@"name"]; | ||
244 | |||
245 | CGSize s; | ||
246 | s.width = [[attributeDict valueForKey:@"width"] intValue]; | ||
247 | s.height = [[attributeDict valueForKey:@"height"] intValue]; | ||
248 | layer.layerSize = s; | ||
249 | |||
250 | layer.visible = ![[attributeDict valueForKey:@"visible"] isEqualToString:@"0"]; | ||
251 | |||
252 | if( [attributeDict valueForKey:@"opacity"] ) | ||
253 | layer.opacity = 255 * [[attributeDict valueForKey:@"opacity"] floatValue]; | ||
254 | else | ||
255 | layer.opacity = 255; | ||
256 | |||
257 | int x = [[attributeDict valueForKey:@"x"] intValue]; | ||
258 | int y = [[attributeDict valueForKey:@"y"] intValue]; | ||
259 | layer.offset = ccp(x,y); | ||
260 | |||
261 | [layers_ addObject:layer]; | ||
262 | [layer release]; | ||
263 | |||
264 | // The parent element is now "layer" | ||
265 | parentElement = TMXPropertyLayer; | ||
266 | |||
267 | } else if([elementName isEqualToString:@"objectgroup"]) { | ||
268 | |||
269 | CCTMXObjectGroup *objectGroup = [[CCTMXObjectGroup alloc] init]; | ||
270 | objectGroup.groupName = [attributeDict valueForKey:@"name"]; | ||
271 | CGPoint positionOffset; | ||
272 | positionOffset.x = [[attributeDict valueForKey:@"x"] intValue] * tileSize_.width; | ||
273 | positionOffset.y = [[attributeDict valueForKey:@"y"] intValue] * tileSize_.height; | ||
274 | objectGroup.positionOffset = positionOffset; | ||
275 | |||
276 | [objectGroups_ addObject:objectGroup]; | ||
277 | [objectGroup release]; | ||
278 | |||
279 | // The parent element is now "objectgroup" | ||
280 | parentElement = TMXPropertyObjectGroup; | ||
281 | |||
282 | } else if([elementName isEqualToString:@"image"]) { | ||
283 | |||
284 | CCTMXTilesetInfo *tileset = [tilesets_ lastObject]; | ||
285 | |||
286 | // build full path | ||
287 | NSString *imagename = [attributeDict valueForKey:@"source"]; | ||
288 | NSString *path = [filename_ stringByDeletingLastPathComponent]; | ||
289 | tileset.sourceImage = [path stringByAppendingPathComponent:imagename]; | ||
290 | |||
291 | } else if([elementName isEqualToString:@"data"]) { | ||
292 | NSString *encoding = [attributeDict valueForKey:@"encoding"]; | ||
293 | NSString *compression = [attributeDict valueForKey:@"compression"]; | ||
294 | |||
295 | if( [encoding isEqualToString:@"base64"] ) { | ||
296 | layerAttribs |= TMXLayerAttribBase64; | ||
297 | storingCharacters = YES; | ||
298 | |||
299 | if( [compression isEqualToString:@"gzip"] ) | ||
300 | layerAttribs |= TMXLayerAttribGzip; | ||
301 | |||
302 | else if( [compression isEqualToString:@"zlib"] ) | ||
303 | layerAttribs |= TMXLayerAttribZlib; | ||
304 | |||
305 | NSAssert( !compression || [compression isEqualToString:@"gzip"] || [compression isEqualToString:@"zlib"], @"TMX: unsupported compression method" ); | ||
306 | } | ||
307 | |||
308 | NSAssert( layerAttribs != TMXLayerAttribNone, @"TMX tile map: Only base64 and/or gzip/zlib maps are supported" ); | ||
309 | |||
310 | } else if([elementName isEqualToString:@"object"]) { | ||
311 | |||
312 | CCTMXObjectGroup *objectGroup = [objectGroups_ lastObject]; | ||
313 | |||
314 | // The value for "type" was blank or not a valid class name | ||
315 | // Create an instance of TMXObjectInfo to store the object and its properties | ||
316 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:5]; | ||
317 | |||
318 | // Set the name of the object to the value for "name" | ||
319 | [dict setValue:[attributeDict valueForKey:@"name"] forKey:@"name"]; | ||
320 | |||
321 | // Assign all the attributes as key/name pairs in the properties dictionary | ||
322 | [dict setValue:[attributeDict valueForKey:@"type"] forKey:@"type"]; | ||
323 | int x = [[attributeDict valueForKey:@"x"] intValue] + objectGroup.positionOffset.x; | ||
324 | [dict setValue:[NSNumber numberWithInt:x] forKey:@"x"]; | ||
325 | int y = [[attributeDict valueForKey:@"y"] intValue] + objectGroup.positionOffset.y; | ||
326 | // Correct y position. (Tiled uses Flipped, cocos2d uses Standard) | ||
327 | y = (mapSize_.height * tileSize_.height) - y - [[attributeDict valueForKey:@"height"] intValue]; | ||
328 | [dict setValue:[NSNumber numberWithInt:y] forKey:@"y"]; | ||
329 | [dict setValue:[attributeDict valueForKey:@"width"] forKey:@"width"]; | ||
330 | [dict setValue:[attributeDict valueForKey:@"height"] forKey:@"height"]; | ||
331 | |||
332 | // Add the object to the objectGroup | ||
333 | [[objectGroup objects] addObject:dict]; | ||
334 | [dict release]; | ||
335 | |||
336 | // The parent element is now "object" | ||
337 | parentElement = TMXPropertyObject; | ||
338 | |||
339 | } else if([elementName isEqualToString:@"property"]) { | ||
340 | |||
341 | if ( parentElement == TMXPropertyNone ) { | ||
342 | |||
343 | CCLOG( @"TMX tile map: Parent element is unsupported. Cannot add property named '%@' with value '%@'", | ||
344 | [attributeDict valueForKey:@"name"], [attributeDict valueForKey:@"value"] ); | ||
345 | |||
346 | } else if ( parentElement == TMXPropertyMap ) { | ||
347 | |||
348 | // The parent element is the map | ||
349 | [properties_ setValue:[attributeDict valueForKey:@"value"] forKey:[attributeDict valueForKey:@"name"]]; | ||
350 | |||
351 | } else if ( parentElement == TMXPropertyLayer ) { | ||
352 | |||
353 | // The parent element is the last layer | ||
354 | CCTMXLayerInfo *layer = [layers_ lastObject]; | ||
355 | // Add the property to the layer | ||
356 | [[layer properties] setValue:[attributeDict valueForKey:@"value"] forKey:[attributeDict valueForKey:@"name"]]; | ||
357 | |||
358 | } else if ( parentElement == TMXPropertyObjectGroup ) { | ||
359 | |||
360 | // The parent element is the last object group | ||
361 | CCTMXObjectGroup *objectGroup = [objectGroups_ lastObject]; | ||
362 | [[objectGroup properties] setValue:[attributeDict valueForKey:@"value"] forKey:[attributeDict valueForKey:@"name"]]; | ||
363 | |||
364 | } else if ( parentElement == TMXPropertyObject ) { | ||
365 | |||
366 | // The parent element is the last object | ||
367 | CCTMXObjectGroup *objectGroup = [objectGroups_ lastObject]; | ||
368 | NSMutableDictionary *dict = [[objectGroup objects] lastObject]; | ||
369 | |||
370 | NSString *propertyName = [attributeDict valueForKey:@"name"]; | ||
371 | NSString *propertyValue = [attributeDict valueForKey:@"value"]; | ||
372 | |||
373 | [dict setValue:propertyValue forKey:propertyName]; | ||
374 | } else if ( parentElement == TMXPropertyTile ) { | ||
375 | |||
376 | NSMutableDictionary* dict = [tileProperties_ objectForKey:[NSNumber numberWithInt:parentGID_]]; | ||
377 | NSString *propertyName = [attributeDict valueForKey:@"name"]; | ||
378 | NSString *propertyValue = [attributeDict valueForKey:@"value"]; | ||
379 | [dict setObject:propertyValue forKey:propertyName]; | ||
380 | |||
381 | } | ||
382 | } | ||
383 | } | ||
384 | |||
385 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName | ||
386 | { | ||
387 | int len = 0; | ||
388 | |||
389 | if([elementName isEqualToString:@"data"] && layerAttribs&TMXLayerAttribBase64) { | ||
390 | storingCharacters = NO; | ||
391 | |||
392 | CCTMXLayerInfo *layer = [layers_ lastObject]; | ||
393 | |||
394 | unsigned char *buffer; | ||
395 | len = base64Decode((unsigned char*)[currentString UTF8String], (unsigned int) [currentString length], &buffer); | ||
396 | if( ! buffer ) { | ||
397 | CCLOG(@"cocos2d: TiledMap: decode data error"); | ||
398 | return; | ||
399 | } | ||
400 | |||
401 | if( layerAttribs & (TMXLayerAttribGzip | TMXLayerAttribZlib) ) { | ||
402 | unsigned char *deflated; | ||
403 | CGSize s = [layer layerSize]; | ||
404 | int sizeHint = s.width * s.height * sizeof(uint32_t); | ||
405 | |||
406 | int inflatedLen = ccInflateMemoryWithHint(buffer, len, &deflated, sizeHint); | ||
407 | NSAssert( inflatedLen == sizeHint, @"CCTMXXMLParser: Hint failed!"); | ||
408 | |||
409 | inflatedLen = (int)&inflatedLen; // XXX: to avoid warings in compiler | ||
410 | |||
411 | free( buffer ); | ||
412 | |||
413 | if( ! deflated ) { | ||
414 | CCLOG(@"cocos2d: TiledMap: inflate data error"); | ||
415 | return; | ||
416 | } | ||
417 | |||
418 | layer.tiles = (unsigned int*) deflated; | ||
419 | } else | ||
420 | layer.tiles = (unsigned int*) buffer; | ||
421 | |||
422 | [currentString setString:@""]; | ||
423 | |||
424 | } else if ([elementName isEqualToString:@"map"]) { | ||
425 | // The map element has ended | ||
426 | parentElement = TMXPropertyNone; | ||
427 | |||
428 | } else if ([elementName isEqualToString:@"layer"]) { | ||
429 | // The layer element has ended | ||
430 | parentElement = TMXPropertyNone; | ||
431 | |||
432 | } else if ([elementName isEqualToString:@"objectgroup"]) { | ||
433 | // The objectgroup element has ended | ||
434 | parentElement = TMXPropertyNone; | ||
435 | |||
436 | } else if ([elementName isEqualToString:@"object"]) { | ||
437 | // The object element has ended | ||
438 | parentElement = TMXPropertyNone; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string | ||
443 | { | ||
444 | if (storingCharacters) | ||
445 | [currentString appendString:string]; | ||
446 | } | ||
447 | |||
448 | |||
449 | // | ||
450 | // the level did not load, file not found, etc. | ||
451 | // | ||
452 | -(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{ | ||
453 | CCLOG(@"cocos2d: Error on XML Parse: %@", [parseError localizedDescription] ); | ||
454 | } | ||
455 | |||
456 | @end | ||
diff --git a/libs/cocos2d/CCTexture2D.h b/libs/cocos2d/CCTexture2D.h new file mode 100755 index 0000000..45eea9c --- /dev/null +++ b/libs/cocos2d/CCTexture2D.h | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | |||
3 | ===== IMPORTANT ===== | ||
4 | |||
5 | This is sample code demonstrating API, technology or techniques in development. | ||
6 | Although this sample code has been reviewed for technical accuracy, it is not | ||
7 | final. Apple is supplying this information to help you plan for the adoption of | ||
8 | the technologies and programming interfaces described herein. This information | ||
9 | is subject to change, and software implemented based on this sample code should | ||
10 | be tested with final operating system software and final documentation. Newer | ||
11 | versions of this sample code may be provided with future seeds of the API or | ||
12 | technology. For information about updates to this and other developer | ||
13 | documentation, view the New & Updated sidebars in subsequent documentation | ||
14 | seeds. | ||
15 | |||
16 | ===================== | ||
17 | |||
18 | File: Texture2D.h | ||
19 | Abstract: Creates OpenGL 2D textures from images or text. | ||
20 | |||
21 | Version: 1.6 | ||
22 | |||
23 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. | ||
24 | ("Apple") in consideration of your agreement to the following terms, and your | ||
25 | use, installation, modification or redistribution of this Apple software | ||
26 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
27 | please do not use, install, modify or redistribute this Apple software. | ||
28 | |||
29 | In consideration of your agreement to abide by the following terms, and subject | ||
30 | to these terms, Apple grants you a personal, non-exclusive license, under | ||
31 | Apple's copyrights in this original Apple software (the "Apple Software"), to | ||
32 | use, reproduce, modify and redistribute the Apple Software, with or without | ||
33 | modifications, in source and/or binary forms; provided that if you redistribute | ||
34 | the Apple Software in its entirety and without modifications, you must retain | ||
35 | this notice and the following text and disclaimers in all such redistributions | ||
36 | of the Apple Software. | ||
37 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used | ||
38 | to endorse or promote products derived from the Apple Software without specific | ||
39 | prior written permission from Apple. Except as expressly stated in this notice, | ||
40 | no other rights or licenses, express or implied, are granted by Apple herein, | ||
41 | including but not limited to any patent rights that may be infringed by your | ||
42 | derivative works or by other works in which the Apple Software may be | ||
43 | incorporated. | ||
44 | |||
45 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
46 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
47 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
48 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
49 | COMBINATION WITH YOUR PRODUCTS. | ||
50 | |||
51 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
52 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
53 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
54 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR | ||
55 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF | ||
56 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF | ||
57 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
58 | |||
59 | Copyright (C) 2008 Apple Inc. All Rights Reserved. | ||
60 | |||
61 | */ | ||
62 | |||
63 | #import <Availability.h> | ||
64 | |||
65 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
66 | #import <UIKit/UIKit.h> // for UIImage | ||
67 | #endif | ||
68 | |||
69 | #import <Foundation/Foundation.h> // for NSObject | ||
70 | |||
71 | #import "Platforms/CCGL.h" // OpenGL stuff | ||
72 | #import "Platforms/CCNS.h" // Next-Step stuff | ||
73 | |||
74 | //CONSTANTS: | ||
75 | |||
76 | /** @typedef CCTexture2DPixelFormat | ||
77 | Possible texture pixel formats | ||
78 | */ | ||
79 | typedef enum { | ||
80 | kCCTexture2DPixelFormat_Automatic = 0, | ||
81 | //! 32-bit texture: RGBA8888 | ||
82 | kCCTexture2DPixelFormat_RGBA8888, | ||
83 | //! 16-bit texture without Alpha channel | ||
84 | kCCTexture2DPixelFormat_RGB565, | ||
85 | //! 8-bit textures used as masks | ||
86 | kCCTexture2DPixelFormat_A8, | ||
87 | //! 8-bit intensity texture | ||
88 | kCCTexture2DPixelFormat_I8, | ||
89 | //! 16-bit textures used as masks | ||
90 | kCCTexture2DPixelFormat_AI88, | ||
91 | //! 16-bit textures: RGBA4444 | ||
92 | kCCTexture2DPixelFormat_RGBA4444, | ||
93 | //! 16-bit textures: RGB5A1 | ||
94 | kCCTexture2DPixelFormat_RGB5A1, | ||
95 | //! 4-bit PVRTC-compressed texture: PVRTC4 | ||
96 | kCCTexture2DPixelFormat_PVRTC4, | ||
97 | //! 2-bit PVRTC-compressed texture: PVRTC2 | ||
98 | kCCTexture2DPixelFormat_PVRTC2, | ||
99 | |||
100 | //! Default texture format: RGBA8888 | ||
101 | kCCTexture2DPixelFormat_Default = kCCTexture2DPixelFormat_RGBA8888, | ||
102 | |||
103 | // backward compatibility stuff | ||
104 | kTexture2DPixelFormat_Automatic = kCCTexture2DPixelFormat_Automatic, | ||
105 | kTexture2DPixelFormat_RGBA8888 = kCCTexture2DPixelFormat_RGBA8888, | ||
106 | kTexture2DPixelFormat_RGB565 = kCCTexture2DPixelFormat_RGB565, | ||
107 | kTexture2DPixelFormat_A8 = kCCTexture2DPixelFormat_A8, | ||
108 | kTexture2DPixelFormat_RGBA4444 = kCCTexture2DPixelFormat_RGBA4444, | ||
109 | kTexture2DPixelFormat_RGB5A1 = kCCTexture2DPixelFormat_RGB5A1, | ||
110 | kTexture2DPixelFormat_Default = kCCTexture2DPixelFormat_Default | ||
111 | |||
112 | } CCTexture2DPixelFormat; | ||
113 | |||
114 | //CLASS INTERFACES: | ||
115 | |||
116 | /** CCTexture2D class. | ||
117 | * This class allows to easily create OpenGL 2D textures from images, text or raw data. | ||
118 | * The created CCTexture2D object will always have power-of-two dimensions. | ||
119 | * Depending on how you create the CCTexture2D object, the actual image area of the texture might be smaller than the texture dimensions i.e. "contentSize" != (pixelsWide, pixelsHigh) and (maxS, maxT) != (1.0, 1.0). | ||
120 | * Be aware that the content of the generated textures will be upside-down! | ||
121 | */ | ||
122 | @interface CCTexture2D : NSObject | ||
123 | { | ||
124 | GLuint name_; | ||
125 | CGSize size_; | ||
126 | NSUInteger width_, | ||
127 | height_; | ||
128 | CCTexture2DPixelFormat format_; | ||
129 | GLfloat maxS_, | ||
130 | maxT_; | ||
131 | BOOL hasPremultipliedAlpha_; | ||
132 | } | ||
133 | /** Intializes with a texture2d with data */ | ||
134 | - (id) initWithData:(const void*)data pixelFormat:(CCTexture2DPixelFormat)pixelFormat pixelsWide:(NSUInteger)width pixelsHigh:(NSUInteger)height contentSize:(CGSize)size; | ||
135 | |||
136 | /** These functions are needed to create mutable textures */ | ||
137 | - (void) releaseData:(void*)data; | ||
138 | - (void*) keepData:(void*)data length:(NSUInteger)length; | ||
139 | |||
140 | /** pixel format of the texture */ | ||
141 | @property(nonatomic,readonly) CCTexture2DPixelFormat pixelFormat; | ||
142 | /** width in pixels */ | ||
143 | @property(nonatomic,readonly) NSUInteger pixelsWide; | ||
144 | /** hight in pixels */ | ||
145 | @property(nonatomic,readonly) NSUInteger pixelsHigh; | ||
146 | |||
147 | /** texture name */ | ||
148 | @property(nonatomic,readonly) GLuint name; | ||
149 | |||
150 | /** returns content size of the texture in pixels */ | ||
151 | @property(nonatomic,readonly, nonatomic) CGSize contentSizeInPixels; | ||
152 | |||
153 | /** texture max S */ | ||
154 | @property(nonatomic,readwrite) GLfloat maxS; | ||
155 | /** texture max T */ | ||
156 | @property(nonatomic,readwrite) GLfloat maxT; | ||
157 | /** whether or not the texture has their Alpha premultiplied */ | ||
158 | @property(nonatomic,readonly) BOOL hasPremultipliedAlpha; | ||
159 | |||
160 | /** returns the content size of the texture in points */ | ||
161 | -(CGSize) contentSize; | ||
162 | @end | ||
163 | |||
164 | /** | ||
165 | Drawing extensions to make it easy to draw basic quads using a CCTexture2D object. | ||
166 | These functions require GL_TEXTURE_2D and both GL_VERTEX_ARRAY and GL_TEXTURE_COORD_ARRAY client states to be enabled. | ||
167 | */ | ||
168 | @interface CCTexture2D (Drawing) | ||
169 | /** draws a texture at a given point */ | ||
170 | - (void) drawAtPoint:(CGPoint)point; | ||
171 | /** draws a texture inside a rect */ | ||
172 | - (void) drawInRect:(CGRect)rect; | ||
173 | @end | ||
174 | |||
175 | /** | ||
176 | Extensions to make it easy to create a CCTexture2D object from an image file. | ||
177 | Note that RGBA type textures will have their alpha premultiplied - use the blending mode (GL_ONE, GL_ONE_MINUS_SRC_ALPHA). | ||
178 | */ | ||
179 | @interface CCTexture2D (Image) | ||
180 | /** Initializes a texture from a UIImage object */ | ||
181 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
182 | - (id) initWithImage:(UIImage *)uiImage; | ||
183 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
184 | - (id) initWithImage:(CGImageRef)cgImage; | ||
185 | #endif | ||
186 | @end | ||
187 | |||
188 | /** | ||
189 | Extensions to make it easy to create a CCTexture2D object from a string of text. | ||
190 | Note that the generated textures are of type A8 - use the blending mode (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA). | ||
191 | */ | ||
192 | @interface CCTexture2D (Text) | ||
193 | /** Initializes a texture from a string with dimensions, alignment, line break mode, font name and font size | ||
194 | Supported lineBreakModes: | ||
195 | - iOS: all UILineBreakMode supported modes | ||
196 | - Mac: Only NSLineBreakByWordWrapping is supported. | ||
197 | @since v1.0 | ||
198 | */ | ||
199 | - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment lineBreakMode:(CCLineBreakMode)lineBreakMode fontName:(NSString*)name fontSize:(CGFloat)size; | ||
200 | /** Initializes a texture from a string with dimensions, alignment, font name and font size */ | ||
201 | - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment fontName:(NSString*)name fontSize:(CGFloat)size; | ||
202 | /** Initializes a texture from a string with font name and font size */ | ||
203 | - (id) initWithString:(NSString*)string fontName:(NSString*)name fontSize:(CGFloat)size; | ||
204 | @end | ||
205 | |||
206 | |||
207 | /** | ||
208 | Extensions to make it easy to create a CCTexture2D object from a PVRTC file | ||
209 | Note that the generated textures don't have their alpha premultiplied - use the blending mode (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA). | ||
210 | */ | ||
211 | @interface CCTexture2D (PVRSupport) | ||
212 | /** Initializes a texture from a PVR Texture Compressed (PVRTC) buffer | ||
213 | * | ||
214 | * IMPORTANT: This method is only defined on iOS. It is not supported on the Mac version. | ||
215 | */ | ||
216 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
217 | -(id) initWithPVRTCData: (const void*)data level:(int)level bpp:(int)bpp hasAlpha:(BOOL)hasAlpha length:(int)length pixelFormat:(CCTexture2DPixelFormat)pixelFormat; | ||
218 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
219 | /** Initializes a texture from a PVR file. | ||
220 | |||
221 | Supported PVR formats: | ||
222 | - BGRA 8888 | ||
223 | - RGBA 8888 | ||
224 | - RGBA 4444 | ||
225 | - RGBA 5551 | ||
226 | - RBG 565 | ||
227 | - A 8 | ||
228 | - I 8 | ||
229 | - AI 8 | ||
230 | - PVRTC 2BPP | ||
231 | - PVRTC 4BPP | ||
232 | |||
233 | By default PVR images are treated as if they alpha channel is NOT premultiplied. You can override this behavior with this class method: | ||
234 | - PVRImagesHavePremultipliedAlpha:(BOOL)haveAlphaPremultiplied; | ||
235 | |||
236 | IMPORTANT: This method is only defined on iOS. It is not supported on the Mac version. | ||
237 | |||
238 | */ | ||
239 | -(id) initWithPVRFile: (NSString*) file; | ||
240 | |||
241 | /** treats (or not) PVR files as if they have alpha premultiplied. | ||
242 | Since it is impossible to know at runtime if the PVR images have the alpha channel premultiplied, it is | ||
243 | possible load them as if they have (or not) the alpha channel premultiplied. | ||
244 | |||
245 | By default it is disabled. | ||
246 | |||
247 | @since v0.99.5 | ||
248 | */ | ||
249 | +(void) PVRImagesHavePremultipliedAlpha:(BOOL)haveAlphaPremultiplied; | ||
250 | @end | ||
251 | |||
252 | /** | ||
253 | Extension to set the Min / Mag filter | ||
254 | */ | ||
255 | typedef struct _ccTexParams { | ||
256 | GLuint minFilter; | ||
257 | GLuint magFilter; | ||
258 | GLuint wrapS; | ||
259 | GLuint wrapT; | ||
260 | } ccTexParams; | ||
261 | |||
262 | @interface CCTexture2D (GLFilter) | ||
263 | /** sets the min filter, mag filter, wrap s and wrap t texture parameters. | ||
264 | If the texture size is NPOT (non power of 2), then in can only use GL_CLAMP_TO_EDGE in GL_TEXTURE_WRAP_{S,T}. | ||
265 | @since v0.8 | ||
266 | */ | ||
267 | -(void) setTexParameters: (ccTexParams*) texParams; | ||
268 | |||
269 | /** sets antialias texture parameters: | ||
270 | - GL_TEXTURE_MIN_FILTER = GL_LINEAR | ||
271 | - GL_TEXTURE_MAG_FILTER = GL_LINEAR | ||
272 | |||
273 | @since v0.8 | ||
274 | */ | ||
275 | - (void) setAntiAliasTexParameters; | ||
276 | |||
277 | /** sets alias texture parameters: | ||
278 | - GL_TEXTURE_MIN_FILTER = GL_NEAREST | ||
279 | - GL_TEXTURE_MAG_FILTER = GL_NEAREST | ||
280 | |||
281 | @since v0.8 | ||
282 | */ | ||
283 | - (void) setAliasTexParameters; | ||
284 | |||
285 | |||
286 | /** Generates mipmap images for the texture. | ||
287 | It only works if the texture size is POT (power of 2). | ||
288 | @since v0.99.0 | ||
289 | */ | ||
290 | -(void) generateMipmap; | ||
291 | |||
292 | |||
293 | @end | ||
294 | |||
295 | @interface CCTexture2D (PixelFormat) | ||
296 | /** sets the default pixel format for UIImages that contains alpha channel. | ||
297 | If the UIImage contains alpha channel, then the options are: | ||
298 | - generate 32-bit textures: kCCTexture2DPixelFormat_RGBA8888 (default one) | ||
299 | - generate 16-bit textures: kCCTexture2DPixelFormat_RGBA4444 | ||
300 | - generate 16-bit textures: kCCTexture2DPixelFormat_RGB5A1 | ||
301 | - generate 16-bit textures: kCCTexture2DPixelFormat_RGB565 | ||
302 | - generate 8-bit textures: kCCTexture2DPixelFormat_A8 (only use it if you use just 1 color) | ||
303 | |||
304 | How does it work ? | ||
305 | - If the image is an RGBA (with Alpha) then the default pixel format will be used (it can be a 8-bit, 16-bit or 32-bit texture) | ||
306 | - If the image is an RGB (without Alpha) then an RGB565 texture will be used (16-bit texture) | ||
307 | |||
308 | This parameter is not valid for PVR images. | ||
309 | |||
310 | @since v0.8 | ||
311 | */ | ||
312 | +(void) setDefaultAlphaPixelFormat:(CCTexture2DPixelFormat)format; | ||
313 | |||
314 | /** returns the alpha pixel format | ||
315 | @since v0.8 | ||
316 | */ | ||
317 | +(CCTexture2DPixelFormat) defaultAlphaPixelFormat; | ||
318 | |||
319 | /** returns the bits-per-pixel of the in-memory OpenGL texture | ||
320 | @since v1.0 | ||
321 | */ | ||
322 | -(NSUInteger) bitsPerPixelForFormat; | ||
323 | @end | ||
324 | |||
325 | |||
326 | |||
327 | |||
328 | |||
diff --git a/libs/cocos2d/CCTexture2D.m b/libs/cocos2d/CCTexture2D.m new file mode 100755 index 0000000..afa64e2 --- /dev/null +++ b/libs/cocos2d/CCTexture2D.m | |||
@@ -0,0 +1,814 @@ | |||
1 | /* | ||
2 | |||
3 | ===== IMPORTANT ===== | ||
4 | |||
5 | This is sample code demonstrating API, technology or techniques in development. | ||
6 | Although this sample code has been reviewed for technical accuracy, it is not | ||
7 | final. Apple is supplying this information to help you plan for the adoption of | ||
8 | the technologies and programming interfaces described herein. This information | ||
9 | is subject to change, and software implemented based on this sample code should | ||
10 | be tested with final operating system software and final documentation. Newer | ||
11 | versions of this sample code may be provided with future seeds of the API or | ||
12 | technology. For information about updates to this and other developer | ||
13 | documentation, view the New & Updated sidebars in subsequent documentationd | ||
14 | seeds. | ||
15 | |||
16 | ===================== | ||
17 | |||
18 | File: Texture2D.m | ||
19 | Abstract: Creates OpenGL 2D textures from images or text. | ||
20 | |||
21 | Version: 1.6 | ||
22 | |||
23 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. | ||
24 | ("Apple") in consideration of your agreement to the following terms, and your | ||
25 | use, installation, modification or redistribution of this Apple software | ||
26 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
27 | please do not use, install, modify or redistribute this Apple software. | ||
28 | |||
29 | In consideration of your agreement to abide by the following terms, and subject | ||
30 | to these terms, Apple grants you a personal, non-exclusive license, under | ||
31 | Apple's copyrights in this original Apple software (the "Apple Software"), to | ||
32 | use, reproduce, modify and redistribute the Apple Software, with or without | ||
33 | modifications, in source and/or binary forms; provided that if you redistribute | ||
34 | the Apple Software in its entirety and without modifications, you must retain | ||
35 | this notice and the following text and disclaimers in all such redistributions | ||
36 | of the Apple Software. | ||
37 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used | ||
38 | to endorse or promote products derived from the Apple Software without specific | ||
39 | prior written permission from Apple. Except as expressly stated in this notice, | ||
40 | no other rights or licenses, express or implied, are granted by Apple herein, | ||
41 | including but not limited to any patent rights that may be infringed by your | ||
42 | derivative works or by other works in which the Apple Software may be | ||
43 | incorporated. | ||
44 | |||
45 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
46 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
47 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
48 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
49 | COMBINATION WITH YOUR PRODUCTS. | ||
50 | |||
51 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
52 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
53 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
54 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR | ||
55 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF | ||
56 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF | ||
57 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
58 | |||
59 | Copyright (C) 2008 Apple Inc. All Rights Reserved. | ||
60 | |||
61 | */ | ||
62 | |||
63 | /* | ||
64 | * Support for RGBA_4_4_4_4 and RGBA_5_5_5_1 was copied from: | ||
65 | * https://devforums.apple.com/message/37855#37855 by a1studmuffin | ||
66 | */ | ||
67 | |||
68 | |||
69 | #import <Availability.h> | ||
70 | |||
71 | #import "Platforms/CCGL.h" | ||
72 | #import "Platforms/CCNS.h" | ||
73 | |||
74 | |||
75 | #import "CCTexture2D.h" | ||
76 | #import "ccConfig.h" | ||
77 | #import "ccMacros.h" | ||
78 | #import "CCConfiguration.h" | ||
79 | #import "Support/ccUtils.h" | ||
80 | #import "CCTexturePVR.h" | ||
81 | |||
82 | #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && CC_FONT_LABEL_SUPPORT | ||
83 | // FontLabel support | ||
84 | #import "FontManager.h" | ||
85 | #import "FontLabelStringDrawing.h" | ||
86 | #endif// CC_FONT_LABEL_SUPPORT | ||
87 | |||
88 | |||
89 | // For Labels use 16-bit textures on iPhone 3GS / iPads since A8 textures are very slow | ||
90 | #if (defined(__ARM_NEON__) || TARGET_IPHONE_SIMULATOR) && CC_USE_LA88_LABELS_ON_NEON_ARCH | ||
91 | #define USE_TEXT_WITH_A8_TEXTURES 0 | ||
92 | |||
93 | #else | ||
94 | #define USE_TEXT_WITH_A8_TEXTURES 1 | ||
95 | #endif | ||
96 | |||
97 | //CLASS IMPLEMENTATIONS: | ||
98 | |||
99 | |||
100 | // If the image has alpha, you can create RGBA8 (32-bit) or RGBA4 (16-bit) or RGB5A1 (16-bit) | ||
101 | // Default is: RGBA8888 (32-bit textures) | ||
102 | static CCTexture2DPixelFormat defaultAlphaPixelFormat_ = kCCTexture2DPixelFormat_Default; | ||
103 | |||
104 | #pragma mark - | ||
105 | #pragma mark CCTexture2D - Main | ||
106 | |||
107 | @implementation CCTexture2D | ||
108 | |||
109 | @synthesize contentSizeInPixels = size_, pixelFormat = format_, pixelsWide = width_, pixelsHigh = height_, name = name_, maxS = maxS_, maxT = maxT_; | ||
110 | @synthesize hasPremultipliedAlpha = hasPremultipliedAlpha_; | ||
111 | |||
112 | - (id) initWithData:(const void*)data pixelFormat:(CCTexture2DPixelFormat)pixelFormat pixelsWide:(NSUInteger)width pixelsHigh:(NSUInteger)height contentSize:(CGSize)size | ||
113 | { | ||
114 | if((self = [super init])) { | ||
115 | glPixelStorei(GL_UNPACK_ALIGNMENT,1); | ||
116 | glGenTextures(1, &name_); | ||
117 | glBindTexture(GL_TEXTURE_2D, name_); | ||
118 | |||
119 | [self setAntiAliasTexParameters]; | ||
120 | |||
121 | // Specify OpenGL texture image | ||
122 | |||
123 | switch(pixelFormat) | ||
124 | { | ||
125 | case kCCTexture2DPixelFormat_RGBA8888: | ||
126 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) width, (GLsizei) height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); | ||
127 | break; | ||
128 | case kCCTexture2DPixelFormat_RGBA4444: | ||
129 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) width, (GLsizei) height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); | ||
130 | break; | ||
131 | case kCCTexture2DPixelFormat_RGB5A1: | ||
132 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) width, (GLsizei) height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, data); | ||
133 | break; | ||
134 | case kCCTexture2DPixelFormat_RGB565: | ||
135 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei) width, (GLsizei) height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); | ||
136 | break; | ||
137 | case kCCTexture2DPixelFormat_AI88: | ||
138 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, (GLsizei) width, (GLsizei) height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data); | ||
139 | break; | ||
140 | case kCCTexture2DPixelFormat_A8: | ||
141 | glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, (GLsizei) width, (GLsizei) height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); | ||
142 | break; | ||
143 | default: | ||
144 | [NSException raise:NSInternalInconsistencyException format:@""]; | ||
145 | |||
146 | } | ||
147 | |||
148 | size_ = size; | ||
149 | width_ = width; | ||
150 | height_ = height; | ||
151 | format_ = pixelFormat; | ||
152 | maxS_ = size.width / (float)width; | ||
153 | maxT_ = size.height / (float)height; | ||
154 | |||
155 | hasPremultipliedAlpha_ = NO; | ||
156 | } | ||
157 | return self; | ||
158 | } | ||
159 | |||
160 | - (void) releaseData:(void*)data | ||
161 | { | ||
162 | //Free data | ||
163 | free(data); | ||
164 | } | ||
165 | |||
166 | - (void*) keepData:(void*)data length:(NSUInteger)length | ||
167 | { | ||
168 | //The texture data mustn't be saved becuase it isn't a mutable texture. | ||
169 | return data; | ||
170 | } | ||
171 | |||
172 | - (void) dealloc | ||
173 | { | ||
174 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
175 | if(name_) | ||
176 | glDeleteTextures(1, &name_); | ||
177 | |||
178 | [super dealloc]; | ||
179 | } | ||
180 | |||
181 | - (NSString*) description | ||
182 | { | ||
183 | return [NSString stringWithFormat:@"<%@ = %08X | Name = %i | Dimensions = %ix%i | Coordinates = (%.2f, %.2f)>", [self class], self, name_, width_, height_, maxS_, maxT_]; | ||
184 | } | ||
185 | |||
186 | -(CGSize) contentSize | ||
187 | { | ||
188 | CGSize ret; | ||
189 | ret.width = size_.width / CC_CONTENT_SCALE_FACTOR(); | ||
190 | ret.height = size_.height / CC_CONTENT_SCALE_FACTOR(); | ||
191 | |||
192 | return ret; | ||
193 | } | ||
194 | @end | ||
195 | |||
196 | #pragma mark - | ||
197 | #pragma mark CCTexture2D - Image | ||
198 | |||
199 | @implementation CCTexture2D (Image) | ||
200 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
201 | - (id) initWithImage:(UIImage *)uiImage | ||
202 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
203 | - (id) initWithImage:(CGImageRef)CGImage | ||
204 | #endif | ||
205 | { | ||
206 | NSUInteger POTWide, POTHigh; | ||
207 | CGContextRef context = nil; | ||
208 | void* data = nil;; | ||
209 | CGColorSpaceRef colorSpace; | ||
210 | void* tempData; | ||
211 | unsigned int* inPixel32; | ||
212 | unsigned short* outPixel16; | ||
213 | BOOL hasAlpha; | ||
214 | CGImageAlphaInfo info; | ||
215 | CGSize imageSize; | ||
216 | CCTexture2DPixelFormat pixelFormat; | ||
217 | |||
218 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
219 | CGImageRef CGImage = uiImage.CGImage; | ||
220 | #endif | ||
221 | |||
222 | if(CGImage == NULL) { | ||
223 | CCLOG(@"cocos2d: CCTexture2D. Can't create Texture. UIImage is nil"); | ||
224 | [self release]; | ||
225 | return nil; | ||
226 | } | ||
227 | |||
228 | CCConfiguration *conf = [CCConfiguration sharedConfiguration]; | ||
229 | |||
230 | #if CC_TEXTURE_NPOT_SUPPORT | ||
231 | if( [conf supportsNPOT] ) { | ||
232 | POTWide = CGImageGetWidth(CGImage); | ||
233 | POTHigh = CGImageGetHeight(CGImage); | ||
234 | |||
235 | } else | ||
236 | #endif | ||
237 | { | ||
238 | POTWide = ccNextPOT(CGImageGetWidth(CGImage)); | ||
239 | POTHigh = ccNextPOT(CGImageGetHeight(CGImage)); | ||
240 | } | ||
241 | |||
242 | NSUInteger maxTextureSize = [conf maxTextureSize]; | ||
243 | if( POTHigh > maxTextureSize || POTWide > maxTextureSize ) { | ||
244 | CCLOG(@"cocos2d: WARNING: Image (%lu x %lu) is bigger than the supported %ld x %ld", | ||
245 | (long)POTWide, (long)POTHigh, | ||
246 | (long)maxTextureSize, (long)maxTextureSize); | ||
247 | [self release]; | ||
248 | return nil; | ||
249 | } | ||
250 | |||
251 | info = CGImageGetAlphaInfo(CGImage); | ||
252 | hasAlpha = ((info == kCGImageAlphaPremultipliedLast) || (info == kCGImageAlphaPremultipliedFirst) || (info == kCGImageAlphaLast) || (info == kCGImageAlphaFirst) ? YES : NO); | ||
253 | |||
254 | size_t bpp = CGImageGetBitsPerComponent(CGImage); | ||
255 | colorSpace = CGImageGetColorSpace(CGImage); | ||
256 | |||
257 | if(colorSpace) { | ||
258 | if(hasAlpha || bpp >= 8) | ||
259 | pixelFormat = defaultAlphaPixelFormat_; | ||
260 | else { | ||
261 | CCLOG(@"cocos2d: CCTexture2D: Using RGB565 texture since image has no alpha"); | ||
262 | pixelFormat = kCCTexture2DPixelFormat_RGB565; | ||
263 | } | ||
264 | } else { | ||
265 | // NOTE: No colorspace means a mask image | ||
266 | CCLOG(@"cocos2d: CCTexture2D: Using A8 texture since image is a mask"); | ||
267 | pixelFormat = kCCTexture2DPixelFormat_A8; | ||
268 | } | ||
269 | |||
270 | imageSize = CGSizeMake(CGImageGetWidth(CGImage), CGImageGetHeight(CGImage)); | ||
271 | |||
272 | // Create the bitmap graphics context | ||
273 | |||
274 | switch(pixelFormat) { | ||
275 | case kCCTexture2DPixelFormat_RGBA8888: | ||
276 | case kCCTexture2DPixelFormat_RGBA4444: | ||
277 | case kCCTexture2DPixelFormat_RGB5A1: | ||
278 | colorSpace = CGColorSpaceCreateDeviceRGB(); | ||
279 | data = malloc(POTHigh * POTWide * 4); | ||
280 | info = hasAlpha ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast; | ||
281 | // info = kCGImageAlphaPremultipliedLast; // issue #886. This patch breaks BMP images. | ||
282 | context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, 4 * POTWide, colorSpace, info | kCGBitmapByteOrder32Big); | ||
283 | CGColorSpaceRelease(colorSpace); | ||
284 | break; | ||
285 | |||
286 | case kCCTexture2DPixelFormat_RGB565: | ||
287 | colorSpace = CGColorSpaceCreateDeviceRGB(); | ||
288 | data = malloc(POTHigh * POTWide * 4); | ||
289 | info = kCGImageAlphaNoneSkipLast; | ||
290 | context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, 4 * POTWide, colorSpace, info | kCGBitmapByteOrder32Big); | ||
291 | CGColorSpaceRelease(colorSpace); | ||
292 | break; | ||
293 | case kCCTexture2DPixelFormat_A8: | ||
294 | data = malloc(POTHigh * POTWide); | ||
295 | info = kCGImageAlphaOnly; | ||
296 | context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide, NULL, info); | ||
297 | break; | ||
298 | default: | ||
299 | [NSException raise:NSInternalInconsistencyException format:@"Invalid pixel format"]; | ||
300 | } | ||
301 | |||
302 | |||
303 | CGContextClearRect(context, CGRectMake(0, 0, POTWide, POTHigh)); | ||
304 | CGContextTranslateCTM(context, 0, POTHigh - imageSize.height); | ||
305 | CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(CGImage), CGImageGetHeight(CGImage)), CGImage); | ||
306 | |||
307 | // Repack the pixel data into the right format | ||
308 | |||
309 | if(pixelFormat == kCCTexture2DPixelFormat_RGB565) { | ||
310 | //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" | ||
311 | tempData = malloc(POTHigh * POTWide * 2); | ||
312 | inPixel32 = (unsigned int*)data; | ||
313 | outPixel16 = (unsigned short*)tempData; | ||
314 | for(unsigned int i = 0; i < POTWide * POTHigh; ++i, ++inPixel32) | ||
315 | *outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0); | ||
316 | free(data); | ||
317 | data = tempData; | ||
318 | |||
319 | } | ||
320 | else if (pixelFormat == kCCTexture2DPixelFormat_RGBA4444) { | ||
321 | //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA" | ||
322 | tempData = malloc(POTHigh * POTWide * 2); | ||
323 | inPixel32 = (unsigned int*)data; | ||
324 | outPixel16 = (unsigned short*)tempData; | ||
325 | for(unsigned int i = 0; i < POTWide * POTHigh; ++i, ++inPixel32) | ||
326 | *outPixel16++ = | ||
327 | ((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R | ||
328 | ((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G | ||
329 | ((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B | ||
330 | ((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A | ||
331 | |||
332 | |||
333 | free(data); | ||
334 | data = tempData; | ||
335 | |||
336 | } | ||
337 | else if (pixelFormat == kCCTexture2DPixelFormat_RGB5A1) { | ||
338 | //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA" | ||
339 | tempData = malloc(POTHigh * POTWide * 2); | ||
340 | inPixel32 = (unsigned int*)data; | ||
341 | outPixel16 = (unsigned short*)tempData; | ||
342 | for(unsigned int i = 0; i < POTWide * POTHigh; ++i, ++inPixel32) | ||
343 | *outPixel16++ = | ||
344 | ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R | ||
345 | ((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G | ||
346 | ((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B | ||
347 | ((((*inPixel32 >> 24) & 0xFF) >> 7) << 0); // A | ||
348 | |||
349 | |||
350 | free(data); | ||
351 | data = tempData; | ||
352 | } | ||
353 | self = [self initWithData:data pixelFormat:pixelFormat pixelsWide:POTWide pixelsHigh:POTHigh contentSize:imageSize]; | ||
354 | |||
355 | // should be after calling super init | ||
356 | hasPremultipliedAlpha_ = (info == kCGImageAlphaPremultipliedLast || info == kCGImageAlphaPremultipliedFirst); | ||
357 | |||
358 | CGContextRelease(context); | ||
359 | [self releaseData:data]; | ||
360 | |||
361 | return self; | ||
362 | } | ||
363 | @end | ||
364 | |||
365 | #pragma mark - | ||
366 | #pragma mark CCTexture2D - Text | ||
367 | |||
368 | @implementation CCTexture2D (Text) | ||
369 | |||
370 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
371 | |||
372 | - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment lineBreakMode:(CCLineBreakMode)lineBreakMode font:(id)uifont | ||
373 | { | ||
374 | NSAssert( uifont, @"Invalid font"); | ||
375 | |||
376 | NSUInteger POTWide = ccNextPOT(dimensions.width); | ||
377 | NSUInteger POTHigh = ccNextPOT(dimensions.height); | ||
378 | unsigned char* data; | ||
379 | |||
380 | CGContextRef context; | ||
381 | CGColorSpaceRef colorSpace; | ||
382 | |||
383 | #if USE_TEXT_WITH_A8_TEXTURES | ||
384 | data = calloc(POTHigh, POTWide); | ||
385 | #else | ||
386 | data = calloc(POTHigh, POTWide * 2); | ||
387 | #endif | ||
388 | |||
389 | colorSpace = CGColorSpaceCreateDeviceGray(); | ||
390 | context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide, colorSpace, kCGImageAlphaNone); | ||
391 | CGColorSpaceRelease(colorSpace); | ||
392 | |||
393 | if( ! context ) { | ||
394 | free(data); | ||
395 | [self release]; | ||
396 | return nil; | ||
397 | } | ||
398 | |||
399 | CGContextSetGrayFillColor(context, 1.0f, 1.0f); | ||
400 | CGContextTranslateCTM(context, 0.0f, POTHigh); | ||
401 | CGContextScaleCTM(context, 1.0f, -1.0f); //NOTE: NSString draws in UIKit referential i.e. renders upside-down compared to CGBitmapContext referential | ||
402 | |||
403 | UIGraphicsPushContext(context); | ||
404 | |||
405 | // normal fonts | ||
406 | if( [uifont isKindOfClass:[UIFont class] ] ) | ||
407 | [string drawInRect:CGRectMake(0, 0, dimensions.width, dimensions.height) withFont:uifont lineBreakMode:lineBreakMode alignment:alignment]; | ||
408 | |||
409 | #if CC_FONT_LABEL_SUPPORT | ||
410 | else // ZFont class | ||
411 | [string drawInRect:CGRectMake(0, 0, dimensions.width, dimensions.height) withZFont:uifont lineBreakMode:lineBreakMode alignment:alignment]; | ||
412 | #endif | ||
413 | |||
414 | UIGraphicsPopContext(); | ||
415 | |||
416 | #if USE_TEXT_WITH_A8_TEXTURES | ||
417 | self = [self initWithData:data pixelFormat:kCCTexture2DPixelFormat_A8 pixelsWide:POTWide pixelsHigh:POTHigh contentSize:dimensions]; | ||
418 | |||
419 | #else // ! USE_TEXT_WITH_A8_TEXTURES | ||
420 | NSUInteger textureSize = POTWide*POTHigh; | ||
421 | unsigned short *la88_data = (unsigned short*)data; | ||
422 | for(int i = textureSize-1; i>=0; i--) //Convert A8 to AI88 | ||
423 | la88_data[i] = (data[i] << 8) | 0xff; | ||
424 | |||
425 | self = [self initWithData:data pixelFormat:kCCTexture2DPixelFormat_AI88 pixelsWide:POTWide pixelsHigh:POTHigh contentSize:dimensions]; | ||
426 | #endif // ! USE_TEXT_WITH_A8_TEXTURES | ||
427 | |||
428 | CGContextRelease(context); | ||
429 | [self releaseData:data]; | ||
430 | |||
431 | return self; | ||
432 | } | ||
433 | |||
434 | |||
435 | |||
436 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
437 | |||
438 | - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment attributedString:(NSAttributedString*)stringWithAttributes | ||
439 | { | ||
440 | NSAssert( stringWithAttributes, @"Invalid stringWithAttributes"); | ||
441 | |||
442 | NSUInteger POTWide = ccNextPOT(dimensions.width); | ||
443 | NSUInteger POTHigh = ccNextPOT(dimensions.height); | ||
444 | unsigned char* data; | ||
445 | |||
446 | NSSize realDimensions = [stringWithAttributes size]; | ||
447 | |||
448 | //Alignment | ||
449 | float xPadding = 0; | ||
450 | |||
451 | // Mac crashes if the width or height is 0 | ||
452 | if( realDimensions.width > 0 && realDimensions.height > 0 ) { | ||
453 | switch (alignment) { | ||
454 | case CCTextAlignmentLeft: xPadding = 0; break; | ||
455 | case CCTextAlignmentCenter: xPadding = (dimensions.width-realDimensions.width)/2.0f; break; | ||
456 | case CCTextAlignmentRight: xPadding = dimensions.width-realDimensions.width; break; | ||
457 | default: break; | ||
458 | } | ||
459 | |||
460 | //Disable antialias | ||
461 | [[NSGraphicsContext currentContext] setShouldAntialias:NO]; | ||
462 | |||
463 | NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(POTWide, POTHigh)]; | ||
464 | [image lockFocus]; | ||
465 | |||
466 | [stringWithAttributes drawAtPoint:NSMakePoint(xPadding, POTHigh-dimensions.height)]; // draw at offset position | ||
467 | |||
468 | NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect (0.0f, 0.0f, POTWide, POTHigh)]; | ||
469 | [image unlockFocus]; | ||
470 | |||
471 | data = (unsigned char*) [bitmap bitmapData]; //Use the same buffer to improve the performance. | ||
472 | |||
473 | NSUInteger textureSize = POTWide*POTHigh; | ||
474 | for(int i = 0; i<textureSize; i++) //Convert RGBA8888 to A8 | ||
475 | data[i] = data[i*4+3]; | ||
476 | |||
477 | data = [self keepData:data length:textureSize]; | ||
478 | self = [self initWithData:data pixelFormat:kCCTexture2DPixelFormat_A8 pixelsWide:POTWide pixelsHigh:POTHigh contentSize:dimensions]; | ||
479 | |||
480 | [bitmap release]; | ||
481 | [image release]; | ||
482 | |||
483 | } else { | ||
484 | [self release]; | ||
485 | return nil; | ||
486 | } | ||
487 | |||
488 | return self; | ||
489 | } | ||
490 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
491 | |||
492 | - (id) initWithString:(NSString*)string fontName:(NSString*)name fontSize:(CGFloat)size | ||
493 | { | ||
494 | CGSize dim; | ||
495 | |||
496 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
497 | id font; | ||
498 | font = [UIFont fontWithName:name size:size]; | ||
499 | if( font ) | ||
500 | dim = [string sizeWithFont:font]; | ||
501 | |||
502 | #if CC_FONT_LABEL_SUPPORT | ||
503 | if( ! font ){ | ||
504 | font = [[FontManager sharedManager] zFontWithName:name pointSize:size]; | ||
505 | if (font) | ||
506 | dim = [string sizeWithZFont:font]; | ||
507 | } | ||
508 | #endif // CC_FONT_LABEL_SUPPORT | ||
509 | |||
510 | if( ! font ) { | ||
511 | CCLOG(@"cocos2d: Unable to load font %@", name); | ||
512 | [self release]; | ||
513 | return nil; | ||
514 | } | ||
515 | |||
516 | return [self initWithString:string dimensions:dim alignment:CCTextAlignmentCenter lineBreakMode:UILineBreakModeWordWrap font:font]; | ||
517 | |||
518 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
519 | { | ||
520 | |||
521 | NSFont *font = [[NSFontManager sharedFontManager] | ||
522 | fontWithFamily:name | ||
523 | traits:NSUnboldFontMask | NSUnitalicFontMask | ||
524 | weight:0 | ||
525 | size:size]; | ||
526 | |||
527 | NSDictionary *dict = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]; | ||
528 | |||
529 | NSAttributedString *stringWithAttributes = [[[NSAttributedString alloc] initWithString:string attributes:dict] autorelease]; | ||
530 | |||
531 | dim = NSSizeToCGSize( [stringWithAttributes size] ); | ||
532 | |||
533 | return [self initWithString:string dimensions:dim alignment:CCTextAlignmentCenter attributedString:stringWithAttributes]; | ||
534 | } | ||
535 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
536 | |||
537 | } | ||
538 | |||
539 | - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment fontName:(NSString*)name fontSize:(CGFloat)size | ||
540 | { | ||
541 | return [self initWithString:string dimensions:dimensions alignment:alignment lineBreakMode:CCLineBreakModeWordWrap fontName:name fontSize:size]; | ||
542 | } | ||
543 | |||
544 | - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(CCTextAlignment)alignment lineBreakMode:(CCLineBreakMode)lineBreakMode fontName:(NSString*)name fontSize:(CGFloat)size | ||
545 | { | ||
546 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
547 | id uifont = nil; | ||
548 | |||
549 | uifont = [UIFont fontWithName:name size:size]; | ||
550 | |||
551 | #if CC_FONT_LABEL_SUPPORT | ||
552 | if( ! uifont ) | ||
553 | uifont = [[FontManager sharedManager] zFontWithName:name pointSize:size]; | ||
554 | #endif // CC_FONT_LABEL_SUPPORT | ||
555 | if( ! uifont ) { | ||
556 | CCLOG(@"cocos2d: Texture2d: Invalid Font: %@. Verify the .ttf name", name); | ||
557 | [self release]; | ||
558 | return nil; | ||
559 | } | ||
560 | |||
561 | return [self initWithString:string dimensions:dimensions alignment:alignment lineBreakMode:lineBreakMode font:uifont]; | ||
562 | |||
563 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
564 | |||
565 | NSAssert( lineBreakMode == CCLineBreakModeWordWrap, @"CCTexture2D: unsupported line break mode for Mac OS X"); | ||
566 | |||
567 | //String with attributes | ||
568 | NSAttributedString *stringWithAttributes = | ||
569 | [[[NSAttributedString alloc] initWithString:string | ||
570 | attributes:[NSDictionary dictionaryWithObject:[[NSFontManager sharedFontManager] | ||
571 | fontWithFamily:name | ||
572 | traits:NSUnboldFontMask | NSUnitalicFontMask | ||
573 | weight:0 | ||
574 | size:size] | ||
575 | forKey:NSFontAttributeName] | ||
576 | ] | ||
577 | autorelease]; | ||
578 | |||
579 | return [self initWithString:string dimensions:dimensions alignment:alignment attributedString:stringWithAttributes]; | ||
580 | |||
581 | #endif // Mac | ||
582 | } | ||
583 | @end | ||
584 | |||
585 | #pragma mark - | ||
586 | #pragma mark CCTexture2D - PVRSupport | ||
587 | |||
588 | @implementation CCTexture2D (PVRSupport) | ||
589 | |||
590 | // By default PVR images are treated as if they don't have the alpha channel premultiplied | ||
591 | static BOOL PVRHaveAlphaPremultiplied_ = NO; | ||
592 | |||
593 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
594 | -(id) initWithPVRTCData: (const void*)data level:(int)level bpp:(int)bpp hasAlpha:(BOOL)hasAlpha length:(int)length pixelFormat:(CCTexture2DPixelFormat)pixelFormat | ||
595 | { | ||
596 | // GLint saveName; | ||
597 | |||
598 | if( ! [[CCConfiguration sharedConfiguration] supportsPVRTC] ) { | ||
599 | CCLOG(@"cocos2d: WARNING: PVRTC images is not supported"); | ||
600 | [self release]; | ||
601 | return nil; | ||
602 | } | ||
603 | |||
604 | if((self = [super init])) { | ||
605 | glGenTextures(1, &name_); | ||
606 | glBindTexture(GL_TEXTURE_2D, name_); | ||
607 | |||
608 | [self setAntiAliasTexParameters]; | ||
609 | |||
610 | GLenum format; | ||
611 | GLsizei size = length * length * bpp / 8; | ||
612 | if(hasAlpha) | ||
613 | format = (bpp == 4) ? GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; | ||
614 | else | ||
615 | format = (bpp == 4) ? GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG : GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; | ||
616 | |||
617 | if(size < 32) | ||
618 | size = 32; | ||
619 | |||
620 | glCompressedTexImage2D(GL_TEXTURE_2D, level, format, length, length, 0, size, data); | ||
621 | |||
622 | size_ = CGSizeMake(length, length); | ||
623 | width_ = length; | ||
624 | height_ = length; | ||
625 | maxS_ = 1.0f; | ||
626 | maxT_ = 1.0f; | ||
627 | hasPremultipliedAlpha_ = PVRHaveAlphaPremultiplied_; | ||
628 | format_ = pixelFormat; | ||
629 | } | ||
630 | return self; | ||
631 | } | ||
632 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
633 | |||
634 | -(id) initWithPVRFile: (NSString*) file | ||
635 | { | ||
636 | if( (self = [super init]) ) { | ||
637 | CCTexturePVR *pvr = [[CCTexturePVR alloc] initWithContentsOfFile:file]; | ||
638 | if( pvr ) { | ||
639 | pvr.retainName = YES; // don't dealloc texture on release | ||
640 | |||
641 | name_ = pvr.name; // texture id | ||
642 | maxS_ = 1; // only POT texture are supported | ||
643 | maxT_ = 1; | ||
644 | width_ = pvr.width; | ||
645 | height_ = pvr.height; | ||
646 | size_ = CGSizeMake(width_, height_); | ||
647 | hasPremultipliedAlpha_ = PVRHaveAlphaPremultiplied_; | ||
648 | format_ = pvr.format; | ||
649 | |||
650 | [pvr release]; | ||
651 | |||
652 | [self setAntiAliasTexParameters]; | ||
653 | } else { | ||
654 | |||
655 | CCLOG(@"cocos2d: Couldn't load PVR image: %@", file); | ||
656 | [self release]; | ||
657 | return nil; | ||
658 | } | ||
659 | } | ||
660 | return self; | ||
661 | } | ||
662 | |||
663 | +(void) PVRImagesHavePremultipliedAlpha:(BOOL)haveAlphaPremultiplied | ||
664 | { | ||
665 | PVRHaveAlphaPremultiplied_ = haveAlphaPremultiplied; | ||
666 | } | ||
667 | @end | ||
668 | |||
669 | #pragma mark - | ||
670 | #pragma mark CCTexture2D - Drawing | ||
671 | |||
672 | @implementation CCTexture2D (Drawing) | ||
673 | |||
674 | - (void) drawAtPoint:(CGPoint)point | ||
675 | { | ||
676 | GLfloat coordinates[] = { 0.0f, maxT_, | ||
677 | maxS_, maxT_, | ||
678 | 0.0f, 0.0f, | ||
679 | maxS_, 0.0f }; | ||
680 | GLfloat width = (GLfloat)width_ * maxS_, | ||
681 | height = (GLfloat)height_ * maxT_; | ||
682 | |||
683 | GLfloat vertices[] = { point.x, point.y, 0.0f, | ||
684 | width + point.x, point.y, 0.0f, | ||
685 | point.x, height + point.y, 0.0f, | ||
686 | width + point.x, height + point.y, 0.0f }; | ||
687 | |||
688 | glBindTexture(GL_TEXTURE_2D, name_); | ||
689 | glVertexPointer(3, GL_FLOAT, 0, vertices); | ||
690 | glTexCoordPointer(2, GL_FLOAT, 0, coordinates); | ||
691 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
692 | } | ||
693 | |||
694 | |||
695 | - (void) drawInRect:(CGRect)rect | ||
696 | { | ||
697 | GLfloat coordinates[] = { 0.0f, maxT_, | ||
698 | maxS_, maxT_, | ||
699 | 0.0f, 0.0f, | ||
700 | maxS_, 0.0f }; | ||
701 | GLfloat vertices[] = { rect.origin.x, rect.origin.y, /*0.0f,*/ | ||
702 | rect.origin.x + rect.size.width, rect.origin.y, /*0.0f,*/ | ||
703 | rect.origin.x, rect.origin.y + rect.size.height, /*0.0f,*/ | ||
704 | rect.origin.x + rect.size.width, rect.origin.y + rect.size.height, /*0.0f*/ }; | ||
705 | |||
706 | glBindTexture(GL_TEXTURE_2D, name_); | ||
707 | glVertexPointer(2, GL_FLOAT, 0, vertices); | ||
708 | glTexCoordPointer(2, GL_FLOAT, 0, coordinates); | ||
709 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
710 | } | ||
711 | |||
712 | @end | ||
713 | |||
714 | |||
715 | #pragma mark - | ||
716 | #pragma mark CCTexture2D - GLFilter | ||
717 | |||
718 | // | ||
719 | // Use to apply MIN/MAG filter | ||
720 | // | ||
721 | @implementation CCTexture2D (GLFilter) | ||
722 | |||
723 | -(void) generateMipmap | ||
724 | { | ||
725 | NSAssert( width_ == ccNextPOT(width_) && height_ == ccNextPOT(height_), @"Mimpap texture only works in POT textures"); | ||
726 | glBindTexture( GL_TEXTURE_2D, name_ ); | ||
727 | ccglGenerateMipmap(GL_TEXTURE_2D); | ||
728 | } | ||
729 | |||
730 | -(void) setTexParameters: (ccTexParams*) texParams | ||
731 | { | ||
732 | NSAssert( (width_ == ccNextPOT(width_) && height_ == ccNextPOT(height_)) || | ||
733 | (texParams->wrapS == GL_CLAMP_TO_EDGE && texParams->wrapT == GL_CLAMP_TO_EDGE), | ||
734 | @"GL_CLAMP_TO_EDGE should be used in NPOT textures"); | ||
735 | glBindTexture( GL_TEXTURE_2D, name_ ); | ||
736 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texParams->minFilter ); | ||
737 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texParams->magFilter ); | ||
738 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texParams->wrapS ); | ||
739 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texParams->wrapT ); | ||
740 | } | ||
741 | |||
742 | -(void) setAliasTexParameters | ||
743 | { | ||
744 | ccTexParams texParams = { GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE }; | ||
745 | [self setTexParameters: &texParams]; | ||
746 | } | ||
747 | |||
748 | -(void) setAntiAliasTexParameters | ||
749 | { | ||
750 | ccTexParams texParams = { GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE }; | ||
751 | [self setTexParameters: &texParams]; | ||
752 | } | ||
753 | @end | ||
754 | |||
755 | |||
756 | #pragma mark - | ||
757 | #pragma mark CCTexture2D - Pixel Format | ||
758 | |||
759 | // | ||
760 | // Texture options for images that contains alpha | ||
761 | // | ||
762 | @implementation CCTexture2D (PixelFormat) | ||
763 | +(void) setDefaultAlphaPixelFormat:(CCTexture2DPixelFormat)format | ||
764 | { | ||
765 | defaultAlphaPixelFormat_ = format; | ||
766 | } | ||
767 | |||
768 | +(CCTexture2DPixelFormat) defaultAlphaPixelFormat | ||
769 | { | ||
770 | return defaultAlphaPixelFormat_; | ||
771 | } | ||
772 | |||
773 | -(NSUInteger) bitsPerPixelForFormat | ||
774 | { | ||
775 | NSUInteger ret=0; | ||
776 | |||
777 | switch (format_) { | ||
778 | case kCCTexture2DPixelFormat_RGBA8888: | ||
779 | ret = 32; | ||
780 | break; | ||
781 | case kCCTexture2DPixelFormat_RGB565: | ||
782 | ret = 16; | ||
783 | break; | ||
784 | case kCCTexture2DPixelFormat_A8: | ||
785 | ret = 8; | ||
786 | break; | ||
787 | case kCCTexture2DPixelFormat_RGBA4444: | ||
788 | ret = 16; | ||
789 | break; | ||
790 | case kCCTexture2DPixelFormat_RGB5A1: | ||
791 | ret = 16; | ||
792 | break; | ||
793 | case kCCTexture2DPixelFormat_PVRTC4: | ||
794 | ret = 4; | ||
795 | break; | ||
796 | case kCCTexture2DPixelFormat_PVRTC2: | ||
797 | ret = 2; | ||
798 | break; | ||
799 | case kCCTexture2DPixelFormat_I8: | ||
800 | ret = 8; | ||
801 | break; | ||
802 | case kCCTexture2DPixelFormat_AI88: | ||
803 | ret = 16; | ||
804 | break; | ||
805 | default: | ||
806 | ret = -1; | ||
807 | NSAssert1(NO , @"bitsPerPixelForFormat: %ld, unrecognised pixel format", (long)format_); | ||
808 | CCLOG(@"bitsPerPixelForFormat: %ld, cannot give useful result", (long)format_); | ||
809 | break; | ||
810 | } | ||
811 | return ret; | ||
812 | } | ||
813 | @end | ||
814 | |||
diff --git a/libs/cocos2d/CCTextureAtlas.h b/libs/cocos2d/CCTextureAtlas.h new file mode 100755 index 0000000..f70bb54 --- /dev/null +++ b/libs/cocos2d/CCTextureAtlas.h | |||
@@ -0,0 +1,147 @@ | |||
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 | #import "CCTexture2D.h" | ||
28 | #import "ccTypes.h" | ||
29 | #import "ccConfig.h" | ||
30 | |||
31 | /** A class that implements a Texture Atlas. | ||
32 | Supported features: | ||
33 | * The atlas file can be a PVRTC, PNG or any other fomrat supported by Texture2D | ||
34 | * Quads can be udpated in runtime | ||
35 | * Quads can be added in runtime | ||
36 | * Quads can be removed in runtime | ||
37 | * Quads can be re-ordered in runtime | ||
38 | * The TextureAtlas capacity can be increased or decreased in runtime | ||
39 | * OpenGL component: V3F, C4B, T2F. | ||
40 | The quads are rendered using an OpenGL ES VBO. | ||
41 | To render the quads using an interleaved vertex array list, you should modify the ccConfig.h file | ||
42 | */ | ||
43 | @interface CCTextureAtlas : NSObject | ||
44 | { | ||
45 | NSUInteger totalQuads_; | ||
46 | NSUInteger capacity_; | ||
47 | ccV3F_C4B_T2F_Quad *quads_; // quads to be rendered | ||
48 | GLushort *indices_; | ||
49 | CCTexture2D *texture_; | ||
50 | #if CC_USES_VBO | ||
51 | GLuint buffersVBO_[2]; //0: vertex 1: indices | ||
52 | BOOL dirty_; //indicates whether or not the array buffer of the VBO needs to be updated | ||
53 | #endif // CC_USES_VBO | ||
54 | } | ||
55 | |||
56 | /** quantity of quads that are going to be drawn */ | ||
57 | @property (nonatomic,readonly) NSUInteger totalQuads; | ||
58 | /** quantity of quads that can be stored with the current texture atlas size */ | ||
59 | @property (nonatomic,readonly) NSUInteger capacity; | ||
60 | /** Texture of the texture atlas */ | ||
61 | @property (nonatomic,retain) CCTexture2D *texture; | ||
62 | /** Quads that are going to be rendered */ | ||
63 | @property (nonatomic,readwrite) ccV3F_C4B_T2F_Quad *quads; | ||
64 | |||
65 | /** creates a TextureAtlas with an filename and with an initial capacity for Quads. | ||
66 | * The TextureAtlas capacity can be increased in runtime. | ||
67 | */ | ||
68 | +(id) textureAtlasWithFile:(NSString*)file capacity:(NSUInteger)capacity; | ||
69 | |||
70 | /** initializes a TextureAtlas with a filename and with a certain capacity for Quads. | ||
71 | * The TextureAtlas capacity can be increased in runtime. | ||
72 | * | ||
73 | * WARNING: Do not reinitialize the TextureAtlas because it will leak memory (issue #706) | ||
74 | */ | ||
75 | -(id) initWithFile: (NSString*) file capacity:(NSUInteger)capacity; | ||
76 | |||
77 | /** creates a TextureAtlas with a previously initialized Texture2D object, and | ||
78 | * with an initial capacity for n Quads. | ||
79 | * The TextureAtlas capacity can be increased in runtime. | ||
80 | */ | ||
81 | +(id) textureAtlasWithTexture:(CCTexture2D *)tex capacity:(NSUInteger)capacity; | ||
82 | |||
83 | /** initializes a TextureAtlas with a previously initialized Texture2D object, and | ||
84 | * with an initial capacity for Quads. | ||
85 | * The TextureAtlas capacity can be increased in runtime. | ||
86 | * | ||
87 | * WARNING: Do not reinitialize the TextureAtlas because it will leak memory (issue #706) | ||
88 | */ | ||
89 | -(id) initWithTexture:(CCTexture2D *)tex capacity:(NSUInteger)capacity; | ||
90 | |||
91 | /** updates a Quad (texture, vertex and color) at a certain index | ||
92 | * index must be between 0 and the atlas capacity - 1 | ||
93 | @since v0.8 | ||
94 | */ | ||
95 | -(void) updateQuad:(ccV3F_C4B_T2F_Quad*)quad atIndex:(NSUInteger)index; | ||
96 | |||
97 | /** Inserts a Quad (texture, vertex and color) at a certain index | ||
98 | index must be between 0 and the atlas capacity - 1 | ||
99 | @since v0.8 | ||
100 | */ | ||
101 | -(void) insertQuad:(ccV3F_C4B_T2F_Quad*)quad atIndex:(NSUInteger)index; | ||
102 | |||
103 | /** Removes the quad that is located at a certain index and inserts it at a new index | ||
104 | This operation is faster than removing and inserting in a quad in 2 different steps | ||
105 | @since v0.7.2 | ||
106 | */ | ||
107 | -(void) insertQuadFromIndex:(NSUInteger)fromIndex atIndex:(NSUInteger)newIndex; | ||
108 | |||
109 | /** removes a quad at a given index number. | ||
110 | The capacity remains the same, but the total number of quads to be drawn is reduced in 1 | ||
111 | @since v0.7.2 | ||
112 | */ | ||
113 | -(void) removeQuadAtIndex:(NSUInteger) index; | ||
114 | |||
115 | /** removes all Quads. | ||
116 | The TextureAtlas capacity remains untouched. No memory is freed. | ||
117 | The total number of quads to be drawn will be 0 | ||
118 | @since v0.7.2 | ||
119 | */ | ||
120 | -(void) removeAllQuads; | ||
121 | |||
122 | /** resize the capacity of the CCTextureAtlas. | ||
123 | * The new capacity can be lower or higher than the current one | ||
124 | * It returns YES if the resize was successful. | ||
125 | * If it fails to resize the capacity it will return NO with a new capacity of 0. | ||
126 | */ | ||
127 | -(BOOL) resizeCapacity: (NSUInteger) n; | ||
128 | |||
129 | |||
130 | /** draws n quads | ||
131 | * n can't be greater than the capacity of the Atlas | ||
132 | */ | ||
133 | -(void) drawNumberOfQuads: (NSUInteger) n; | ||
134 | |||
135 | |||
136 | /** draws n quads from an index (offset). | ||
137 | n + start can't be greater than the capacity of the atlas | ||
138 | |||
139 | @since v1.0 | ||
140 | */ | ||
141 | -(void) drawNumberOfQuads: (NSUInteger) n fromIndex: (NSUInteger) start; | ||
142 | |||
143 | /** draws all the Atlas's Quads | ||
144 | */ | ||
145 | -(void) drawQuads; | ||
146 | |||
147 | @end | ||
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 | ||
diff --git a/libs/cocos2d/CCTextureCache.h b/libs/cocos2d/CCTextureCache.h new file mode 100755 index 0000000..7084793 --- /dev/null +++ b/libs/cocos2d/CCTextureCache.h | |||
@@ -0,0 +1,149 @@ | |||
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 | #import <Availability.h> | ||
28 | |||
29 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
30 | #import <CoreGraphics/CGImage.h> | ||
31 | #endif | ||
32 | |||
33 | #import <Foundation/Foundation.h> | ||
34 | |||
35 | @class CCTexture2D; | ||
36 | |||
37 | /** Singleton that handles the loading of textures | ||
38 | * Once the texture is loaded, the next time it will return | ||
39 | * a reference of the previously loaded texture reducing GPU & CPU memory | ||
40 | */ | ||
41 | @interface CCTextureCache : NSObject | ||
42 | { | ||
43 | NSMutableDictionary *textures_; | ||
44 | NSLock *dictLock_; | ||
45 | NSLock *contextLock_; | ||
46 | } | ||
47 | |||
48 | /** Retruns ths shared instance of the cache */ | ||
49 | + (CCTextureCache *) sharedTextureCache; | ||
50 | |||
51 | /** purges the cache. It releases the retained instance. | ||
52 | @since v0.99.0 | ||
53 | */ | ||
54 | +(void)purgeSharedTextureCache; | ||
55 | |||
56 | |||
57 | /** Returns a Texture2D object given an file image | ||
58 | * If the file image was not previously loaded, it will create a new CCTexture2D | ||
59 | * object and it will return it. It will use the filename as a key. | ||
60 | * Otherwise it will return a reference of a previosly loaded image. | ||
61 | * Supported image extensions: .png, .bmp, .tiff, .jpeg, .pvr, .gif | ||
62 | */ | ||
63 | -(CCTexture2D*) addImage: (NSString*) fileimage; | ||
64 | |||
65 | /** Returns a Texture2D object given a file image | ||
66 | * If the file image was not previously loaded, it will create a new CCTexture2D object and it will return it. | ||
67 | * Otherwise it will load a texture in a new thread, and when the image is loaded, the callback will be called with the Texture2D as a parameter. | ||
68 | * The callback will be called from the main thread, so it is safe to create any cocos2d object from the callback. | ||
69 | * Supported image extensions: .png, .bmp, .tiff, .jpeg, .pvr, .gif | ||
70 | * @since v0.8 | ||
71 | */ | ||
72 | -(void) addImageAsync:(NSString*) filename target:(id)target selector:(SEL)selector; | ||
73 | |||
74 | /** Returns a Texture2D object given an CGImageRef image | ||
75 | * If the image was not previously loaded, it will create a new CCTexture2D object and it will return it. | ||
76 | * Otherwise it will return a reference of a previously loaded image | ||
77 | * The "key" parameter will be used as the "key" for the cache. | ||
78 | * If "key" is nil, then a new texture will be created each time. | ||
79 | * @since v0.8 | ||
80 | */ | ||
81 | -(CCTexture2D*) addCGImage: (CGImageRef) image forKey: (NSString *)key; | ||
82 | |||
83 | /** Returns an already created texture. Returns nil if the texture doesn't exist. | ||
84 | @since v0.99.5 | ||
85 | */ | ||
86 | -(CCTexture2D *) textureForKey:(NSString *)key; | ||
87 | |||
88 | /** Purges the dictionary of loaded textures. | ||
89 | * Call this method if you receive the "Memory Warning" | ||
90 | * In the short term: it will free some resources preventing your app from being killed | ||
91 | * In the medium term: it will allocate more resources | ||
92 | * In the long term: it will be the same | ||
93 | */ | ||
94 | -(void) removeAllTextures; | ||
95 | |||
96 | /** Removes unused textures | ||
97 | * Textures that have a retain count of 1 will be deleted | ||
98 | * It is convinient to call this method after when starting a new Scene | ||
99 | * @since v0.8 | ||
100 | */ | ||
101 | -(void) removeUnusedTextures; | ||
102 | |||
103 | /** Deletes a texture from the cache given a texture | ||
104 | */ | ||
105 | -(void) removeTexture: (CCTexture2D*) tex; | ||
106 | |||
107 | /** Deletes a texture from the cache given a its key name | ||
108 | @since v0.99.4 | ||
109 | */ | ||
110 | -(void) removeTextureForKey: (NSString*) textureKeyName; | ||
111 | |||
112 | @end | ||
113 | |||
114 | |||
115 | @interface CCTextureCache (PVRSupport) | ||
116 | |||
117 | /** Returns a Texture2D object given an PVRTC RAW filename | ||
118 | * If the file image was not previously loaded, it will create a new CCTexture2D | ||
119 | * object and it will return it. Otherwise it will return a reference of a previosly loaded image | ||
120 | * | ||
121 | * It can only load square images: width == height, and it must be a power of 2 (128,256,512...) | ||
122 | * bpp can only be 2 or 4. 2 means more compression but lower quality. | ||
123 | * hasAlpha: whether or not the image contains alpha channel | ||
124 | * | ||
125 | * IMPORTANT: This method is only defined on iOS. It is not supported on the Mac version. | ||
126 | */ | ||
127 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
128 | -(CCTexture2D*) addPVRTCImage:(NSString*)fileimage bpp:(int)bpp hasAlpha:(BOOL)alpha width:(int)w; | ||
129 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
130 | |||
131 | /** Returns a Texture2D object given an PVR filename. | ||
132 | * If the file image was not previously loaded, it will create a new CCTexture2D | ||
133 | * object and it will return it. Otherwise it will return a reference of a previosly loaded image | ||
134 | * | ||
135 | */ | ||
136 | -(CCTexture2D*) addPVRImage:(NSString*) filename; | ||
137 | |||
138 | @end | ||
139 | |||
140 | |||
141 | @interface CCTextureCache (Debug) | ||
142 | /** Output to CCLOG the current contents of this CCTextureCache | ||
143 | * This will attempt to calculate the size of each texture, and the total texture memory in use | ||
144 | * | ||
145 | * @since v1.0 | ||
146 | */ | ||
147 | -(void) dumpCachedTextureInfo; | ||
148 | |||
149 | @end | ||
diff --git a/libs/cocos2d/CCTextureCache.m b/libs/cocos2d/CCTextureCache.m new file mode 100755 index 0000000..080770a --- /dev/null +++ b/libs/cocos2d/CCTextureCache.m | |||
@@ -0,0 +1,498 @@ | |||
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 | #import <Availability.h> | ||
28 | |||
29 | #import "Platforms/CCGL.h" | ||
30 | #import "CCTextureCache.h" | ||
31 | #import "CCTexture2D.h" | ||
32 | #import "CCTexturePVR.h" | ||
33 | #import "ccMacros.h" | ||
34 | #import "CCConfiguration.h" | ||
35 | #import "Support/CCFileUtils.h" | ||
36 | #import "CCDirector.h" | ||
37 | #import "ccConfig.h" | ||
38 | |||
39 | // needed for CCCallFuncO in Mac-display_link version | ||
40 | #import "CCActionManager.h" | ||
41 | #import "CCActionInstant.h" | ||
42 | |||
43 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
44 | static EAGLContext *auxGLcontext = nil; | ||
45 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
46 | static NSOpenGLContext *auxGLcontext = nil; | ||
47 | #endif | ||
48 | |||
49 | |||
50 | @interface CCAsyncObject : NSObject | ||
51 | { | ||
52 | SEL selector_; | ||
53 | id target_; | ||
54 | id data_; | ||
55 | } | ||
56 | @property (readwrite,assign) SEL selector; | ||
57 | @property (readwrite,retain) id target; | ||
58 | @property (readwrite,retain) id data; | ||
59 | @end | ||
60 | |||
61 | @implementation CCAsyncObject | ||
62 | @synthesize selector = selector_; | ||
63 | @synthesize target = target_; | ||
64 | @synthesize data = data_; | ||
65 | - (void) dealloc | ||
66 | { | ||
67 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
68 | [target_ release]; | ||
69 | [data_ release]; | ||
70 | [super dealloc]; | ||
71 | } | ||
72 | @end | ||
73 | |||
74 | |||
75 | @implementation CCTextureCache | ||
76 | |||
77 | #pragma mark TextureCache - Alloc, Init & Dealloc | ||
78 | static CCTextureCache *sharedTextureCache; | ||
79 | |||
80 | + (CCTextureCache *)sharedTextureCache | ||
81 | { | ||
82 | if (!sharedTextureCache) | ||
83 | sharedTextureCache = [[CCTextureCache alloc] init]; | ||
84 | |||
85 | return sharedTextureCache; | ||
86 | } | ||
87 | |||
88 | +(id)alloc | ||
89 | { | ||
90 | NSAssert(sharedTextureCache == nil, @"Attempted to allocate a second instance of a singleton."); | ||
91 | return [super alloc]; | ||
92 | } | ||
93 | |||
94 | +(void)purgeSharedTextureCache | ||
95 | { | ||
96 | [sharedTextureCache release]; | ||
97 | sharedTextureCache = nil; | ||
98 | } | ||
99 | |||
100 | -(id) init | ||
101 | { | ||
102 | if( (self=[super init]) ) { | ||
103 | textures_ = [[NSMutableDictionary dictionaryWithCapacity: 10] retain]; | ||
104 | dictLock_ = [[NSLock alloc] init]; | ||
105 | contextLock_ = [[NSLock alloc] init]; | ||
106 | } | ||
107 | |||
108 | return self; | ||
109 | } | ||
110 | |||
111 | - (NSString*) description | ||
112 | { | ||
113 | return [NSString stringWithFormat:@"<%@ = %08X | num of textures = %i | keys: %@>", | ||
114 | [self class], | ||
115 | self, | ||
116 | [textures_ count], | ||
117 | [textures_ allKeys] | ||
118 | ]; | ||
119 | |||
120 | } | ||
121 | |||
122 | -(void) dealloc | ||
123 | { | ||
124 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
125 | |||
126 | [textures_ release]; | ||
127 | [dictLock_ release]; | ||
128 | [contextLock_ release]; | ||
129 | [auxGLcontext release]; | ||
130 | auxGLcontext = nil; | ||
131 | sharedTextureCache = nil; | ||
132 | [super dealloc]; | ||
133 | } | ||
134 | |||
135 | #pragma mark TextureCache - Add Images | ||
136 | |||
137 | -(void) addImageWithAsyncObject:(CCAsyncObject*)async | ||
138 | { | ||
139 | NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; | ||
140 | |||
141 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
142 | // textures will be created on the main OpenGL context | ||
143 | // it seems that in SDK 2.2.x there can't be 2 threads creating textures at the same time | ||
144 | // the lock is used for this purpose: issue #472 | ||
145 | [contextLock_ lock]; | ||
146 | if( auxGLcontext == nil ) { | ||
147 | auxGLcontext = [[EAGLContext alloc] | ||
148 | initWithAPI:kEAGLRenderingAPIOpenGLES1 | ||
149 | sharegroup:[[[[CCDirector sharedDirector] openGLView] context] sharegroup]]; | ||
150 | |||
151 | if( ! auxGLcontext ) | ||
152 | CCLOG(@"cocos2d: TextureCache: Could not create EAGL context"); | ||
153 | } | ||
154 | |||
155 | if( [EAGLContext setCurrentContext:auxGLcontext] ) { | ||
156 | |||
157 | // load / create the texture | ||
158 | CCTexture2D *tex = [self addImage:async.data]; | ||
159 | |||
160 | // The callback will be executed on the main thread | ||
161 | [async.target performSelectorOnMainThread:async.selector withObject:tex waitUntilDone:NO]; | ||
162 | |||
163 | [EAGLContext setCurrentContext:nil]; | ||
164 | } else { | ||
165 | CCLOG(@"cocos2d: TetureCache: EAGLContext error"); | ||
166 | } | ||
167 | [contextLock_ unlock]; | ||
168 | |||
169 | [autoreleasepool release]; | ||
170 | |||
171 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
172 | |||
173 | [contextLock_ lock]; | ||
174 | if( auxGLcontext == nil ) { | ||
175 | |||
176 | MacGLView *view = [[CCDirector sharedDirector] openGLView]; | ||
177 | |||
178 | NSOpenGLPixelFormat *pf = [view pixelFormat]; | ||
179 | NSOpenGLContext *share = [view openGLContext]; | ||
180 | |||
181 | auxGLcontext = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:share]; | ||
182 | |||
183 | if( ! auxGLcontext ) | ||
184 | CCLOG(@"cocos2d: TextureCache: Could not create NSOpenGLContext"); | ||
185 | } | ||
186 | |||
187 | [auxGLcontext makeCurrentContext]; | ||
188 | |||
189 | // load / create the texture | ||
190 | CCTexture2D *tex = [self addImage:async.data]; | ||
191 | |||
192 | #if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
193 | id action = [CCCallFuncO actionWithTarget:async.target selector:async.selector object:tex]; | ||
194 | [[CCActionManager sharedManager] addAction:action target:async.target paused:NO]; | ||
195 | #else | ||
196 | // The callback will be executed on the main thread | ||
197 | [async.target performSelector:async.selector | ||
198 | onThread:[[CCDirector sharedDirector] runningThread] | ||
199 | withObject:tex | ||
200 | waitUntilDone:NO]; | ||
201 | #endif | ||
202 | |||
203 | |||
204 | [NSOpenGLContext clearCurrentContext]; | ||
205 | |||
206 | [contextLock_ unlock]; | ||
207 | |||
208 | [autoreleasepool release]; | ||
209 | |||
210 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
211 | } | ||
212 | |||
213 | -(void) addImageAsync: (NSString*)path target:(id)target selector:(SEL)selector | ||
214 | { | ||
215 | NSAssert(path != nil, @"TextureCache: fileimage MUST not be nill"); | ||
216 | |||
217 | // optimization | ||
218 | |||
219 | CCTexture2D * tex; | ||
220 | |||
221 | path = ccRemoveHDSuffixFromFile(path); | ||
222 | |||
223 | if( (tex=[textures_ objectForKey: path] ) ) { | ||
224 | [target performSelector:selector withObject:tex]; | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | // schedule the load | ||
229 | |||
230 | CCAsyncObject *asyncObject = [[CCAsyncObject alloc] init]; | ||
231 | asyncObject.selector = selector; | ||
232 | asyncObject.target = target; | ||
233 | asyncObject.data = path; | ||
234 | |||
235 | [NSThread detachNewThreadSelector:@selector(addImageWithAsyncObject:) toTarget:self withObject:asyncObject]; | ||
236 | [asyncObject release]; | ||
237 | } | ||
238 | |||
239 | -(CCTexture2D*) addImage: (NSString*) path | ||
240 | { | ||
241 | NSAssert(path != nil, @"TextureCache: fileimage MUST not be nill"); | ||
242 | |||
243 | CCTexture2D * tex = nil; | ||
244 | |||
245 | // MUTEX: | ||
246 | // Needed since addImageAsync calls this method from a different thread | ||
247 | [dictLock_ lock]; | ||
248 | |||
249 | // remove possible -HD suffix to prevent caching the same image twice (issue #1040) | ||
250 | path = ccRemoveHDSuffixFromFile( path ); | ||
251 | |||
252 | tex=[textures_ objectForKey: path]; | ||
253 | |||
254 | if( ! tex ) { | ||
255 | |||
256 | NSString *lowerCase = [path lowercaseString]; | ||
257 | // all images are handled by UIImage except PVR extension that is handled by our own handler | ||
258 | |||
259 | if ( [lowerCase hasSuffix:@".pvr"] || [lowerCase hasSuffix:@".pvr.gz"] || [lowerCase hasSuffix:@".pvr.ccz"] ) | ||
260 | tex = [self addPVRImage:path]; | ||
261 | |||
262 | // Only iPhone | ||
263 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
264 | |||
265 | // Issue #886: TEMPORARY FIX FOR TRANSPARENT JPEGS IN IOS4 | ||
266 | else if ( ( [[CCConfiguration sharedConfiguration] OSVersion] >= kCCiOSVersion_4_0) && | ||
267 | ( [lowerCase hasSuffix:@".jpg"] || [lowerCase hasSuffix:@".jpeg"] ) | ||
268 | ) { | ||
269 | // convert jpg to png before loading the texture | ||
270 | |||
271 | NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ]; | ||
272 | |||
273 | UIImage *jpg = [[UIImage alloc] initWithContentsOfFile:fullpath]; | ||
274 | UIImage *png = [[UIImage alloc] initWithData:UIImagePNGRepresentation(jpg)]; | ||
275 | tex = [ [CCTexture2D alloc] initWithImage: png ]; | ||
276 | [png release]; | ||
277 | [jpg release]; | ||
278 | |||
279 | if( tex ) | ||
280 | [textures_ setObject: tex forKey:path]; | ||
281 | else | ||
282 | CCLOG(@"cocos2d: Couldn't add image:%@ in CCTextureCache", path); | ||
283 | |||
284 | // autorelease prevents possible crash in multithreaded environments | ||
285 | [tex autorelease]; | ||
286 | } | ||
287 | |||
288 | else { | ||
289 | |||
290 | // prevents overloading the autorelease pool | ||
291 | NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ]; | ||
292 | |||
293 | UIImage *image = [ [UIImage alloc] initWithContentsOfFile: fullpath ]; | ||
294 | tex = [ [CCTexture2D alloc] initWithImage: image ]; | ||
295 | [image release]; | ||
296 | |||
297 | if( tex ) | ||
298 | [textures_ setObject: tex forKey:path]; | ||
299 | else | ||
300 | CCLOG(@"cocos2d: Couldn't add image:%@ in CCTextureCache", path); | ||
301 | |||
302 | // autorelease prevents possible crash in multithreaded environments | ||
303 | [tex autorelease]; | ||
304 | } | ||
305 | |||
306 | // Only in Mac | ||
307 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
308 | else { | ||
309 | NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ]; | ||
310 | |||
311 | NSData *data = [[NSData alloc] initWithContentsOfFile:fullpath]; | ||
312 | NSBitmapImageRep *image = [[NSBitmapImageRep alloc] initWithData:data]; | ||
313 | tex = [ [CCTexture2D alloc] initWithImage:[image CGImage]]; | ||
314 | |||
315 | [data release]; | ||
316 | [image release]; | ||
317 | |||
318 | if( tex ) | ||
319 | [textures_ setObject: tex forKey:path]; | ||
320 | else | ||
321 | CCLOG(@"cocos2d: Couldn't add image:%@ in CCTextureCache", path); | ||
322 | |||
323 | // autorelease prevents possible crash in multithreaded environments | ||
324 | [tex autorelease]; | ||
325 | } | ||
326 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
327 | |||
328 | } | ||
329 | |||
330 | [dictLock_ unlock]; | ||
331 | |||
332 | return tex; | ||
333 | } | ||
334 | |||
335 | |||
336 | -(CCTexture2D*) addCGImage: (CGImageRef) imageref forKey: (NSString *)key | ||
337 | { | ||
338 | NSAssert(imageref != nil, @"TextureCache: image MUST not be nill"); | ||
339 | |||
340 | CCTexture2D * tex = nil; | ||
341 | |||
342 | // If key is nil, then create a new texture each time | ||
343 | if( key && (tex=[textures_ objectForKey: key] ) ) { | ||
344 | return tex; | ||
345 | } | ||
346 | |||
347 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
348 | // prevents overloading the autorelease pool | ||
349 | UIImage *image = [[UIImage alloc] initWithCGImage:imageref]; | ||
350 | tex = [[CCTexture2D alloc] initWithImage: image]; | ||
351 | [image release]; | ||
352 | |||
353 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
354 | tex = [[CCTexture2D alloc] initWithImage: imageref]; | ||
355 | #endif | ||
356 | |||
357 | if(tex && key) | ||
358 | [textures_ setObject: tex forKey:key]; | ||
359 | else | ||
360 | CCLOG(@"cocos2d: Couldn't add CGImage in CCTextureCache"); | ||
361 | |||
362 | return [tex autorelease]; | ||
363 | } | ||
364 | |||
365 | #pragma mark TextureCache - Remove | ||
366 | |||
367 | -(void) removeAllTextures | ||
368 | { | ||
369 | [textures_ removeAllObjects]; | ||
370 | } | ||
371 | |||
372 | -(void) removeUnusedTextures | ||
373 | { | ||
374 | NSArray *keys = [textures_ allKeys]; | ||
375 | for( id key in keys ) { | ||
376 | id value = [textures_ objectForKey:key]; | ||
377 | if( [value retainCount] == 1 ) { | ||
378 | CCLOG(@"cocos2d: CCTextureCache: removing unused texture: %@", key); | ||
379 | [textures_ removeObjectForKey:key]; | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | |||
384 | -(void) removeTexture: (CCTexture2D*) tex | ||
385 | { | ||
386 | if( ! tex ) | ||
387 | return; | ||
388 | |||
389 | NSArray *keys = [textures_ allKeysForObject:tex]; | ||
390 | |||
391 | for( NSUInteger i = 0; i < [keys count]; i++ ) | ||
392 | [textures_ removeObjectForKey:[keys objectAtIndex:i]]; | ||
393 | } | ||
394 | |||
395 | -(void) removeTextureForKey:(NSString*)name | ||
396 | { | ||
397 | if( ! name ) | ||
398 | return; | ||
399 | |||
400 | [textures_ removeObjectForKey:name]; | ||
401 | } | ||
402 | |||
403 | #pragma mark TextureCache - Get | ||
404 | - (CCTexture2D *)textureForKey:(NSString *)key | ||
405 | { | ||
406 | return [textures_ objectForKey:key]; | ||
407 | } | ||
408 | |||
409 | @end | ||
410 | |||
411 | |||
412 | @implementation CCTextureCache (PVRSupport) | ||
413 | |||
414 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
415 | -(CCTexture2D*) addPVRTCImage:(NSString*)path bpp:(int)bpp hasAlpha:(BOOL)alpha width:(int)w | ||
416 | { | ||
417 | NSAssert(path != nil, @"TextureCache: fileimage MUST not be nill"); | ||
418 | NSAssert( bpp==2 || bpp==4, @"TextureCache: bpp must be either 2 or 4"); | ||
419 | |||
420 | CCTexture2D * tex; | ||
421 | |||
422 | // remove possible -HD suffix to prevent caching the same image twice (issue #1040) | ||
423 | path = ccRemoveHDSuffixFromFile( path ); | ||
424 | |||
425 | if( (tex=[textures_ objectForKey: path] ) ) { | ||
426 | return tex; | ||
427 | } | ||
428 | |||
429 | // Split up directory and filename | ||
430 | NSString *fullpath = [CCFileUtils fullPathFromRelativePath:path]; | ||
431 | |||
432 | NSData *nsdata = [[NSData alloc] initWithContentsOfFile:fullpath]; | ||
433 | tex = [[CCTexture2D alloc] initWithPVRTCData:[nsdata bytes] level:0 bpp:bpp hasAlpha:alpha length:w pixelFormat:bpp==2?kCCTexture2DPixelFormat_PVRTC2:kCCTexture2DPixelFormat_PVRTC4]; | ||
434 | if( tex ) | ||
435 | [textures_ setObject: tex forKey:path]; | ||
436 | else | ||
437 | CCLOG(@"cocos2d: Couldn't add PVRTCImage:%@ in CCTextureCache",path); | ||
438 | |||
439 | [nsdata release]; | ||
440 | |||
441 | return [tex autorelease]; | ||
442 | } | ||
443 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
444 | |||
445 | -(CCTexture2D*) addPVRImage:(NSString*)path | ||
446 | { | ||
447 | NSAssert(path != nil, @"TextureCache: fileimage MUST not be nill"); | ||
448 | |||
449 | CCTexture2D * tex; | ||
450 | |||
451 | // remove possible -HD suffix to prevent caching the same image twice (issue #1040) | ||
452 | path = ccRemoveHDSuffixFromFile( path ); | ||
453 | |||
454 | if( (tex=[textures_ objectForKey: path] ) ) { | ||
455 | return tex; | ||
456 | } | ||
457 | |||
458 | // Split up directory and filename | ||
459 | NSString *fullpath = [CCFileUtils fullPathFromRelativePath:path]; | ||
460 | |||
461 | tex = [[CCTexture2D alloc] initWithPVRFile: fullpath]; | ||
462 | if( tex ) | ||
463 | [textures_ setObject: tex forKey:path]; | ||
464 | else | ||
465 | CCLOG(@"cocos2d: Couldn't add PVRImage:%@ in CCTextureCache",path); | ||
466 | |||
467 | return [tex autorelease]; | ||
468 | } | ||
469 | |||
470 | @end | ||
471 | |||
472 | |||
473 | @implementation CCTextureCache (Debug) | ||
474 | |||
475 | -(void) dumpCachedTextureInfo | ||
476 | { | ||
477 | NSUInteger count = 0; | ||
478 | NSUInteger totalBytes = 0; | ||
479 | for (NSString* texKey in textures_) { | ||
480 | CCTexture2D* tex = [textures_ objectForKey:texKey]; | ||
481 | NSUInteger bpp = [tex bitsPerPixelForFormat]; | ||
482 | // Each texture takes up width * height * bytesPerPixel bytes. | ||
483 | NSUInteger bytes = tex.pixelsWide * tex.pixelsWide * bpp / 8; | ||
484 | totalBytes += bytes; | ||
485 | count++; | ||
486 | CCLOG( @"cocos2d: \"%@\" rc=%lu id=%lu %lu x %lu @ %ld bpp => %lu KB", | ||
487 | texKey, | ||
488 | (long)[tex retainCount], | ||
489 | (long)tex.name, | ||
490 | (long)tex.pixelsWide, | ||
491 | (long)tex.pixelsHigh, | ||
492 | (long)bpp, | ||
493 | (long)bytes / 1024 ); | ||
494 | } | ||
495 | CCLOG( @"cocos2d: CCTextureCache dumpDebugInfo: %ld textures, for %lu KB (%.2f MB)", (long)count, (long)totalBytes / 1024, totalBytes / (1024.0f*1024.0f)); | ||
496 | } | ||
497 | |||
498 | @end | ||
diff --git a/libs/cocos2d/CCTexturePVR.h b/libs/cocos2d/CCTexturePVR.h new file mode 100755 index 0000000..66f8286 --- /dev/null +++ b/libs/cocos2d/CCTexturePVR.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | |||
3 | File: PVRTexture.h | ||
4 | Abstract: The PVRTexture class is responsible for loading .pvr files. | ||
5 | |||
6 | Version: 1.0 | ||
7 | |||
8 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. | ||
9 | ("Apple") in consideration of your agreement to the following terms, and your | ||
10 | use, installation, modification or redistribution of this Apple software | ||
11 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
12 | please do not use, install, modify or redistribute this Apple software. | ||
13 | |||
14 | In consideration of your agreement to abide by the following terms, and subject | ||
15 | to these terms, Apple grants you a personal, non-exclusive license, under | ||
16 | Apple's copyrights in this original Apple software (the "Apple Software"), to | ||
17 | use, reproduce, modify and redistribute the Apple Software, with or without | ||
18 | modifications, in source and/or binary forms; provided that if you redistribute | ||
19 | the Apple Software in its entirety and without modifications, you must retain | ||
20 | this notice and the following text and disclaimers in all such redistributions | ||
21 | of the Apple Software. | ||
22 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used | ||
23 | to endorse or promote products derived from the Apple Software without specific | ||
24 | prior written permission from Apple. Except as expressly stated in this notice, | ||
25 | no other rights or licenses, express or implied, are granted by Apple herein, | ||
26 | including but not limited to any patent rights that may be infringed by your | ||
27 | derivative works or by other works in which the Apple Software may be | ||
28 | incorporated. | ||
29 | |||
30 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
31 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
32 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
33 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
34 | COMBINATION WITH YOUR PRODUCTS. | ||
35 | |||
36 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
37 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
38 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
39 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR | ||
40 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF | ||
41 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF | ||
42 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
43 | |||
44 | Copyright (C) 2008 Apple Inc. All Rights Reserved. | ||
45 | |||
46 | */ | ||
47 | |||
48 | #import <Foundation/Foundation.h> | ||
49 | |||
50 | #import "Platforms/CCGL.h" | ||
51 | #import "CCTexture2D.h" | ||
52 | |||
53 | |||
54 | #pragma mark - | ||
55 | #pragma mark CCTexturePVR | ||
56 | |||
57 | struct CCPVRMipmap { | ||
58 | unsigned char *address; | ||
59 | unsigned int len; | ||
60 | }; | ||
61 | |||
62 | enum { | ||
63 | CC_PVRMIPMAP_MAX = 16, | ||
64 | }; | ||
65 | |||
66 | /** CCTexturePVR | ||
67 | |||
68 | Object that loads PVR images. | ||
69 | |||
70 | Supported PVR formats: | ||
71 | - RGBA8888 | ||
72 | - BGRA8888 | ||
73 | - RGBA4444 | ||
74 | - RGBA5551 | ||
75 | - RGB565 | ||
76 | - A8 | ||
77 | - I8 | ||
78 | - AI88 | ||
79 | - PVRTC 4BPP | ||
80 | - PVRTC 2BPP | ||
81 | |||
82 | Limitations: | ||
83 | Pre-generated mipmaps, such as PVR textures with mipmap levels embedded in file, | ||
84 | are only supported if all individual sprites are of _square_ size. | ||
85 | To use mipmaps with non-square textures, instead call CCTexture2D#generateMipmap on the sheet texture itself | ||
86 | (and to save space, save the PVR sprite sheet without mip maps included). | ||
87 | */ | ||
88 | @interface CCTexturePVR : NSObject | ||
89 | { | ||
90 | struct CCPVRMipmap mipmaps_[CC_PVRMIPMAP_MAX]; // pointer to mipmap images | ||
91 | int numberOfMipmaps_; // number of mipmap used | ||
92 | |||
93 | unsigned int tableFormatIndex_; | ||
94 | uint32_t width_, height_; | ||
95 | GLuint name_; | ||
96 | BOOL hasAlpha_; | ||
97 | |||
98 | // cocos2d integration | ||
99 | BOOL retainName_; | ||
100 | CCTexture2DPixelFormat format_; | ||
101 | } | ||
102 | |||
103 | /** initializes a CCTexturePVR with a path */ | ||
104 | - (id)initWithContentsOfFile:(NSString *)path; | ||
105 | /** initializes a CCTexturePVR with an URL */ | ||
106 | - (id)initWithContentsOfURL:(NSURL *)url; | ||
107 | /** creates and initializes a CCTexturePVR with a path */ | ||
108 | + (id)pvrTextureWithContentsOfFile:(NSString *)path; | ||
109 | /** creates and initializes a CCTexturePVR with an URL */ | ||
110 | + (id)pvrTextureWithContentsOfURL:(NSURL *)url; | ||
111 | |||
112 | /** texture id name */ | ||
113 | @property (nonatomic,readonly) GLuint name; | ||
114 | /** texture width */ | ||
115 | @property (nonatomic,readonly) uint32_t width; | ||
116 | /** texture height */ | ||
117 | @property (nonatomic,readonly) uint32_t height; | ||
118 | /** whether or not the texture has alpha */ | ||
119 | @property (nonatomic,readonly) BOOL hasAlpha; | ||
120 | |||
121 | // cocos2d integration | ||
122 | @property (nonatomic,readwrite) BOOL retainName; | ||
123 | @property (nonatomic,readonly) CCTexture2DPixelFormat format; | ||
124 | |||
125 | @end | ||
126 | |||
127 | |||
diff --git a/libs/cocos2d/CCTexturePVR.m b/libs/cocos2d/CCTexturePVR.m new file mode 100755 index 0000000..692d5f9 --- /dev/null +++ b/libs/cocos2d/CCTexturePVR.m | |||
@@ -0,0 +1,428 @@ | |||
1 | /* | ||
2 | |||
3 | File: PVRTexture.m | ||
4 | Abstract: The PVRTexture class is responsible for loading .pvr files. | ||
5 | |||
6 | Version: 1.0 | ||
7 | |||
8 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. | ||
9 | ("Apple") in consideration of your agreement to the following terms, and your | ||
10 | use, installation, modification or redistribution of this Apple software | ||
11 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
12 | please do not use, install, modify or redistribute this Apple software. | ||
13 | |||
14 | In consideration of your agreement to abide by the following terms, and subject | ||
15 | to these terms, Apple grants you a personal, non-exclusive license, under | ||
16 | Apple's copyrights in this original Apple software (the "Apple Software"), to | ||
17 | use, reproduce, modify and redistribute the Apple Software, with or without | ||
18 | modifications, in source and/or binary forms; provided that if you redistribute | ||
19 | the Apple Software in its entirety and without modifications, you must retain | ||
20 | this notice and the following text and disclaimers in all such redistributions | ||
21 | of the Apple Software. | ||
22 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used | ||
23 | to endorse or promote products derived from the Apple Software without specific | ||
24 | prior written permission from Apple. Except as expressly stated in this notice, | ||
25 | no other rights or licenses, express or implied, are granted by Apple herein, | ||
26 | including but not limited to any patent rights that may be infringed by your | ||
27 | derivative works or by other works in which the Apple Software may be | ||
28 | incorporated. | ||
29 | |||
30 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
31 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
32 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
33 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
34 | COMBINATION WITH YOUR PRODUCTS. | ||
35 | |||
36 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
37 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
38 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
39 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR | ||
40 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF | ||
41 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF | ||
42 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
43 | |||
44 | Copyright (C) 2008 Apple Inc. All Rights Reserved. | ||
45 | |||
46 | */ | ||
47 | |||
48 | /* | ||
49 | * Extended PVR formats for cocos2d project ( http://www.cocos2d-iphone.org ) | ||
50 | * - RGBA8888 | ||
51 | * - BGRA8888 | ||
52 | * - RGBA4444 | ||
53 | * - RGBA5551 | ||
54 | * - RGB565 | ||
55 | * - A8 | ||
56 | * - I8 | ||
57 | * - AI88 | ||
58 | */ | ||
59 | |||
60 | #import <Availability.h> | ||
61 | |||
62 | #import <zlib.h> | ||
63 | |||
64 | #import "CCTexturePVR.h" | ||
65 | #import "ccMacros.h" | ||
66 | #import "CCConfiguration.h" | ||
67 | #import "Support/ccUtils.h" | ||
68 | #import "Support/CCFileUtils.h" | ||
69 | #import "Support/ZipUtils.h" | ||
70 | #import "Support/OpenGL_Internal.h" | ||
71 | |||
72 | #pragma mark - | ||
73 | #pragma mark CCTexturePVR | ||
74 | |||
75 | #define PVR_TEXTURE_FLAG_TYPE_MASK 0xff | ||
76 | |||
77 | // Values taken from PVRTexture.h from http://www.imgtec.com | ||
78 | enum { | ||
79 | kPVRTextureFlagMipmap = (1<<8), // has mip map levels | ||
80 | kPVRTextureFlagTwiddle = (1<<9), // is twiddled | ||
81 | kPVRTextureFlagBumpmap = (1<<10), // has normals encoded for a bump map | ||
82 | kPVRTextureFlagTiling = (1<<11), // is bordered for tiled pvr | ||
83 | kPVRTextureFlagCubemap = (1<<12), // is a cubemap/skybox | ||
84 | kPVRTextureFlagFalseMipCol = (1<<13), // are there false coloured MIP levels | ||
85 | kPVRTextureFlagVolume = (1<<14), // is this a volume texture | ||
86 | kPVRTextureFlagAlpha = (1<<15), // v2.1 is there transparency info in the texture | ||
87 | kPVRTextureFlagVerticalFlip = (1<<16), // v2.1 is the texture vertically flipped | ||
88 | }; | ||
89 | |||
90 | |||
91 | static char gPVRTexIdentifier[4] = "PVR!"; | ||
92 | |||
93 | enum | ||
94 | { | ||
95 | kPVRTexturePixelTypeRGBA_4444= 0x10, | ||
96 | kPVRTexturePixelTypeRGBA_5551, | ||
97 | kPVRTexturePixelTypeRGBA_8888, | ||
98 | kPVRTexturePixelTypeRGB_565, | ||
99 | kPVRTexturePixelTypeRGB_555, // unsupported | ||
100 | kPVRTexturePixelTypeRGB_888, // unsupported | ||
101 | kPVRTexturePixelTypeI_8, | ||
102 | kPVRTexturePixelTypeAI_88, | ||
103 | kPVRTexturePixelTypePVRTC_2, | ||
104 | kPVRTexturePixelTypePVRTC_4, | ||
105 | kPVRTexturePixelTypeBGRA_8888, | ||
106 | kPVRTexturePixelTypeA_8, | ||
107 | }; | ||
108 | |||
109 | static const uint32_t tableFormats[][7] = { | ||
110 | |||
111 | // - PVR texture format | ||
112 | // - OpenGL internal format | ||
113 | // - OpenGL format | ||
114 | // - OpenGL type | ||
115 | // - bpp | ||
116 | // - compressed | ||
117 | // - Cocos2d texture format constant | ||
118 | { kPVRTexturePixelTypeRGBA_4444, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16, NO, kCCTexture2DPixelFormat_RGBA4444 }, | ||
119 | { kPVRTexturePixelTypeRGBA_5551, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16, NO, kCCTexture2DPixelFormat_RGB5A1 }, | ||
120 | { kPVRTexturePixelTypeRGBA_8888, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 32, NO, kCCTexture2DPixelFormat_RGBA8888 }, | ||
121 | { kPVRTexturePixelTypeRGB_565, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, NO, kCCTexture2DPixelFormat_RGB565 }, | ||
122 | { kPVRTexturePixelTypeA_8, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, 8, NO, kCCTexture2DPixelFormat_A8 }, | ||
123 | { kPVRTexturePixelTypeI_8, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 8, NO, kCCTexture2DPixelFormat_I8 }, | ||
124 | { kPVRTexturePixelTypeAI_88, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 16, NO, kCCTexture2DPixelFormat_AI88 }, | ||
125 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
126 | { kPVRTexturePixelTypePVRTC_2, GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, -1, -1, 2, YES, kCCTexture2DPixelFormat_PVRTC2 }, | ||
127 | { kPVRTexturePixelTypePVRTC_4, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, -1, -1, 4, YES, kCCTexture2DPixelFormat_PVRTC4 }, | ||
128 | #endif // iphone only | ||
129 | { kPVRTexturePixelTypeBGRA_8888, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE, 32, NO, kCCTexture2DPixelFormat_RGBA8888 }, | ||
130 | }; | ||
131 | #define MAX_TABLE_ELEMENTS (sizeof(tableFormats) / sizeof(tableFormats[0])) | ||
132 | |||
133 | enum { | ||
134 | kCCInternalPVRTextureFormat, | ||
135 | kCCInternalOpenGLInternalFormat, | ||
136 | kCCInternalOpenGLFormat, | ||
137 | kCCInternalOpenGLType, | ||
138 | kCCInternalBPP, | ||
139 | kCCInternalCompressedImage, | ||
140 | kCCInternalCCTexture2DPixelFormat, | ||
141 | }; | ||
142 | |||
143 | typedef struct _PVRTexHeader | ||
144 | { | ||
145 | uint32_t headerLength; | ||
146 | uint32_t height; | ||
147 | uint32_t width; | ||
148 | uint32_t numMipmaps; | ||
149 | uint32_t flags; | ||
150 | uint32_t dataLength; | ||
151 | uint32_t bpp; | ||
152 | uint32_t bitmaskRed; | ||
153 | uint32_t bitmaskGreen; | ||
154 | uint32_t bitmaskBlue; | ||
155 | uint32_t bitmaskAlpha; | ||
156 | uint32_t pvrTag; | ||
157 | uint32_t numSurfs; | ||
158 | } PVRTexHeader; | ||
159 | |||
160 | |||
161 | @implementation CCTexturePVR | ||
162 | |||
163 | @synthesize name = name_; | ||
164 | @synthesize width = width_; | ||
165 | @synthesize height = height_; | ||
166 | @synthesize hasAlpha = hasAlpha_; | ||
167 | |||
168 | // cocos2d integration | ||
169 | @synthesize retainName = retainName_; | ||
170 | @synthesize format = format_; | ||
171 | |||
172 | |||
173 | - (BOOL)unpackPVRData:(unsigned char*)data PVRLen:(NSUInteger)len | ||
174 | { | ||
175 | BOOL success = FALSE; | ||
176 | PVRTexHeader *header = NULL; | ||
177 | uint32_t flags, pvrTag; | ||
178 | uint32_t dataLength = 0, dataOffset = 0, dataSize = 0; | ||
179 | uint32_t blockSize = 0, widthBlocks = 0, heightBlocks = 0; | ||
180 | uint32_t width = 0, height = 0, bpp = 4; | ||
181 | uint8_t *bytes = NULL; | ||
182 | uint32_t formatFlags; | ||
183 | |||
184 | header = (PVRTexHeader *)data; | ||
185 | |||
186 | pvrTag = CFSwapInt32LittleToHost(header->pvrTag); | ||
187 | |||
188 | if ((uint32_t)gPVRTexIdentifier[0] != ((pvrTag >> 0) & 0xff) || | ||
189 | (uint32_t)gPVRTexIdentifier[1] != ((pvrTag >> 8) & 0xff) || | ||
190 | (uint32_t)gPVRTexIdentifier[2] != ((pvrTag >> 16) & 0xff) || | ||
191 | (uint32_t)gPVRTexIdentifier[3] != ((pvrTag >> 24) & 0xff)) | ||
192 | { | ||
193 | return FALSE; | ||
194 | } | ||
195 | |||
196 | CCConfiguration *configuration = [CCConfiguration sharedConfiguration]; | ||
197 | |||
198 | flags = CFSwapInt32LittleToHost(header->flags); | ||
199 | formatFlags = flags & PVR_TEXTURE_FLAG_TYPE_MASK; | ||
200 | BOOL flipped = flags & kPVRTextureFlagVerticalFlip; | ||
201 | if( flipped ) | ||
202 | CCLOG(@"cocos2d: WARNING: Image is flipped. Regenerate it using PVRTexTool"); | ||
203 | |||
204 | if( ! [configuration supportsNPOT] && | ||
205 | ( header->width != ccNextPOT(header->width) || header->height != ccNextPOT(header->height ) ) ) { | ||
206 | CCLOG(@"cocos2d: ERROR: Loding an NPOT texture (%dx%d) but is not supported on this device", header->width, header->height); | ||
207 | return FALSE; | ||
208 | } | ||
209 | |||
210 | for( tableFormatIndex_=0; tableFormatIndex_ < (unsigned int)MAX_TABLE_ELEMENTS ; tableFormatIndex_++) { | ||
211 | if( tableFormats[tableFormatIndex_][kCCInternalPVRTextureFormat] == formatFlags ) { | ||
212 | |||
213 | numberOfMipmaps_ = 0; | ||
214 | |||
215 | width_ = width = CFSwapInt32LittleToHost(header->width); | ||
216 | height_ = height = CFSwapInt32LittleToHost(header->height); | ||
217 | |||
218 | if (CFSwapInt32LittleToHost(header->bitmaskAlpha)) | ||
219 | hasAlpha_ = TRUE; | ||
220 | else | ||
221 | hasAlpha_ = FALSE; | ||
222 | |||
223 | dataLength = CFSwapInt32LittleToHost(header->dataLength); | ||
224 | bytes = ((uint8_t *)data) + sizeof(PVRTexHeader); | ||
225 | format_ = tableFormats[tableFormatIndex_][kCCInternalCCTexture2DPixelFormat]; | ||
226 | bpp = tableFormats[tableFormatIndex_][kCCInternalBPP]; | ||
227 | |||
228 | // Calculate the data size for each texture level and respect the minimum number of blocks | ||
229 | while (dataOffset < dataLength) | ||
230 | { | ||
231 | switch (formatFlags) { | ||
232 | case kPVRTexturePixelTypePVRTC_2: | ||
233 | blockSize = 8 * 4; // Pixel by pixel block size for 2bpp | ||
234 | widthBlocks = width / 8; | ||
235 | heightBlocks = height / 4; | ||
236 | break; | ||
237 | case kPVRTexturePixelTypePVRTC_4: | ||
238 | blockSize = 4 * 4; // Pixel by pixel block size for 4bpp | ||
239 | widthBlocks = width / 4; | ||
240 | heightBlocks = height / 4; | ||
241 | break; | ||
242 | case kPVRTexturePixelTypeBGRA_8888: | ||
243 | if( ! [[CCConfiguration sharedConfiguration] supportsBGRA8888] ) { | ||
244 | CCLOG(@"cocos2d: TexturePVR. BGRA8888 not supported on this device"); | ||
245 | return FALSE; | ||
246 | } | ||
247 | default: | ||
248 | blockSize = 1; | ||
249 | widthBlocks = width; | ||
250 | heightBlocks = height; | ||
251 | break; | ||
252 | } | ||
253 | |||
254 | // Clamp to minimum number of blocks | ||
255 | if (widthBlocks < 2) | ||
256 | widthBlocks = 2; | ||
257 | if (heightBlocks < 2) | ||
258 | heightBlocks = 2; | ||
259 | |||
260 | dataSize = widthBlocks * heightBlocks * ((blockSize * bpp) / 8); | ||
261 | float packetLength = (dataLength-dataOffset); | ||
262 | packetLength = packetLength > dataSize ? dataSize : packetLength; | ||
263 | |||
264 | mipmaps_[numberOfMipmaps_].address = bytes+dataOffset; | ||
265 | mipmaps_[numberOfMipmaps_].len = packetLength; | ||
266 | numberOfMipmaps_++; | ||
267 | |||
268 | NSAssert( numberOfMipmaps_ < CC_PVRMIPMAP_MAX, @"TexturePVR: Maximum number of mimpaps reached. Increate the CC_PVRMIPMAP_MAX value"); | ||
269 | |||
270 | dataOffset += packetLength; | ||
271 | |||
272 | width = MAX(width >> 1, 1); | ||
273 | height = MAX(height >> 1, 1); | ||
274 | } | ||
275 | |||
276 | success = TRUE; | ||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | if( ! success ) | ||
282 | CCLOG(@"cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%2x. Re-encode it with a OpenGL pixel format variant", formatFlags); | ||
283 | |||
284 | return success; | ||
285 | } | ||
286 | |||
287 | |||
288 | - (BOOL)createGLTexture | ||
289 | { | ||
290 | GLsizei width = width_; | ||
291 | GLsizei height = height_; | ||
292 | GLenum err; | ||
293 | |||
294 | if (numberOfMipmaps_ > 0) | ||
295 | { | ||
296 | if (name_ != 0) | ||
297 | glDeleteTextures(1, &name_); | ||
298 | |||
299 | glPixelStorei(GL_UNPACK_ALIGNMENT,1); | ||
300 | glGenTextures(1, &name_); | ||
301 | glBindTexture(GL_TEXTURE_2D, name_); | ||
302 | } | ||
303 | |||
304 | CHECK_GL_ERROR(); // clean possible GL error | ||
305 | |||
306 | // Generate textures with mipmaps | ||
307 | for (GLint i=0; i < numberOfMipmaps_; i++) | ||
308 | { | ||
309 | GLenum internalFormat = tableFormats[tableFormatIndex_][kCCInternalOpenGLInternalFormat]; | ||
310 | GLenum format = tableFormats[tableFormatIndex_][kCCInternalOpenGLFormat]; | ||
311 | GLenum type = tableFormats[tableFormatIndex_][kCCInternalOpenGLType]; | ||
312 | BOOL compressed = tableFormats[tableFormatIndex_][kCCInternalCompressedImage]; | ||
313 | |||
314 | if( compressed && ! [[CCConfiguration sharedConfiguration] supportsPVRTC] ) { | ||
315 | CCLOG(@"cocos2d: WARNING: PVRTC images are not supported"); | ||
316 | return FALSE; | ||
317 | } | ||
318 | |||
319 | unsigned char *data = mipmaps_[i].address; | ||
320 | unsigned int datalen = mipmaps_[i].len; | ||
321 | |||
322 | if( compressed) | ||
323 | glCompressedTexImage2D(GL_TEXTURE_2D, i, internalFormat, width, height, 0, datalen, data); | ||
324 | else | ||
325 | glTexImage2D(GL_TEXTURE_2D, i, internalFormat, width, height, 0, format, type, data); | ||
326 | |||
327 | if( i > 0 && (width != height || ccNextPOT(width) != width ) ) | ||
328 | CCLOG(@"cocos2d: TexturePVR. WARNING. Mipmap level %u is not squared. Texture won't render correctly. width=%u != height=%u", i, width, height); | ||
329 | |||
330 | err = glGetError(); | ||
331 | if (err != GL_NO_ERROR) | ||
332 | { | ||
333 | CCLOG(@"cocos2d: TexturePVR: Error uploading compressed texture level: %u . glError: 0x%04X", i, err); | ||
334 | return FALSE; | ||
335 | } | ||
336 | |||
337 | width = MAX(width >> 1, 1); | ||
338 | height = MAX(height >> 1, 1); | ||
339 | } | ||
340 | |||
341 | return TRUE; | ||
342 | } | ||
343 | |||
344 | |||
345 | - (id)initWithContentsOfFile:(NSString *)path | ||
346 | { | ||
347 | if((self = [super init])) | ||
348 | { | ||
349 | unsigned char *pvrdata = NULL; | ||
350 | NSInteger pvrlen = 0; | ||
351 | NSString *lowerCase = [path lowercaseString]; | ||
352 | |||
353 | if ( [lowerCase hasSuffix:@".ccz"]) | ||
354 | pvrlen = ccInflateCCZFile( [path UTF8String], &pvrdata ); | ||
355 | |||
356 | else if( [lowerCase hasSuffix:@".gz"] ) | ||
357 | pvrlen = ccInflateGZipFile( [path UTF8String], &pvrdata ); | ||
358 | |||
359 | else | ||
360 | pvrlen = ccLoadFileIntoMemory( [path UTF8String], &pvrdata ); | ||
361 | |||
362 | if( pvrlen < 0 ) { | ||
363 | [self release]; | ||
364 | return nil; | ||
365 | } | ||
366 | |||
367 | |||
368 | numberOfMipmaps_ = 0; | ||
369 | |||
370 | name_ = 0; | ||
371 | width_ = height_ = 0; | ||
372 | tableFormatIndex_ = -1; | ||
373 | hasAlpha_ = FALSE; | ||
374 | |||
375 | retainName_ = NO; // cocos2d integration | ||
376 | |||
377 | if( ! [self unpackPVRData:pvrdata PVRLen:pvrlen] || ![self createGLTexture] ) { | ||
378 | free(pvrdata); | ||
379 | [self release]; | ||
380 | return nil; | ||
381 | } | ||
382 | |||
383 | free(pvrdata); | ||
384 | } | ||
385 | |||
386 | return self; | ||
387 | } | ||
388 | |||
389 | - (id)initWithContentsOfURL:(NSURL *)url | ||
390 | { | ||
391 | if (![url isFileURL]) | ||
392 | { | ||
393 | CCLOG(@"cocos2d: CCPVRTexture: Only files are supported"); | ||
394 | [self release]; | ||
395 | return nil; | ||
396 | } | ||
397 | |||
398 | return [self initWithContentsOfFile:[url path]]; | ||
399 | } | ||
400 | |||
401 | |||
402 | + (id)pvrTextureWithContentsOfFile:(NSString *)path | ||
403 | { | ||
404 | return [[[self alloc] initWithContentsOfFile:path] autorelease]; | ||
405 | } | ||
406 | |||
407 | |||
408 | + (id)pvrTextureWithContentsOfURL:(NSURL *)url | ||
409 | { | ||
410 | if (![url isFileURL]) | ||
411 | return nil; | ||
412 | |||
413 | return [CCTexturePVR pvrTextureWithContentsOfFile:[url path]]; | ||
414 | } | ||
415 | |||
416 | |||
417 | - (void)dealloc | ||
418 | { | ||
419 | CCLOGINFO( @"cocos2d: deallocing %@", self); | ||
420 | |||
421 | if (name_ != 0 && ! retainName_ ) | ||
422 | glDeleteTextures(1, &name_); | ||
423 | |||
424 | [super dealloc]; | ||
425 | } | ||
426 | |||
427 | @end | ||
428 | |||
diff --git a/libs/cocos2d/CCTileMapAtlas.h b/libs/cocos2d/CCTileMapAtlas.h new file mode 100755 index 0000000..102ae46 --- /dev/null +++ b/libs/cocos2d/CCTileMapAtlas.h | |||
@@ -0,0 +1,83 @@ | |||
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 | #import "CCTextureAtlas.h" | ||
28 | #import "CCAtlasNode.h" | ||
29 | #import "Support/TGAlib.h" | ||
30 | |||
31 | /** CCTileMapAtlas is a subclass of CCAtlasNode. | ||
32 | |||
33 | It knows how to render a map based of tiles. | ||
34 | The tiles must be in a .PNG format while the map must be a .TGA file. | ||
35 | |||
36 | For more information regarding the format, please see this post: | ||
37 | http://www.cocos2d-iphone.org/archives/27 | ||
38 | |||
39 | All features from CCAtlasNode are valid in CCTileMapAtlas | ||
40 | |||
41 | IMPORTANT: | ||
42 | This class is deprecated. It is maintained for compatibility reasons only. | ||
43 | You SHOULD not use this class. | ||
44 | Instead, use the newer TMX file format: CCTMXTiledMap | ||
45 | */ | ||
46 | @interface CCTileMapAtlas : CCAtlasNode | ||
47 | { | ||
48 | |||
49 | /// info about the map file | ||
50 | tImageTGA *tgaInfo; | ||
51 | |||
52 | /// x,y to altas dicctionary | ||
53 | NSMutableDictionary *posToAtlasIndex; | ||
54 | |||
55 | /// numbers of tiles to render | ||
56 | int itemsToRender; | ||
57 | } | ||
58 | |||
59 | /** TileMap info */ | ||
60 | @property (nonatomic,readonly) tImageTGA *tgaInfo; | ||
61 | |||
62 | /** creates a CCTileMap with a tile file (atlas) with a map file and the width and height of each tile in points. | ||
63 | The tile file will be loaded using the TextureMgr. | ||
64 | */ | ||
65 | +(id) tileMapAtlasWithTileFile:(NSString*)tile mapFile:(NSString*)map tileWidth:(int)w tileHeight:(int)h; | ||
66 | |||
67 | /** initializes a CCTileMap with a tile file (atlas) with a map file and the width and height of each tile in points. | ||
68 | The file will be loaded using the TextureMgr. | ||
69 | */ | ||
70 | -(id) initWithTileFile:(NSString*)tile mapFile:(NSString*)map tileWidth:(int)w tileHeight:(int)h; | ||
71 | |||
72 | /** returns a tile from position x,y. | ||
73 | For the moment only channel R is used | ||
74 | */ | ||
75 | -(ccColor3B) tileAt: (ccGridSize) position; | ||
76 | |||
77 | /** sets a tile at position x,y. | ||
78 | For the moment only channel R is used | ||
79 | */ | ||
80 | -(void) setTile:(ccColor3B)tile at:(ccGridSize)position; | ||
81 | /** dealloc the map from memory */ | ||
82 | -(void) releaseMap; | ||
83 | @end | ||
diff --git a/libs/cocos2d/CCTileMapAtlas.m b/libs/cocos2d/CCTileMapAtlas.m new file mode 100755 index 0000000..aef6fe0 --- /dev/null +++ b/libs/cocos2d/CCTileMapAtlas.m | |||
@@ -0,0 +1,234 @@ | |||
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 | #import "ccConfig.h" | ||
28 | #import "CCTileMapAtlas.h" | ||
29 | #import "ccMacros.h" | ||
30 | #import "Support/CCFileUtils.h" | ||
31 | |||
32 | @interface CCTileMapAtlas (Private) | ||
33 | -(void) loadTGAfile:(NSString*)file; | ||
34 | -(void) calculateItemsToRender; | ||
35 | -(void) updateAtlasValueAt:(ccGridSize)pos withValue:(ccColor3B)value withIndex:(NSUInteger)idx; | ||
36 | @end | ||
37 | |||
38 | |||
39 | @implementation CCTileMapAtlas | ||
40 | |||
41 | @synthesize tgaInfo; | ||
42 | |||
43 | #pragma mark CCTileMapAtlas - Creation & Init | ||
44 | +(id) tileMapAtlasWithTileFile:(NSString*)tile mapFile:(NSString*)map tileWidth:(int)w tileHeight:(int)h | ||
45 | { | ||
46 | return [[[self alloc] initWithTileFile:tile mapFile:map tileWidth:w tileHeight:h] autorelease]; | ||
47 | } | ||
48 | |||
49 | |||
50 | -(id) initWithTileFile:(NSString*)tile mapFile:(NSString*)map tileWidth:(int)w tileHeight:(int)h | ||
51 | { | ||
52 | [self loadTGAfile: map]; | ||
53 | [self calculateItemsToRender]; | ||
54 | |||
55 | if( (self=[super initWithTileFile:tile tileWidth:w tileHeight:h itemsToRender: itemsToRender]) ) { | ||
56 | |||
57 | posToAtlasIndex = [[NSMutableDictionary dictionaryWithCapacity:itemsToRender] retain]; | ||
58 | |||
59 | [self updateAtlasValues]; | ||
60 | |||
61 | [self setContentSize: CGSizeMake(tgaInfo->width*itemWidth_, tgaInfo->height*itemHeight_)]; | ||
62 | } | ||
63 | |||
64 | return self; | ||
65 | } | ||
66 | |||
67 | -(void) dealloc | ||
68 | { | ||
69 | if( tgaInfo ) | ||
70 | tgaDestroy(tgaInfo); | ||
71 | |||
72 | [posToAtlasIndex release]; | ||
73 | |||
74 | [super dealloc]; | ||
75 | } | ||
76 | |||
77 | -(void) releaseMap | ||
78 | { | ||
79 | if( tgaInfo ) | ||
80 | tgaDestroy(tgaInfo); | ||
81 | |||
82 | tgaInfo = nil; | ||
83 | |||
84 | [posToAtlasIndex release]; | ||
85 | posToAtlasIndex = nil; | ||
86 | } | ||
87 | |||
88 | -(void) calculateItemsToRender | ||
89 | { | ||
90 | NSAssert( tgaInfo != nil, @"tgaInfo must be non-nil"); | ||
91 | |||
92 | itemsToRender = 0; | ||
93 | for(int x = 0;x < tgaInfo->width; x++ ) { | ||
94 | for(int y = 0; y < tgaInfo->height; y++ ) { | ||
95 | ccColor3B *ptr = (ccColor3B*) tgaInfo->imageData; | ||
96 | ccColor3B value = ptr[x + y * tgaInfo->width]; | ||
97 | if( value.r ) | ||
98 | itemsToRender++; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | -(void) loadTGAfile:(NSString*)file | ||
104 | { | ||
105 | NSAssert( file != nil, @"file must be non-nil"); | ||
106 | |||
107 | NSString *path = [CCFileUtils fullPathFromRelativePath:file ]; | ||
108 | |||
109 | // //Find the path of the file | ||
110 | // NSBundle *mainBndl = [CCDirector sharedDirector].loadingBundle; | ||
111 | // NSString *resourcePath = [mainBndl resourcePath]; | ||
112 | // NSString * path = [resourcePath stringByAppendingPathComponent:file]; | ||
113 | |||
114 | tgaInfo = tgaLoad( [path UTF8String] ); | ||
115 | #if 1 | ||
116 | if( tgaInfo->status != TGA_OK ) | ||
117 | [NSException raise:@"TileMapAtlasLoadTGA" format:@"TileMapAtas cannot load TGA file"]; | ||
118 | |||
119 | #endif | ||
120 | } | ||
121 | |||
122 | #pragma mark CCTileMapAtlas - Atlas generation / updates | ||
123 | |||
124 | -(void) setTile:(ccColor3B) tile at:(ccGridSize) pos | ||
125 | { | ||
126 | NSAssert( tgaInfo != nil, @"tgaInfo must not be nil"); | ||
127 | NSAssert( posToAtlasIndex != nil, @"posToAtlasIndex must not be nil"); | ||
128 | NSAssert( pos.x < tgaInfo->width, @"Invalid position.x"); | ||
129 | NSAssert( pos.y < tgaInfo->height, @"Invalid position.x"); | ||
130 | NSAssert( tile.r != 0, @"R component must be non 0"); | ||
131 | |||
132 | ccColor3B *ptr = (ccColor3B*) tgaInfo->imageData; | ||
133 | ccColor3B value = ptr[pos.x + pos.y * tgaInfo->width]; | ||
134 | if( value.r == 0 ) | ||
135 | CCLOG(@"cocos2d: Value.r must be non 0."); | ||
136 | else { | ||
137 | ptr[pos.x + pos.y * tgaInfo->width] = tile; | ||
138 | |||
139 | // XXX: this method consumes a lot of memory | ||
140 | // XXX: a tree of something like that shall be impolemented | ||
141 | NSNumber *num = [posToAtlasIndex objectForKey: [NSString stringWithFormat:@"%d,%d", pos.x, pos.y]]; | ||
142 | [self updateAtlasValueAt:pos withValue:tile withIndex: [num integerValue]]; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | -(ccColor3B) tileAt:(ccGridSize) pos | ||
147 | { | ||
148 | NSAssert( tgaInfo != nil, @"tgaInfo must not be nil"); | ||
149 | NSAssert( pos.x < tgaInfo->width, @"Invalid position.x"); | ||
150 | NSAssert( pos.y < tgaInfo->height, @"Invalid position.y"); | ||
151 | |||
152 | ccColor3B *ptr = (ccColor3B*) tgaInfo->imageData; | ||
153 | ccColor3B value = ptr[pos.x + pos.y * tgaInfo->width]; | ||
154 | |||
155 | return value; | ||
156 | } | ||
157 | |||
158 | -(void) updateAtlasValueAt:(ccGridSize)pos withValue:(ccColor3B)value withIndex:(NSUInteger)idx | ||
159 | { | ||
160 | ccV3F_C4B_T2F_Quad quad; | ||
161 | |||
162 | NSInteger x = pos.x; | ||
163 | NSInteger y = pos.y; | ||
164 | float row = (value.r % itemsPerRow_); | ||
165 | float col = (value.r / itemsPerRow_); | ||
166 | |||
167 | float textureWide = [[textureAtlas_ texture] pixelsWide]; | ||
168 | float textureHigh = [[textureAtlas_ texture] pixelsHigh]; | ||
169 | |||
170 | #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
171 | float left = (2*row*itemWidth_+1)/(2*textureWide); | ||
172 | float right = left+(itemWidth_*2-2)/(2*textureWide); | ||
173 | float top = (2*col*itemHeight_+1)/(2*textureHigh); | ||
174 | float bottom = top+(itemHeight_*2-2)/(2*textureHigh); | ||
175 | #else | ||
176 | float left = (row*itemWidth_)/textureWide; | ||
177 | float right = left+itemWidth_/textureWide; | ||
178 | float top = (col*itemHeight_)/textureHigh; | ||
179 | float bottom = top+itemHeight_/textureHigh; | ||
180 | #endif | ||
181 | |||
182 | |||
183 | quad.tl.texCoords.u = left; | ||
184 | quad.tl.texCoords.v = top; | ||
185 | quad.tr.texCoords.u = right; | ||
186 | quad.tr.texCoords.v = top; | ||
187 | quad.bl.texCoords.u = left; | ||
188 | quad.bl.texCoords.v = bottom; | ||
189 | quad.br.texCoords.u = right; | ||
190 | quad.br.texCoords.v = bottom; | ||
191 | |||
192 | quad.bl.vertices.x = (int) (x * itemWidth_); | ||
193 | quad.bl.vertices.y = (int) (y * itemHeight_); | ||
194 | quad.bl.vertices.z = 0.0f; | ||
195 | quad.br.vertices.x = (int)(x * itemWidth_ + itemWidth_); | ||
196 | quad.br.vertices.y = (int)(y * itemHeight_); | ||
197 | quad.br.vertices.z = 0.0f; | ||
198 | quad.tl.vertices.x = (int)(x * itemWidth_); | ||
199 | quad.tl.vertices.y = (int)(y * itemHeight_ + itemHeight_); | ||
200 | quad.tl.vertices.z = 0.0f; | ||
201 | quad.tr.vertices.x = (int)(x * itemWidth_ + itemWidth_); | ||
202 | quad.tr.vertices.y = (int)(y * itemHeight_ + itemHeight_); | ||
203 | quad.tr.vertices.z = 0.0f; | ||
204 | |||
205 | [textureAtlas_ updateQuad:&quad atIndex:idx]; | ||
206 | } | ||
207 | |||
208 | -(void) updateAtlasValues | ||
209 | { | ||
210 | NSAssert( tgaInfo != nil, @"tgaInfo must be non-nil"); | ||
211 | |||
212 | |||
213 | int total = 0; | ||
214 | |||
215 | for(int x = 0;x < tgaInfo->width; x++ ) { | ||
216 | for(int y = 0; y < tgaInfo->height; y++ ) { | ||
217 | if( total < itemsToRender ) { | ||
218 | ccColor3B *ptr = (ccColor3B*) tgaInfo->imageData; | ||
219 | ccColor3B value = ptr[x + y * tgaInfo->width]; | ||
220 | |||
221 | if( value.r != 0 ) { | ||
222 | [self updateAtlasValueAt:ccg(x,y) withValue:value withIndex:total]; | ||
223 | |||
224 | NSString *key = [NSString stringWithFormat:@"%d,%d", x,y]; | ||
225 | NSNumber *num = [NSNumber numberWithInt:total]; | ||
226 | [posToAtlasIndex setObject:num forKey:key]; | ||
227 | |||
228 | total++; | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | @end | ||
diff --git a/libs/cocos2d/CCTransition.h b/libs/cocos2d/CCTransition.h new file mode 100755 index 0000000..e37d3e8 --- /dev/null +++ b/libs/cocos2d/CCTransition.h | |||
@@ -0,0 +1,296 @@ | |||
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 | #import "CCScene.h" | ||
29 | @class CCActionInterval; | ||
30 | @class CCNode; | ||
31 | |||
32 | /** CCTransitionEaseScene can ease the actions of the scene protocol. | ||
33 | @since v0.8.2 | ||
34 | */ | ||
35 | @protocol CCTransitionEaseScene <NSObject> | ||
36 | /** returns the Ease action that will be performed on a linear action. | ||
37 | @since v0.8.2 | ||
38 | */ | ||
39 | -(CCActionInterval*) easeActionWithAction:(CCActionInterval*)action; | ||
40 | @end | ||
41 | |||
42 | /** Orientation Type used by some transitions | ||
43 | */ | ||
44 | typedef enum { | ||
45 | /// An horizontal orientation where the Left is nearer | ||
46 | kOrientationLeftOver = 0, | ||
47 | /// An horizontal orientation where the Right is nearer | ||
48 | kOrientationRightOver = 1, | ||
49 | /// A vertical orientation where the Up is nearer | ||
50 | kOrientationUpOver = 0, | ||
51 | /// A vertical orientation where the Bottom is nearer | ||
52 | kOrientationDownOver = 1, | ||
53 | } tOrientation; | ||
54 | |||
55 | /** Base class for CCTransition scenes | ||
56 | */ | ||
57 | @interface CCTransitionScene : CCScene | ||
58 | { | ||
59 | CCScene *inScene_; | ||
60 | CCScene *outScene_; | ||
61 | ccTime duration_; | ||
62 | BOOL inSceneOnTop_; | ||
63 | BOOL sendCleanupToScene_; | ||
64 | } | ||
65 | /** creates a base transition with duration and incoming scene */ | ||
66 | +(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s; | ||
67 | /** initializes a transition with duration and incoming scene */ | ||
68 | -(id) initWithDuration:(ccTime) t scene:(CCScene*)s; | ||
69 | /** called after the transition finishes */ | ||
70 | -(void) finish; | ||
71 | /** used by some transitions to hide the outter scene */ | ||
72 | -(void) hideOutShowIn; | ||
73 | @end | ||
74 | |||
75 | /** A CCTransition that supports orientation like. | ||
76 | * Possible orientation: LeftOver, RightOver, UpOver, DownOver | ||
77 | */ | ||
78 | @interface CCTransitionSceneOriented : CCTransitionScene | ||
79 | { | ||
80 | tOrientation orientation; | ||
81 | } | ||
82 | /** creates a base transition with duration and incoming scene */ | ||
83 | +(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s orientation:(tOrientation)o; | ||
84 | /** initializes a transition with duration and incoming scene */ | ||
85 | -(id) initWithDuration:(ccTime) t scene:(CCScene*)s orientation:(tOrientation)o; | ||
86 | @end | ||
87 | |||
88 | |||
89 | /** CCTransitionRotoZoom: | ||
90 | Rotate and zoom out the outgoing scene, and then rotate and zoom in the incoming | ||
91 | */ | ||
92 | @interface CCTransitionRotoZoom : CCTransitionScene | ||
93 | {} | ||
94 | @end | ||
95 | |||
96 | /** CCTransitionJumpZoom: | ||
97 | Zoom out and jump the outgoing scene, and then jump and zoom in the incoming | ||
98 | */ | ||
99 | @interface CCTransitionJumpZoom : CCTransitionScene | ||
100 | {} | ||
101 | @end | ||
102 | |||
103 | /** CCTransitionMoveInL: | ||
104 | Move in from to the left the incoming scene. | ||
105 | */ | ||
106 | @interface CCTransitionMoveInL : CCTransitionScene <CCTransitionEaseScene> | ||
107 | {} | ||
108 | /** initializes the scenes */ | ||
109 | -(void) initScenes; | ||
110 | /** returns the action that will be performed */ | ||
111 | -(CCActionInterval*) action; | ||
112 | @end | ||
113 | |||
114 | /** CCTransitionMoveInR: | ||
115 | Move in from to the right the incoming scene. | ||
116 | */ | ||
117 | @interface CCTransitionMoveInR : CCTransitionMoveInL | ||
118 | {} | ||
119 | @end | ||
120 | |||
121 | /** CCTransitionMoveInT: | ||
122 | Move in from to the top the incoming scene. | ||
123 | */ | ||
124 | @interface CCTransitionMoveInT : CCTransitionMoveInL | ||
125 | {} | ||
126 | @end | ||
127 | |||
128 | /** CCTransitionMoveInB: | ||
129 | Move in from to the bottom the incoming scene. | ||
130 | */ | ||
131 | @interface CCTransitionMoveInB : CCTransitionMoveInL | ||
132 | {} | ||
133 | @end | ||
134 | |||
135 | /** CCTransitionSlideInL: | ||
136 | Slide in the incoming scene from the left border. | ||
137 | */ | ||
138 | @interface CCTransitionSlideInL : CCTransitionScene <CCTransitionEaseScene> | ||
139 | {} | ||
140 | /** initializes the scenes */ | ||
141 | -(void) initScenes; | ||
142 | /** returns the action that will be performed by the incomming and outgoing scene */ | ||
143 | -(CCActionInterval*) action; | ||
144 | @end | ||
145 | |||
146 | /** CCTransitionSlideInR: | ||
147 | Slide in the incoming scene from the right border. | ||
148 | */ | ||
149 | @interface CCTransitionSlideInR : CCTransitionSlideInL | ||
150 | {} | ||
151 | @end | ||
152 | |||
153 | /** CCTransitionSlideInB: | ||
154 | Slide in the incoming scene from the bottom border. | ||
155 | */ | ||
156 | @interface CCTransitionSlideInB : CCTransitionSlideInL | ||
157 | {} | ||
158 | @end | ||
159 | |||
160 | /** CCTransitionSlideInT: | ||
161 | Slide in the incoming scene from the top border. | ||
162 | */ | ||
163 | @interface CCTransitionSlideInT : CCTransitionSlideInL | ||
164 | {} | ||
165 | @end | ||
166 | |||
167 | /** | ||
168 | Shrink the outgoing scene while grow the incoming scene | ||
169 | */ | ||
170 | @interface CCTransitionShrinkGrow : CCTransitionScene <CCTransitionEaseScene> | ||
171 | {} | ||
172 | @end | ||
173 | |||
174 | /** CCTransitionFlipX: | ||
175 | Flips the screen horizontally. | ||
176 | The front face is the outgoing scene and the back face is the incoming scene. | ||
177 | */ | ||
178 | @interface CCTransitionFlipX : CCTransitionSceneOriented | ||
179 | {} | ||
180 | @end | ||
181 | |||
182 | /** CCTransitionFlipY: | ||
183 | Flips the screen vertically. | ||
184 | The front face is the outgoing scene and the back face is the incoming scene. | ||
185 | */ | ||
186 | @interface CCTransitionFlipY : CCTransitionSceneOriented | ||
187 | {} | ||
188 | @end | ||
189 | |||
190 | /** CCTransitionFlipAngular: | ||
191 | Flips the screen half horizontally and half vertically. | ||
192 | The front face is the outgoing scene and the back face is the incoming scene. | ||
193 | */ | ||
194 | @interface CCTransitionFlipAngular : CCTransitionSceneOriented | ||
195 | {} | ||
196 | @end | ||
197 | |||
198 | /** CCTransitionZoomFlipX: | ||
199 | Flips the screen horizontally doing a zoom out/in | ||
200 | The front face is the outgoing scene and the back face is the incoming scene. | ||
201 | */ | ||
202 | @interface CCTransitionZoomFlipX : CCTransitionSceneOriented | ||
203 | {} | ||
204 | @end | ||
205 | |||
206 | /** CCTransitionZoomFlipY: | ||
207 | Flips the screen vertically doing a little zooming out/in | ||
208 | The front face is the outgoing scene and the back face is the incoming scene. | ||
209 | */ | ||
210 | @interface CCTransitionZoomFlipY : CCTransitionSceneOriented | ||
211 | {} | ||
212 | @end | ||
213 | |||
214 | /** CCTransitionZoomFlipAngular: | ||
215 | Flips the screen half horizontally and half vertically doing a little zooming out/in. | ||
216 | The front face is the outgoing scene and the back face is the incoming scene. | ||
217 | */ | ||
218 | @interface CCTransitionZoomFlipAngular : CCTransitionSceneOriented | ||
219 | {} | ||
220 | @end | ||
221 | |||
222 | /** CCTransitionFade: | ||
223 | Fade out the outgoing scene and then fade in the incoming scene.''' | ||
224 | */ | ||
225 | @interface CCTransitionFade : CCTransitionScene | ||
226 | { | ||
227 | ccColor4B color; | ||
228 | } | ||
229 | /** creates the transition with a duration and with an RGB color | ||
230 | * Example: [FadeTransition transitionWithDuration:2 scene:s withColor:ccc3(255,0,0)]; // red color | ||
231 | */ | ||
232 | +(id) transitionWithDuration:(ccTime)duration scene:(CCScene*)scene withColor:(ccColor3B)color; | ||
233 | /** initializes the transition with a duration and with an RGB color */ | ||
234 | -(id) initWithDuration:(ccTime)duration scene:(CCScene*)scene withColor:(ccColor3B)color; | ||
235 | @end | ||
236 | |||
237 | |||
238 | /** | ||
239 | CCTransitionCrossFade: | ||
240 | Cross fades two scenes using the CCRenderTexture object. | ||
241 | */ | ||
242 | @class CCRenderTexture; | ||
243 | @interface CCTransitionCrossFade : CCTransitionScene | ||
244 | {} | ||
245 | @end | ||
246 | |||
247 | /** CCTransitionTurnOffTiles: | ||
248 | Turn off the tiles of the outgoing scene in random order | ||
249 | */ | ||
250 | @interface CCTransitionTurnOffTiles : CCTransitionScene <CCTransitionEaseScene> | ||
251 | {} | ||
252 | @end | ||
253 | |||
254 | /** CCTransitionSplitCols: | ||
255 | The odd columns goes upwards while the even columns goes downwards. | ||
256 | */ | ||
257 | @interface CCTransitionSplitCols : CCTransitionScene <CCTransitionEaseScene> | ||
258 | {} | ||
259 | -(CCActionInterval*) action; | ||
260 | @end | ||
261 | |||
262 | /** CCTransitionSplitRows: | ||
263 | The odd rows goes to the left while the even rows goes to the right. | ||
264 | */ | ||
265 | @interface CCTransitionSplitRows : CCTransitionSplitCols | ||
266 | {} | ||
267 | @end | ||
268 | |||
269 | /** CCTransitionFadeTR: | ||
270 | Fade the tiles of the outgoing scene from the left-bottom corner the to top-right corner. | ||
271 | */ | ||
272 | @interface CCTransitionFadeTR : CCTransitionScene <CCTransitionEaseScene> | ||
273 | {} | ||
274 | -(CCActionInterval*) actionWithSize:(ccGridSize) vector; | ||
275 | @end | ||
276 | |||
277 | /** CCTransitionFadeBL: | ||
278 | Fade the tiles of the outgoing scene from the top-right corner to the bottom-left corner. | ||
279 | */ | ||
280 | @interface CCTransitionFadeBL : CCTransitionFadeTR | ||
281 | {} | ||
282 | @end | ||
283 | |||
284 | /** CCTransitionFadeUp: | ||
285 | * Fade the tiles of the outgoing scene from the bottom to the top. | ||
286 | */ | ||
287 | @interface CCTransitionFadeUp : CCTransitionFadeTR | ||
288 | {} | ||
289 | @end | ||
290 | |||
291 | /** CCTransitionFadeDown: | ||
292 | * Fade the tiles of the outgoing scene from the top to the bottom. | ||
293 | */ | ||
294 | @interface CCTransitionFadeDown : CCTransitionFadeTR | ||
295 | {} | ||
296 | @end | ||
diff --git a/libs/cocos2d/CCTransition.m b/libs/cocos2d/CCTransition.m new file mode 100755 index 0000000..22eed50 --- /dev/null +++ b/libs/cocos2d/CCTransition.m | |||
@@ -0,0 +1,1059 @@ | |||
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 | |||
29 | #import "CCTransition.h" | ||
30 | #import "CCNode.h" | ||
31 | #import "CCDirector.h" | ||
32 | #import "CCActionInterval.h" | ||
33 | #import "CCActionInstant.h" | ||
34 | #import "CCActionCamera.h" | ||
35 | #import "CCLayer.h" | ||
36 | #import "CCCamera.h" | ||
37 | #import "CCActionTiledGrid.h" | ||
38 | #import "CCActionEase.h" | ||
39 | #import "CCRenderTexture.h" | ||
40 | #import "Support/CGPointExtension.h" | ||
41 | |||
42 | #import <Availability.h> | ||
43 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
44 | #import "Platforms/iOS/CCTouchDispatcher.h" | ||
45 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
46 | #import "Platforms/Mac/CCEventDispatcher.h" | ||
47 | #endif | ||
48 | |||
49 | const uint32_t kSceneFade = 0xFADEFADE; | ||
50 | |||
51 | |||
52 | @interface CCTransitionScene (Private) | ||
53 | -(void) sceneOrder; | ||
54 | - (void)setNewScene:(ccTime)dt; | ||
55 | @end | ||
56 | |||
57 | @implementation CCTransitionScene | ||
58 | +(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s | ||
59 | { | ||
60 | return [[[self alloc] initWithDuration:t scene:s] autorelease]; | ||
61 | } | ||
62 | |||
63 | -(id) initWithDuration:(ccTime) t scene:(CCScene*)s | ||
64 | { | ||
65 | NSAssert( s != nil, @"Argument scene must be non-nil"); | ||
66 | |||
67 | if( (self=[super init]) ) { | ||
68 | |||
69 | duration_ = t; | ||
70 | |||
71 | // retain | ||
72 | inScene_ = [s retain]; | ||
73 | outScene_ = [[CCDirector sharedDirector] runningScene]; | ||
74 | [outScene_ retain]; | ||
75 | |||
76 | NSAssert( inScene_ != outScene_, @"Incoming scene must be different from the outgoing scene" ); | ||
77 | |||
78 | // disable events while transitions | ||
79 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
80 | [[CCTouchDispatcher sharedDispatcher] setDispatchEvents: NO]; | ||
81 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
82 | [[CCEventDispatcher sharedDispatcher] setDispatchEvents: NO]; | ||
83 | #endif | ||
84 | |||
85 | [self sceneOrder]; | ||
86 | } | ||
87 | return self; | ||
88 | } | ||
89 | -(void) sceneOrder | ||
90 | { | ||
91 | inSceneOnTop_ = YES; | ||
92 | } | ||
93 | |||
94 | -(void) draw | ||
95 | { | ||
96 | [super draw]; | ||
97 | |||
98 | if( inSceneOnTop_ ) { | ||
99 | [outScene_ visit]; | ||
100 | [inScene_ visit]; | ||
101 | } else { | ||
102 | [inScene_ visit]; | ||
103 | [outScene_ visit]; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | -(void) finish | ||
108 | { | ||
109 | /* clean up */ | ||
110 | [inScene_ setVisible:YES]; | ||
111 | [inScene_ setPosition:ccp(0,0)]; | ||
112 | [inScene_ setScale:1.0f]; | ||
113 | [inScene_ setRotation:0.0f]; | ||
114 | [inScene_.camera restore]; | ||
115 | |||
116 | [outScene_ setVisible:NO]; | ||
117 | [outScene_ setPosition:ccp(0,0)]; | ||
118 | [outScene_ setScale:1.0f]; | ||
119 | [outScene_ setRotation:0.0f]; | ||
120 | [outScene_.camera restore]; | ||
121 | |||
122 | [self schedule:@selector(setNewScene:) interval:0]; | ||
123 | } | ||
124 | |||
125 | -(void) setNewScene: (ccTime) dt | ||
126 | { | ||
127 | [self unschedule:_cmd]; | ||
128 | |||
129 | CCDirector *director = [CCDirector sharedDirector]; | ||
130 | |||
131 | // Before replacing, save the "send cleanup to scene" | ||
132 | sendCleanupToScene_ = [director sendCleanupToScene]; | ||
133 | |||
134 | [director replaceScene: inScene_]; | ||
135 | |||
136 | // enable events while transitions | ||
137 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
138 | [[CCTouchDispatcher sharedDispatcher] setDispatchEvents: YES]; | ||
139 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
140 | [[CCEventDispatcher sharedDispatcher] setDispatchEvents: YES]; | ||
141 | #endif | ||
142 | |||
143 | // issue #267 | ||
144 | [outScene_ setVisible:YES]; | ||
145 | } | ||
146 | |||
147 | -(void) hideOutShowIn | ||
148 | { | ||
149 | [inScene_ setVisible:YES]; | ||
150 | [outScene_ setVisible:NO]; | ||
151 | } | ||
152 | |||
153 | // custom onEnter | ||
154 | -(void) onEnter | ||
155 | { | ||
156 | [super onEnter]; | ||
157 | [inScene_ onEnter]; | ||
158 | // outScene_ should not receive the onEnter callback | ||
159 | } | ||
160 | |||
161 | // custom onExit | ||
162 | -(void) onExit | ||
163 | { | ||
164 | [super onExit]; | ||
165 | [outScene_ onExit]; | ||
166 | |||
167 | // inScene_ should not receive the onExit callback | ||
168 | // only the onEnterTransitionDidFinish | ||
169 | [inScene_ onEnterTransitionDidFinish]; | ||
170 | } | ||
171 | |||
172 | // custom cleanup | ||
173 | -(void) cleanup | ||
174 | { | ||
175 | [super cleanup]; | ||
176 | |||
177 | if( sendCleanupToScene_ ) | ||
178 | [outScene_ cleanup]; | ||
179 | } | ||
180 | |||
181 | -(void) dealloc | ||
182 | { | ||
183 | [inScene_ release]; | ||
184 | [outScene_ release]; | ||
185 | [super dealloc]; | ||
186 | } | ||
187 | @end | ||
188 | |||
189 | // | ||
190 | // Oriented Transition | ||
191 | // | ||
192 | @implementation CCTransitionSceneOriented | ||
193 | +(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s orientation:(tOrientation)o | ||
194 | { | ||
195 | return [[[self alloc] initWithDuration:t scene:s orientation:o] autorelease]; | ||
196 | } | ||
197 | |||
198 | -(id) initWithDuration:(ccTime) t scene:(CCScene*)s orientation:(tOrientation)o | ||
199 | { | ||
200 | if( (self=[super initWithDuration:t scene:s]) ) | ||
201 | orientation = o; | ||
202 | return self; | ||
203 | } | ||
204 | @end | ||
205 | |||
206 | |||
207 | // | ||
208 | // RotoZoom | ||
209 | // | ||
210 | @implementation CCTransitionRotoZoom | ||
211 | -(void) onEnter | ||
212 | { | ||
213 | [super onEnter]; | ||
214 | |||
215 | [inScene_ setScale:0.001f]; | ||
216 | [outScene_ setScale:1.0f]; | ||
217 | |||
218 | [inScene_ setAnchorPoint:ccp(0.5f, 0.5f)]; | ||
219 | [outScene_ setAnchorPoint:ccp(0.5f, 0.5f)]; | ||
220 | |||
221 | CCActionInterval *rotozoom = [CCSequence actions: [CCSpawn actions: | ||
222 | [CCScaleBy actionWithDuration:duration_/2 scale:0.001f], | ||
223 | [CCRotateBy actionWithDuration:duration_/2 angle:360 *2], | ||
224 | nil], | ||
225 | [CCDelayTime actionWithDuration:duration_/2], | ||
226 | nil]; | ||
227 | |||
228 | |||
229 | [outScene_ runAction: rotozoom]; | ||
230 | [inScene_ runAction: [CCSequence actions: | ||
231 | [rotozoom reverse], | ||
232 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
233 | nil]]; | ||
234 | } | ||
235 | @end | ||
236 | |||
237 | // | ||
238 | // JumpZoom | ||
239 | // | ||
240 | @implementation CCTransitionJumpZoom | ||
241 | -(void) onEnter | ||
242 | { | ||
243 | [super onEnter]; | ||
244 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
245 | |||
246 | [inScene_ setScale:0.5f]; | ||
247 | [inScene_ setPosition:ccp( s.width,0 )]; | ||
248 | |||
249 | [inScene_ setAnchorPoint:ccp(0.5f, 0.5f)]; | ||
250 | [outScene_ setAnchorPoint:ccp(0.5f, 0.5f)]; | ||
251 | |||
252 | CCActionInterval *jump = [CCJumpBy actionWithDuration:duration_/4 position:ccp(-s.width,0) height:s.width/4 jumps:2]; | ||
253 | CCActionInterval *scaleIn = [CCScaleTo actionWithDuration:duration_/4 scale:1.0f]; | ||
254 | CCActionInterval *scaleOut = [CCScaleTo actionWithDuration:duration_/4 scale:0.5f]; | ||
255 | |||
256 | CCActionInterval *jumpZoomOut = [CCSequence actions: scaleOut, jump, nil]; | ||
257 | CCActionInterval *jumpZoomIn = [CCSequence actions: jump, scaleIn, nil]; | ||
258 | |||
259 | CCActionInterval *delay = [CCDelayTime actionWithDuration:duration_/2]; | ||
260 | |||
261 | [outScene_ runAction: jumpZoomOut]; | ||
262 | [inScene_ runAction: [CCSequence actions: delay, | ||
263 | jumpZoomIn, | ||
264 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
265 | nil] ]; | ||
266 | } | ||
267 | @end | ||
268 | |||
269 | // | ||
270 | // MoveInL | ||
271 | // | ||
272 | @implementation CCTransitionMoveInL | ||
273 | -(void) onEnter | ||
274 | { | ||
275 | [super onEnter]; | ||
276 | |||
277 | [self initScenes]; | ||
278 | |||
279 | CCActionInterval *a = [self action]; | ||
280 | |||
281 | [inScene_ runAction: [CCSequence actions: | ||
282 | [self easeActionWithAction:a], | ||
283 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
284 | nil] | ||
285 | ]; | ||
286 | |||
287 | } | ||
288 | -(CCActionInterval*) action | ||
289 | { | ||
290 | return [CCMoveTo actionWithDuration:duration_ position:ccp(0,0)]; | ||
291 | } | ||
292 | |||
293 | -(CCActionInterval*) easeActionWithAction:(CCActionInterval*)action | ||
294 | { | ||
295 | return [CCEaseOut actionWithAction:action rate:2.0f]; | ||
296 | // return [EaseElasticOut actionWithAction:action period:0.4f]; | ||
297 | } | ||
298 | |||
299 | -(void) initScenes | ||
300 | { | ||
301 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
302 | [inScene_ setPosition: ccp( -s.width,0) ]; | ||
303 | } | ||
304 | @end | ||
305 | |||
306 | // | ||
307 | // MoveInR | ||
308 | // | ||
309 | @implementation CCTransitionMoveInR | ||
310 | -(void) initScenes | ||
311 | { | ||
312 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
313 | [inScene_ setPosition: ccp( s.width,0) ]; | ||
314 | } | ||
315 | @end | ||
316 | |||
317 | // | ||
318 | // MoveInT | ||
319 | // | ||
320 | @implementation CCTransitionMoveInT | ||
321 | -(void) initScenes | ||
322 | { | ||
323 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
324 | [inScene_ setPosition: ccp( 0, s.height) ]; | ||
325 | } | ||
326 | @end | ||
327 | |||
328 | // | ||
329 | // MoveInB | ||
330 | // | ||
331 | @implementation CCTransitionMoveInB | ||
332 | -(void) initScenes | ||
333 | { | ||
334 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
335 | [inScene_ setPosition: ccp( 0, -s.height) ]; | ||
336 | } | ||
337 | @end | ||
338 | |||
339 | // | ||
340 | // SlideInL | ||
341 | // | ||
342 | |||
343 | // The adjust factor is needed to prevent issue #442 | ||
344 | // One solution is to use DONT_RENDER_IN_SUBPIXELS images, but NO | ||
345 | // The other issue is that in some transitions (and I don't know why) | ||
346 | // the order should be reversed (In in top of Out or vice-versa). | ||
347 | #define ADJUST_FACTOR 0.5f | ||
348 | @implementation CCTransitionSlideInL | ||
349 | -(void) onEnter | ||
350 | { | ||
351 | [super onEnter]; | ||
352 | |||
353 | [self initScenes]; | ||
354 | |||
355 | CCActionInterval *in = [self action]; | ||
356 | CCActionInterval *out = [self action]; | ||
357 | |||
358 | id inAction = [self easeActionWithAction:in]; | ||
359 | id outAction = [CCSequence actions: | ||
360 | [self easeActionWithAction:out], | ||
361 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
362 | nil]; | ||
363 | |||
364 | [inScene_ runAction: inAction]; | ||
365 | [outScene_ runAction: outAction]; | ||
366 | } | ||
367 | -(void) sceneOrder | ||
368 | { | ||
369 | inSceneOnTop_ = NO; | ||
370 | } | ||
371 | -(void) initScenes | ||
372 | { | ||
373 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
374 | [inScene_ setPosition: ccp( -(s.width-ADJUST_FACTOR),0) ]; | ||
375 | } | ||
376 | -(CCActionInterval*) action | ||
377 | { | ||
378 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
379 | return [CCMoveBy actionWithDuration:duration_ position:ccp(s.width-ADJUST_FACTOR,0)]; | ||
380 | } | ||
381 | |||
382 | -(CCActionInterval*) easeActionWithAction:(CCActionInterval*)action | ||
383 | { | ||
384 | return [CCEaseOut actionWithAction:action rate:2.0f]; | ||
385 | // return [EaseElasticOut actionWithAction:action period:0.4f]; | ||
386 | } | ||
387 | |||
388 | @end | ||
389 | |||
390 | // | ||
391 | // SlideInR | ||
392 | // | ||
393 | @implementation CCTransitionSlideInR | ||
394 | -(void) sceneOrder | ||
395 | { | ||
396 | inSceneOnTop_ = YES; | ||
397 | } | ||
398 | -(void) initScenes | ||
399 | { | ||
400 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
401 | [inScene_ setPosition: ccp( s.width-ADJUST_FACTOR,0) ]; | ||
402 | } | ||
403 | |||
404 | -(CCActionInterval*) action | ||
405 | { | ||
406 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
407 | return [CCMoveBy actionWithDuration:duration_ position:ccp(-(s.width-ADJUST_FACTOR),0)]; | ||
408 | } | ||
409 | |||
410 | @end | ||
411 | |||
412 | // | ||
413 | // SlideInT | ||
414 | // | ||
415 | @implementation CCTransitionSlideInT | ||
416 | -(void) sceneOrder | ||
417 | { | ||
418 | inSceneOnTop_ = NO; | ||
419 | } | ||
420 | -(void) initScenes | ||
421 | { | ||
422 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
423 | [inScene_ setPosition: ccp(0,s.height-ADJUST_FACTOR) ]; | ||
424 | } | ||
425 | |||
426 | -(CCActionInterval*) action | ||
427 | { | ||
428 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
429 | return [CCMoveBy actionWithDuration:duration_ position:ccp(0,-(s.height-ADJUST_FACTOR))]; | ||
430 | } | ||
431 | |||
432 | @end | ||
433 | |||
434 | // | ||
435 | // SlideInB | ||
436 | // | ||
437 | @implementation CCTransitionSlideInB | ||
438 | -(void) sceneOrder | ||
439 | { | ||
440 | inSceneOnTop_ = YES; | ||
441 | } | ||
442 | |||
443 | -(void) initScenes | ||
444 | { | ||
445 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
446 | [inScene_ setPosition: ccp(0,-(s.height-ADJUST_FACTOR)) ]; | ||
447 | } | ||
448 | |||
449 | -(CCActionInterval*) action | ||
450 | { | ||
451 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
452 | return [CCMoveBy actionWithDuration:duration_ position:ccp(0,s.height-ADJUST_FACTOR)]; | ||
453 | } | ||
454 | @end | ||
455 | |||
456 | // | ||
457 | // ShrinkGrow Transition | ||
458 | // | ||
459 | @implementation CCTransitionShrinkGrow | ||
460 | -(void) onEnter | ||
461 | { | ||
462 | [super onEnter]; | ||
463 | |||
464 | [inScene_ setScale:0.001f]; | ||
465 | [outScene_ setScale:1.0f]; | ||
466 | |||
467 | [inScene_ setAnchorPoint:ccp(2/3.0f,0.5f)]; | ||
468 | [outScene_ setAnchorPoint:ccp(1/3.0f,0.5f)]; | ||
469 | |||
470 | CCActionInterval *scaleOut = [CCScaleTo actionWithDuration:duration_ scale:0.01f]; | ||
471 | CCActionInterval *scaleIn = [CCScaleTo actionWithDuration:duration_ scale:1.0f]; | ||
472 | |||
473 | [inScene_ runAction: [self easeActionWithAction:scaleIn]]; | ||
474 | [outScene_ runAction: [CCSequence actions: | ||
475 | [self easeActionWithAction:scaleOut], | ||
476 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
477 | nil] ]; | ||
478 | } | ||
479 | -(CCActionInterval*) easeActionWithAction:(CCActionInterval*)action | ||
480 | { | ||
481 | return [CCEaseOut actionWithAction:action rate:2.0f]; | ||
482 | // return [EaseElasticOut actionWithAction:action period:0.3f]; | ||
483 | } | ||
484 | @end | ||
485 | |||
486 | // | ||
487 | // FlipX Transition | ||
488 | // | ||
489 | @implementation CCTransitionFlipX | ||
490 | -(void) onEnter | ||
491 | { | ||
492 | [super onEnter]; | ||
493 | |||
494 | CCActionInterval *inA, *outA; | ||
495 | [inScene_ setVisible: NO]; | ||
496 | |||
497 | float inDeltaZ, inAngleZ; | ||
498 | float outDeltaZ, outAngleZ; | ||
499 | |||
500 | if( orientation == kOrientationRightOver ) { | ||
501 | inDeltaZ = 90; | ||
502 | inAngleZ = 270; | ||
503 | outDeltaZ = 90; | ||
504 | outAngleZ = 0; | ||
505 | } else { | ||
506 | inDeltaZ = -90; | ||
507 | inAngleZ = 90; | ||
508 | outDeltaZ = -90; | ||
509 | outAngleZ = 0; | ||
510 | } | ||
511 | |||
512 | inA = [CCSequence actions: | ||
513 | [CCDelayTime actionWithDuration:duration_/2], | ||
514 | [CCShow action], | ||
515 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:inAngleZ deltaAngleZ:inDeltaZ angleX:0 deltaAngleX:0], | ||
516 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
517 | nil ]; | ||
518 | outA = [CCSequence actions: | ||
519 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:outAngleZ deltaAngleZ:outDeltaZ angleX:0 deltaAngleX:0], | ||
520 | [CCHide action], | ||
521 | [CCDelayTime actionWithDuration:duration_/2], | ||
522 | nil ]; | ||
523 | |||
524 | [inScene_ runAction: inA]; | ||
525 | [outScene_ runAction: outA]; | ||
526 | |||
527 | } | ||
528 | @end | ||
529 | |||
530 | // | ||
531 | // FlipY Transition | ||
532 | // | ||
533 | @implementation CCTransitionFlipY | ||
534 | -(void) onEnter | ||
535 | { | ||
536 | [super onEnter]; | ||
537 | |||
538 | CCActionInterval *inA, *outA; | ||
539 | [inScene_ setVisible: NO]; | ||
540 | |||
541 | float inDeltaZ, inAngleZ; | ||
542 | float outDeltaZ, outAngleZ; | ||
543 | |||
544 | if( orientation == kOrientationUpOver ) { | ||
545 | inDeltaZ = 90; | ||
546 | inAngleZ = 270; | ||
547 | outDeltaZ = 90; | ||
548 | outAngleZ = 0; | ||
549 | } else { | ||
550 | inDeltaZ = -90; | ||
551 | inAngleZ = 90; | ||
552 | outDeltaZ = -90; | ||
553 | outAngleZ = 0; | ||
554 | } | ||
555 | inA = [CCSequence actions: | ||
556 | [CCDelayTime actionWithDuration:duration_/2], | ||
557 | [CCShow action], | ||
558 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:inAngleZ deltaAngleZ:inDeltaZ angleX:90 deltaAngleX:0], | ||
559 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
560 | nil ]; | ||
561 | outA = [CCSequence actions: | ||
562 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:outAngleZ deltaAngleZ:outDeltaZ angleX:90 deltaAngleX:0], | ||
563 | [CCHide action], | ||
564 | [CCDelayTime actionWithDuration:duration_/2], | ||
565 | nil ]; | ||
566 | |||
567 | [inScene_ runAction: inA]; | ||
568 | [outScene_ runAction: outA]; | ||
569 | |||
570 | } | ||
571 | @end | ||
572 | |||
573 | // | ||
574 | // FlipAngular Transition | ||
575 | // | ||
576 | @implementation CCTransitionFlipAngular | ||
577 | -(void) onEnter | ||
578 | { | ||
579 | [super onEnter]; | ||
580 | |||
581 | CCActionInterval *inA, *outA; | ||
582 | [inScene_ setVisible: NO]; | ||
583 | |||
584 | float inDeltaZ, inAngleZ; | ||
585 | float outDeltaZ, outAngleZ; | ||
586 | |||
587 | if( orientation == kOrientationRightOver ) { | ||
588 | inDeltaZ = 90; | ||
589 | inAngleZ = 270; | ||
590 | outDeltaZ = 90; | ||
591 | outAngleZ = 0; | ||
592 | } else { | ||
593 | inDeltaZ = -90; | ||
594 | inAngleZ = 90; | ||
595 | outDeltaZ = -90; | ||
596 | outAngleZ = 0; | ||
597 | } | ||
598 | inA = [CCSequence actions: | ||
599 | [CCDelayTime actionWithDuration:duration_/2], | ||
600 | [CCShow action], | ||
601 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:inAngleZ deltaAngleZ:inDeltaZ angleX:-45 deltaAngleX:0], | ||
602 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
603 | nil ]; | ||
604 | outA = [CCSequence actions: | ||
605 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:outAngleZ deltaAngleZ:outDeltaZ angleX:45 deltaAngleX:0], | ||
606 | [CCHide action], | ||
607 | [CCDelayTime actionWithDuration:duration_/2], | ||
608 | nil ]; | ||
609 | |||
610 | [inScene_ runAction: inA]; | ||
611 | [outScene_ runAction: outA]; | ||
612 | } | ||
613 | @end | ||
614 | |||
615 | // | ||
616 | // ZoomFlipX Transition | ||
617 | // | ||
618 | @implementation CCTransitionZoomFlipX | ||
619 | -(void) onEnter | ||
620 | { | ||
621 | [super onEnter]; | ||
622 | |||
623 | CCActionInterval *inA, *outA; | ||
624 | [inScene_ setVisible: NO]; | ||
625 | |||
626 | float inDeltaZ, inAngleZ; | ||
627 | float outDeltaZ, outAngleZ; | ||
628 | |||
629 | if( orientation == kOrientationRightOver ) { | ||
630 | inDeltaZ = 90; | ||
631 | inAngleZ = 270; | ||
632 | outDeltaZ = 90; | ||
633 | outAngleZ = 0; | ||
634 | } else { | ||
635 | inDeltaZ = -90; | ||
636 | inAngleZ = 90; | ||
637 | outDeltaZ = -90; | ||
638 | outAngleZ = 0; | ||
639 | } | ||
640 | inA = [CCSequence actions: | ||
641 | [CCDelayTime actionWithDuration:duration_/2], | ||
642 | [CCSpawn actions: | ||
643 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:inAngleZ deltaAngleZ:inDeltaZ angleX:0 deltaAngleX:0], | ||
644 | [CCScaleTo actionWithDuration:duration_/2 scale:1], | ||
645 | [CCShow action], | ||
646 | nil], | ||
647 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
648 | nil ]; | ||
649 | outA = [CCSequence actions: | ||
650 | [CCSpawn actions: | ||
651 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:outAngleZ deltaAngleZ:outDeltaZ angleX:0 deltaAngleX:0], | ||
652 | [CCScaleTo actionWithDuration:duration_/2 scale:0.5f], | ||
653 | nil], | ||
654 | [CCHide action], | ||
655 | [CCDelayTime actionWithDuration:duration_/2], | ||
656 | nil ]; | ||
657 | |||
658 | inScene_.scale = 0.5f; | ||
659 | [inScene_ runAction: inA]; | ||
660 | [outScene_ runAction: outA]; | ||
661 | } | ||
662 | @end | ||
663 | |||
664 | // | ||
665 | // ZoomFlipY Transition | ||
666 | // | ||
667 | @implementation CCTransitionZoomFlipY | ||
668 | -(void) onEnter | ||
669 | { | ||
670 | [super onEnter]; | ||
671 | |||
672 | CCActionInterval *inA, *outA; | ||
673 | [inScene_ setVisible: NO]; | ||
674 | |||
675 | float inDeltaZ, inAngleZ; | ||
676 | float outDeltaZ, outAngleZ; | ||
677 | |||
678 | if( orientation == kOrientationUpOver ) { | ||
679 | inDeltaZ = 90; | ||
680 | inAngleZ = 270; | ||
681 | outDeltaZ = 90; | ||
682 | outAngleZ = 0; | ||
683 | } else { | ||
684 | inDeltaZ = -90; | ||
685 | inAngleZ = 90; | ||
686 | outDeltaZ = -90; | ||
687 | outAngleZ = 0; | ||
688 | } | ||
689 | |||
690 | inA = [CCSequence actions: | ||
691 | [CCDelayTime actionWithDuration:duration_/2], | ||
692 | [CCSpawn actions: | ||
693 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:inAngleZ deltaAngleZ:inDeltaZ angleX:90 deltaAngleX:0], | ||
694 | [CCScaleTo actionWithDuration:duration_/2 scale:1], | ||
695 | [CCShow action], | ||
696 | nil], | ||
697 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
698 | nil ]; | ||
699 | outA = [CCSequence actions: | ||
700 | [CCSpawn actions: | ||
701 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:outAngleZ deltaAngleZ:outDeltaZ angleX:90 deltaAngleX:0], | ||
702 | [CCScaleTo actionWithDuration:duration_/2 scale:0.5f], | ||
703 | nil], | ||
704 | [CCHide action], | ||
705 | [CCDelayTime actionWithDuration:duration_/2], | ||
706 | nil ]; | ||
707 | |||
708 | inScene_.scale = 0.5f; | ||
709 | [inScene_ runAction: inA]; | ||
710 | [outScene_ runAction: outA]; | ||
711 | } | ||
712 | @end | ||
713 | |||
714 | // | ||
715 | // ZoomFlipAngular Transition | ||
716 | // | ||
717 | @implementation CCTransitionZoomFlipAngular | ||
718 | -(void) onEnter | ||
719 | { | ||
720 | [super onEnter]; | ||
721 | |||
722 | CCActionInterval *inA, *outA; | ||
723 | [inScene_ setVisible: NO]; | ||
724 | |||
725 | float inDeltaZ, inAngleZ; | ||
726 | float outDeltaZ, outAngleZ; | ||
727 | |||
728 | if( orientation == kOrientationRightOver ) { | ||
729 | inDeltaZ = 90; | ||
730 | inAngleZ = 270; | ||
731 | outDeltaZ = 90; | ||
732 | outAngleZ = 0; | ||
733 | } else { | ||
734 | inDeltaZ = -90; | ||
735 | inAngleZ = 90; | ||
736 | outDeltaZ = -90; | ||
737 | outAngleZ = 0; | ||
738 | } | ||
739 | |||
740 | inA = [CCSequence actions: | ||
741 | [CCDelayTime actionWithDuration:duration_/2], | ||
742 | [CCSpawn actions: | ||
743 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:inAngleZ deltaAngleZ:inDeltaZ angleX:-45 deltaAngleX:0], | ||
744 | [CCScaleTo actionWithDuration:duration_/2 scale:1], | ||
745 | [CCShow action], | ||
746 | nil], | ||
747 | [CCShow action], | ||
748 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
749 | nil ]; | ||
750 | outA = [CCSequence actions: | ||
751 | [CCSpawn actions: | ||
752 | [CCOrbitCamera actionWithDuration: duration_/2 radius: 1 deltaRadius:0 angleZ:outAngleZ deltaAngleZ:outDeltaZ angleX:45 deltaAngleX:0], | ||
753 | [CCScaleTo actionWithDuration:duration_/2 scale:0.5f], | ||
754 | nil], | ||
755 | [CCHide action], | ||
756 | [CCDelayTime actionWithDuration:duration_/2], | ||
757 | nil ]; | ||
758 | |||
759 | inScene_.scale = 0.5f; | ||
760 | [inScene_ runAction: inA]; | ||
761 | [outScene_ runAction: outA]; | ||
762 | } | ||
763 | @end | ||
764 | |||
765 | |||
766 | // | ||
767 | // Fade Transition | ||
768 | // | ||
769 | @implementation CCTransitionFade | ||
770 | +(id) transitionWithDuration:(ccTime)d scene:(CCScene*)s withColor:(ccColor3B)color | ||
771 | { | ||
772 | return [[[self alloc] initWithDuration:d scene:s withColor:color] autorelease]; | ||
773 | } | ||
774 | |||
775 | -(id) initWithDuration:(ccTime)d scene:(CCScene*)s withColor:(ccColor3B)aColor | ||
776 | { | ||
777 | if( (self=[super initWithDuration:d scene:s]) ) { | ||
778 | color.r = aColor.r; | ||
779 | color.g = aColor.g; | ||
780 | color.b = aColor.b; | ||
781 | } | ||
782 | |||
783 | return self; | ||
784 | } | ||
785 | |||
786 | -(id) initWithDuration:(ccTime)d scene:(CCScene*)s | ||
787 | { | ||
788 | return [self initWithDuration:d scene:s withColor:ccBLACK]; | ||
789 | } | ||
790 | |||
791 | -(void) onEnter | ||
792 | { | ||
793 | [super onEnter]; | ||
794 | |||
795 | CCLayerColor *l = [CCLayerColor layerWithColor:color]; | ||
796 | [inScene_ setVisible: NO]; | ||
797 | |||
798 | [self addChild: l z:2 tag:kSceneFade]; | ||
799 | |||
800 | |||
801 | CCNode *f = [self getChildByTag:kSceneFade]; | ||
802 | |||
803 | CCActionInterval *a = [CCSequence actions: | ||
804 | [CCFadeIn actionWithDuration:duration_/2], | ||
805 | [CCCallFunc actionWithTarget:self selector:@selector(hideOutShowIn)], | ||
806 | [CCFadeOut actionWithDuration:duration_/2], | ||
807 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
808 | nil ]; | ||
809 | [f runAction: a]; | ||
810 | } | ||
811 | |||
812 | -(void) onExit | ||
813 | { | ||
814 | [super onExit]; | ||
815 | [self removeChildByTag:kSceneFade cleanup:NO]; | ||
816 | } | ||
817 | @end | ||
818 | |||
819 | |||
820 | // | ||
821 | // Cross Fade Transition | ||
822 | // | ||
823 | @implementation CCTransitionCrossFade | ||
824 | |||
825 | -(void) draw | ||
826 | { | ||
827 | // override draw since both scenes (textures) are rendered in 1 scene | ||
828 | } | ||
829 | |||
830 | -(void) onEnter | ||
831 | { | ||
832 | [super onEnter]; | ||
833 | |||
834 | // create a transparent color layer | ||
835 | // in which we are going to add our rendertextures | ||
836 | ccColor4B color = {0,0,0,0}; | ||
837 | CGSize size = [[CCDirector sharedDirector] winSize]; | ||
838 | CCLayerColor * layer = [CCLayerColor layerWithColor:color]; | ||
839 | |||
840 | // create the first render texture for inScene_ | ||
841 | CCRenderTexture *inTexture = [CCRenderTexture renderTextureWithWidth:size.width height:size.height]; | ||
842 | inTexture.sprite.anchorPoint= ccp(0.5f,0.5f); | ||
843 | inTexture.position = ccp(size.width/2, size.height/2); | ||
844 | inTexture.anchorPoint = ccp(0.5f,0.5f); | ||
845 | |||
846 | // render inScene_ to its texturebuffer | ||
847 | [inTexture begin]; | ||
848 | [inScene_ visit]; | ||
849 | [inTexture end]; | ||
850 | |||
851 | // create the second render texture for outScene_ | ||
852 | CCRenderTexture *outTexture = [CCRenderTexture renderTextureWithWidth:size.width height:size.height]; | ||
853 | outTexture.sprite.anchorPoint= ccp(0.5f,0.5f); | ||
854 | outTexture.position = ccp(size.width/2, size.height/2); | ||
855 | outTexture.anchorPoint = ccp(0.5f,0.5f); | ||
856 | |||
857 | // render outScene_ to its texturebuffer | ||
858 | [outTexture begin]; | ||
859 | [outScene_ visit]; | ||
860 | [outTexture end]; | ||
861 | |||
862 | // create blend functions | ||
863 | |||
864 | ccBlendFunc blend1 = {GL_ONE, GL_ONE}; // inScene_ will lay on background and will not be used with alpha | ||
865 | ccBlendFunc blend2 = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}; // we are going to blend outScene_ via alpha | ||
866 | |||
867 | // set blendfunctions | ||
868 | [inTexture.sprite setBlendFunc:blend1]; | ||
869 | [outTexture.sprite setBlendFunc:blend2]; | ||
870 | |||
871 | // add render textures to the layer | ||
872 | [layer addChild:inTexture]; | ||
873 | [layer addChild:outTexture]; | ||
874 | |||
875 | // initial opacity: | ||
876 | [inTexture.sprite setOpacity:255]; | ||
877 | [outTexture.sprite setOpacity:255]; | ||
878 | |||
879 | // create the blend action | ||
880 | CCActionInterval * layerAction = [CCSequence actions: | ||
881 | [CCFadeTo actionWithDuration:duration_ opacity:0], | ||
882 | [CCCallFunc actionWithTarget:self selector:@selector(hideOutShowIn)], | ||
883 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
884 | nil ]; | ||
885 | |||
886 | |||
887 | // run the blend action | ||
888 | [outTexture.sprite runAction: layerAction]; | ||
889 | |||
890 | // add the layer (which contains our two rendertextures) to the scene | ||
891 | [self addChild: layer z:2 tag:kSceneFade]; | ||
892 | } | ||
893 | |||
894 | // clean up on exit | ||
895 | -(void) onExit | ||
896 | { | ||
897 | // remove our layer and release all containing objects | ||
898 | [self removeChildByTag:kSceneFade cleanup:NO]; | ||
899 | |||
900 | [super onExit]; | ||
901 | } | ||
902 | @end | ||
903 | |||
904 | // | ||
905 | // TurnOffTilesTransition | ||
906 | // | ||
907 | @implementation CCTransitionTurnOffTiles | ||
908 | |||
909 | // override addScenes, and change the order | ||
910 | -(void) sceneOrder | ||
911 | { | ||
912 | inSceneOnTop_ = NO; | ||
913 | } | ||
914 | |||
915 | -(void) onEnter | ||
916 | { | ||
917 | [super onEnter]; | ||
918 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
919 | float aspect = s.width / s.height; | ||
920 | int x = 12 * aspect; | ||
921 | int y = 12; | ||
922 | |||
923 | id toff = [CCTurnOffTiles actionWithSize: ccg(x,y) duration:duration_]; | ||
924 | id action = [self easeActionWithAction:toff]; | ||
925 | [outScene_ runAction: [CCSequence actions: action, | ||
926 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
927 | [CCStopGrid action], | ||
928 | nil] | ||
929 | ]; | ||
930 | |||
931 | } | ||
932 | -(CCActionInterval*) easeActionWithAction:(CCActionInterval*)action | ||
933 | { | ||
934 | return action; | ||
935 | // return [EaseIn actionWithAction:action rate:2.0f]; | ||
936 | } | ||
937 | @end | ||
938 | |||
939 | #pragma mark Split Transitions | ||
940 | |||
941 | // | ||
942 | // SplitCols Transition | ||
943 | // | ||
944 | @implementation CCTransitionSplitCols | ||
945 | |||
946 | -(void) onEnter | ||
947 | { | ||
948 | [super onEnter]; | ||
949 | |||
950 | inScene_.visible = NO; | ||
951 | |||
952 | id split = [self action]; | ||
953 | id seq = [CCSequence actions: | ||
954 | split, | ||
955 | [CCCallFunc actionWithTarget:self selector:@selector(hideOutShowIn)], | ||
956 | [split reverse], | ||
957 | nil | ||
958 | ]; | ||
959 | [self runAction: [CCSequence actions: | ||
960 | [self easeActionWithAction:seq], | ||
961 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
962 | [CCStopGrid action], | ||
963 | nil] | ||
964 | ]; | ||
965 | } | ||
966 | |||
967 | -(CCActionInterval*) action | ||
968 | { | ||
969 | return [CCSplitCols actionWithCols:3 duration:duration_/2.0f]; | ||
970 | } | ||
971 | |||
972 | -(CCActionInterval*) easeActionWithAction:(CCActionInterval*)action | ||
973 | { | ||
974 | return [CCEaseInOut actionWithAction:action rate:3.0f]; | ||
975 | } | ||
976 | @end | ||
977 | |||
978 | // | ||
979 | // SplitRows Transition | ||
980 | // | ||
981 | @implementation CCTransitionSplitRows | ||
982 | -(CCActionInterval*) action | ||
983 | { | ||
984 | return [CCSplitRows actionWithRows:3 duration:duration_/2.0f]; | ||
985 | } | ||
986 | @end | ||
987 | |||
988 | |||
989 | #pragma mark Fade Grid Transitions | ||
990 | |||
991 | // | ||
992 | // FadeTR Transition | ||
993 | // | ||
994 | @implementation CCTransitionFadeTR | ||
995 | -(void) sceneOrder | ||
996 | { | ||
997 | inSceneOnTop_ = NO; | ||
998 | } | ||
999 | |||
1000 | -(void) onEnter | ||
1001 | { | ||
1002 | [super onEnter]; | ||
1003 | |||
1004 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
1005 | float aspect = s.width / s.height; | ||
1006 | int x = 12 * aspect; | ||
1007 | int y = 12; | ||
1008 | |||
1009 | id action = [self actionWithSize:ccg(x,y)]; | ||
1010 | |||
1011 | [outScene_ runAction: [CCSequence actions: | ||
1012 | [self easeActionWithAction:action], | ||
1013 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
1014 | [CCStopGrid action], | ||
1015 | nil] | ||
1016 | ]; | ||
1017 | } | ||
1018 | |||
1019 | -(CCActionInterval*) actionWithSize: (ccGridSize) v | ||
1020 | { | ||
1021 | return [CCFadeOutTRTiles actionWithSize:v duration:duration_]; | ||
1022 | } | ||
1023 | |||
1024 | -(CCActionInterval*) easeActionWithAction:(CCActionInterval*)action | ||
1025 | { | ||
1026 | return action; | ||
1027 | // return [EaseIn actionWithAction:action rate:2.0f]; | ||
1028 | } | ||
1029 | @end | ||
1030 | |||
1031 | // | ||
1032 | // FadeBL Transition | ||
1033 | // | ||
1034 | @implementation CCTransitionFadeBL | ||
1035 | -(CCActionInterval*) actionWithSize: (ccGridSize) v | ||
1036 | { | ||
1037 | return [CCFadeOutBLTiles actionWithSize:v duration:duration_]; | ||
1038 | } | ||
1039 | @end | ||
1040 | |||
1041 | // | ||
1042 | // FadeUp Transition | ||
1043 | // | ||
1044 | @implementation CCTransitionFadeUp | ||
1045 | -(CCActionInterval*) actionWithSize: (ccGridSize) v | ||
1046 | { | ||
1047 | return [CCFadeOutUpTiles actionWithSize:v duration:duration_]; | ||
1048 | } | ||
1049 | @end | ||
1050 | |||
1051 | // | ||
1052 | // FadeDown Transition | ||
1053 | // | ||
1054 | @implementation CCTransitionFadeDown | ||
1055 | -(CCActionInterval*) actionWithSize: (ccGridSize) v | ||
1056 | { | ||
1057 | return [CCFadeOutDownTiles actionWithSize:v duration:duration_]; | ||
1058 | } | ||
1059 | @end | ||
diff --git a/libs/cocos2d/CCTransitionPageTurn.h b/libs/cocos2d/CCTransitionPageTurn.h new file mode 100755 index 0000000..aacb7fc --- /dev/null +++ b/libs/cocos2d/CCTransitionPageTurn.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Sindesso Pty Ltd http://www.sindesso.com/ | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCTransition.h" | ||
28 | |||
29 | /** CCTransitionPageTurn transition. | ||
30 | * A transition which peels back the bottom right hand corner of a scene | ||
31 | * to transition to the scene beneath it simulating a page turn | ||
32 | * | ||
33 | * This uses a 3DAction so it's strongly recommended that depth buffering | ||
34 | * is turned on in CCDirector using: | ||
35 | * | ||
36 | * [[CCDirector sharedDirector] setDepthBufferFormat:kCCDepthBuffer16]; | ||
37 | * | ||
38 | * @since v0.8.2 | ||
39 | */ | ||
40 | @interface CCTransitionPageTurn : CCTransitionScene | ||
41 | { | ||
42 | BOOL back_; | ||
43 | } | ||
44 | /** | ||
45 | * creates a base transition with duration and incoming scene | ||
46 | * if back is TRUE then the effect is reversed to appear as if the incoming | ||
47 | * scene is being turned from left over the outgoing scene | ||
48 | */ | ||
49 | +(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s backwards:(BOOL) back; | ||
50 | |||
51 | /** | ||
52 | * creates a base transition with duration and incoming scene | ||
53 | * if back is TRUE then the effect is reversed to appear as if the incoming | ||
54 | * scene is being turned from left over the outgoing scene | ||
55 | */ | ||
56 | -(id) initWithDuration:(ccTime) t scene:(CCScene*)s backwards:(BOOL) back; | ||
57 | |||
58 | -(CCActionInterval*) actionWithSize:(ccGridSize) vector; | ||
59 | |||
60 | @end | ||
diff --git a/libs/cocos2d/CCTransitionPageTurn.m b/libs/cocos2d/CCTransitionPageTurn.m new file mode 100755 index 0000000..bff43a7 --- /dev/null +++ b/libs/cocos2d/CCTransitionPageTurn.m | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Sindesso Pty Ltd http://www.sindesso.com/ | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "CCTransitionPageTurn.h" | ||
28 | #import "CCActionPageTurn3D.h" | ||
29 | #import "CCDirector.h" | ||
30 | |||
31 | @implementation CCTransitionPageTurn | ||
32 | |||
33 | /** creates a base transition with duration and incoming scene */ | ||
34 | +(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s backwards:(BOOL) back | ||
35 | { | ||
36 | return [[[self alloc] initWithDuration:t scene:s backwards:back] autorelease]; | ||
37 | } | ||
38 | |||
39 | /** initializes a transition with duration and incoming scene */ | ||
40 | -(id) initWithDuration:(ccTime) t scene:(CCScene*)s backwards:(BOOL) back | ||
41 | { | ||
42 | // XXX: needed before [super init] | ||
43 | back_ = back; | ||
44 | |||
45 | if( ( self = [super initWithDuration:t scene:s] ) ) | ||
46 | { | ||
47 | // do something | ||
48 | } | ||
49 | return self; | ||
50 | } | ||
51 | |||
52 | -(void) sceneOrder | ||
53 | { | ||
54 | inSceneOnTop_ = back_; | ||
55 | } | ||
56 | |||
57 | // | ||
58 | -(void) onEnter | ||
59 | { | ||
60 | [super onEnter]; | ||
61 | |||
62 | CGSize s = [[CCDirector sharedDirector] winSize]; | ||
63 | int x, y; | ||
64 | if( s.width > s.height) | ||
65 | { | ||
66 | x = 16; | ||
67 | y = 12; | ||
68 | } | ||
69 | else | ||
70 | { | ||
71 | x = 12; | ||
72 | y = 16; | ||
73 | } | ||
74 | |||
75 | id action = [self actionWithSize:ccg(x,y)]; | ||
76 | |||
77 | if(! back_ ) | ||
78 | { | ||
79 | [outScene_ runAction: [CCSequence actions: | ||
80 | action, | ||
81 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
82 | [CCStopGrid action], | ||
83 | nil] | ||
84 | ]; | ||
85 | } | ||
86 | else | ||
87 | { | ||
88 | // to prevent initial flicker | ||
89 | inScene_.visible = NO; | ||
90 | [inScene_ runAction: [CCSequence actions: | ||
91 | [CCShow action], | ||
92 | action, | ||
93 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
94 | [CCStopGrid action], | ||
95 | nil] | ||
96 | ]; | ||
97 | } | ||
98 | |||
99 | } | ||
100 | |||
101 | -(CCActionInterval*) actionWithSize: (ccGridSize) v | ||
102 | { | ||
103 | if( back_ ) | ||
104 | { | ||
105 | // Get hold of the PageTurn3DAction | ||
106 | return [CCReverseTime actionWithAction: | ||
107 | [CCPageTurn3D actionWithSize:v duration:duration_]]; | ||
108 | } | ||
109 | else | ||
110 | { | ||
111 | // Get hold of the PageTurn3DAction | ||
112 | return [CCPageTurn3D actionWithSize:v duration:duration_]; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | @end | ||
117 | |||
diff --git a/libs/cocos2d/CCTransitionRadial.h b/libs/cocos2d/CCTransitionRadial.h new file mode 100755 index 0000000..6d4a5e0 --- /dev/null +++ b/libs/cocos2d/CCTransitionRadial.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Lam Pham | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import "CCTransition.h" | ||
27 | #import "CCProgressTimer.h" | ||
28 | #import "CCActionProgressTimer.h" | ||
29 | |||
30 | /** CCTransitionRadialCCW transition. | ||
31 | A counter colock-wise radial transition to the next scene | ||
32 | */ | ||
33 | @interface CCTransitionRadialCCW : CCTransitionScene | ||
34 | @end | ||
35 | |||
36 | /** CCTransitionRadialCW transition. | ||
37 | A counter colock-wise radial transition to the next scene | ||
38 | */ | ||
39 | @interface CCTransitionRadialCW : CCTransitionRadialCCW | ||
40 | @end | ||
diff --git a/libs/cocos2d/CCTransitionRadial.m b/libs/cocos2d/CCTransitionRadial.m new file mode 100755 index 0000000..a892f35 --- /dev/null +++ b/libs/cocos2d/CCTransitionRadial.m | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Lam Pham | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | |||
28 | #import "CCDirector.h" | ||
29 | #import "CCTransitionRadial.h" | ||
30 | #import "CCRenderTexture.h" | ||
31 | #import "CCLayer.h" | ||
32 | #import "CCActionInstant.h" | ||
33 | #import "Support/CGPointExtension.h" | ||
34 | |||
35 | enum { | ||
36 | kSceneRadial = 0xc001, | ||
37 | }; | ||
38 | |||
39 | #pragma mark - | ||
40 | #pragma mark Transition Radial CCW | ||
41 | |||
42 | @implementation CCTransitionRadialCCW | ||
43 | -(void) sceneOrder | ||
44 | { | ||
45 | inSceneOnTop_ = NO; | ||
46 | } | ||
47 | |||
48 | -(CCProgressTimerType) radialType | ||
49 | { | ||
50 | return kCCProgressTimerTypeRadialCCW; | ||
51 | } | ||
52 | |||
53 | -(void) onEnter | ||
54 | { | ||
55 | [super onEnter]; | ||
56 | // create a transparent color layer | ||
57 | // in which we are going to add our rendertextures | ||
58 | CGSize size = [[CCDirector sharedDirector] winSize]; | ||
59 | |||
60 | // create the second render texture for outScene | ||
61 | CCRenderTexture *outTexture = [CCRenderTexture renderTextureWithWidth:size.width height:size.height]; | ||
62 | outTexture.sprite.anchorPoint= ccp(0.5f,0.5f); | ||
63 | outTexture.position = ccp(size.width/2, size.height/2); | ||
64 | outTexture.anchorPoint = ccp(0.5f,0.5f); | ||
65 | |||
66 | // render outScene to its texturebuffer | ||
67 | [outTexture clear:0 g:0 b:0 a:1]; | ||
68 | [outTexture begin]; | ||
69 | [outScene_ visit]; | ||
70 | [outTexture end]; | ||
71 | |||
72 | // Since we've passed the outScene to the texture we don't need it. | ||
73 | [self hideOutShowIn]; | ||
74 | |||
75 | // We need the texture in RenderTexture. | ||
76 | CCProgressTimer *outNode = [CCProgressTimer progressWithTexture:outTexture.sprite.texture]; | ||
77 | // but it's flipped upside down so we flip the sprite | ||
78 | outNode.sprite.flipY = YES; | ||
79 | // Return the radial type that we want to use | ||
80 | outNode.type = [self radialType]; | ||
81 | outNode.percentage = 100.f; | ||
82 | outNode.position = ccp(size.width/2, size.height/2); | ||
83 | outNode.anchorPoint = ccp(0.5f,0.5f); | ||
84 | |||
85 | // create the blend action | ||
86 | CCActionInterval * layerAction = [CCSequence actions: | ||
87 | [CCProgressFromTo actionWithDuration:duration_ from:100.f to:0.f], | ||
88 | [CCCallFunc actionWithTarget:self selector:@selector(finish)], | ||
89 | nil ]; | ||
90 | // run the blend action | ||
91 | [outNode runAction: layerAction]; | ||
92 | |||
93 | // add the layer (which contains our two rendertextures) to the scene | ||
94 | [self addChild: outNode z:2 tag:kSceneRadial]; | ||
95 | } | ||
96 | |||
97 | // clean up on exit | ||
98 | -(void) onExit | ||
99 | { | ||
100 | // remove our layer and release all containing objects | ||
101 | [self removeChildByTag:kSceneRadial cleanup:NO]; | ||
102 | [super onExit]; | ||
103 | } | ||
104 | @end | ||
105 | |||
106 | #pragma mark - | ||
107 | #pragma mark Transition Radial CW | ||
108 | |||
109 | @implementation CCTransitionRadialCW | ||
110 | -(CCProgressTimerType) radialType | ||
111 | { | ||
112 | return kCCProgressTimerTypeRadialCW; | ||
113 | } | ||
114 | @end | ||
115 | |||
diff --git a/libs/cocos2d/Platforms/CCGL.h b/libs/cocos2d/Platforms/CCGL.h new file mode 100755 index 0000000..0725f89 --- /dev/null +++ b/libs/cocos2d/Platforms/CCGL.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | // Common layer for OpenGL stuff | ||
28 | // | ||
29 | |||
30 | #import <Availability.h> | ||
31 | |||
32 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
33 | #import <OpenGLES/ES1/gl.h> | ||
34 | #import <OpenGLES/ES1/glext.h> | ||
35 | #import <OpenGLES/EAGL.h> | ||
36 | #import "iOS/glu.h" | ||
37 | #import "iOS/EAGLView.h" | ||
38 | |||
39 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
40 | #import <OpenGL/gl.h> | ||
41 | #import <OpenGL/glu.h> | ||
42 | #import <Cocoa/Cocoa.h> // needed for NSOpenGLView | ||
43 | #import "Mac/MacGLView.h" | ||
44 | #endif | ||
45 | |||
46 | |||
47 | // iOS | ||
48 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
49 | #define CC_GLVIEW EAGLView | ||
50 | #define ccglOrtho glOrthof | ||
51 | #define ccglClearDepth glClearDepthf | ||
52 | #define ccglGenerateMipmap glGenerateMipmapOES | ||
53 | #define ccglGenFramebuffers glGenFramebuffersOES | ||
54 | #define ccglBindFramebuffer glBindFramebufferOES | ||
55 | #define ccglFramebufferTexture2D glFramebufferTexture2DOES | ||
56 | #define ccglDeleteFramebuffers glDeleteFramebuffersOES | ||
57 | #define ccglCheckFramebufferStatus glCheckFramebufferStatusOES | ||
58 | #define ccglTranslate glTranslatef | ||
59 | |||
60 | #define CC_GL_FRAMEBUFFER GL_FRAMEBUFFER_OES | ||
61 | #define CC_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_OES | ||
62 | #define CC_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_OES | ||
63 | #define CC_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES | ||
64 | |||
65 | // Mac | ||
66 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
67 | #define CC_GLVIEW MacGLView | ||
68 | #define ccglOrtho glOrtho | ||
69 | #define ccglClearDepth glClearDepth | ||
70 | #define ccglGenerateMipmap glGenerateMipmap | ||
71 | #define ccglGenFramebuffers glGenFramebuffers | ||
72 | #define ccglBindFramebuffer glBindFramebuffer | ||
73 | #define ccglFramebufferTexture2D glFramebufferTexture2D | ||
74 | #define ccglDeleteFramebuffers glDeleteFramebuffers | ||
75 | #define ccglCheckFramebufferStatus glCheckFramebufferStatus | ||
76 | #define ccglTranslate glTranslated | ||
77 | |||
78 | #define CC_GL_FRAMEBUFFER GL_FRAMEBUFFER | ||
79 | #define CC_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING | ||
80 | #define CC_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0 | ||
81 | #define CC_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE | ||
82 | |||
83 | #endif | ||
diff --git a/libs/cocos2d/Platforms/CCNS.h b/libs/cocos2d/Platforms/CCNS.h new file mode 100755 index 0000000..c595a18 --- /dev/null +++ b/libs/cocos2d/Platforms/CCNS.h | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | // Common layer for NS (Next-Step) stuff | ||
28 | // | ||
29 | |||
30 | #import <Availability.h> | ||
31 | |||
32 | #import <Foundation/Foundation.h> // for NSObject | ||
33 | |||
34 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
35 | |||
36 | #define CCRectFromString(__r__) CGRectFromString(__r__) | ||
37 | #define CCPointFromString(__p__) CGPointFromString(__p__) | ||
38 | #define CCSizeFromString(__s__) CGSizeFromString(__s__) | ||
39 | #define CCNSSizeToCGSize | ||
40 | #define CCNSRectToCGRect | ||
41 | #define CCNSPointToCGPoint | ||
42 | #define CCTextAlignment UITextAlignment | ||
43 | #define CCTextAlignmentCenter UITextAlignmentCenter | ||
44 | #define CCTextAlignmentLeft UITextAlignmentLeft | ||
45 | #define CCTextAlignmentRight UITextAlignmentRight | ||
46 | #define CCLineBreakMode UILineBreakMode | ||
47 | #define CCLineBreakModeWordWrap UILineBreakModeWordWrap | ||
48 | #define CCLineBreakModeCharacterWrap UILineBreakModeCharacterWrap | ||
49 | #define CCLineBreakModeClip UILineBreakModeClip | ||
50 | #define CCLineBreakModeHeadTruncation UILineBreakModeHeadTruncation | ||
51 | #define CCLineBreakModeTailTruncation UILineBreakModeTailTruncation | ||
52 | #define CCLineBreakModeMiddleTruncation UILineBreakModeMiddleTruncation | ||
53 | |||
54 | |||
55 | |||
56 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
57 | |||
58 | #define CCRectFromString(__r__) NSRectToCGRect( NSRectFromString(__r__) ) | ||
59 | #define CCPointFromString(__p__) NSPointToCGPoint( NSPointFromString(__p__) ) | ||
60 | #define CCSizeFromString(__s__) NSSizeToCGSize( NSSizeFromString(__s__) ) | ||
61 | #define CCNSSizeToCGSize NSSizeToCGSize | ||
62 | #define CCNSRectToCGRect NSRectToCGRect | ||
63 | #define CCNSPointToCGPoint NSPointToCGPoint | ||
64 | #define CCTextAlignment NSTextAlignment | ||
65 | #define CCTextAlignmentCenter NSCenterTextAlignment | ||
66 | #define CCTextAlignmentLeft NSLeftTextAlignment | ||
67 | #define CCTextAlignmentRight NSRightTextAlignment | ||
68 | #define CCLineBreakMode NSLineBreakMode | ||
69 | #define CCLineBreakModeWordWrap NSLineBreakByWordWrapping | ||
70 | #define CCLineBreakModeClip -1 | ||
71 | #define CCLineBreakModeHeadTruncation -1 | ||
72 | #define CCLineBreakModeTailTruncation -1 | ||
73 | #define CCLineBreakModeMiddleTruncation -1 | ||
74 | |||
75 | |||
76 | #endif | ||
77 | |||
78 | |||
diff --git a/libs/cocos2d/Platforms/Mac/CCDirectorMac.h b/libs/cocos2d/Platforms/Mac/CCDirectorMac.h new file mode 100755 index 0000000..0d623b4 --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/CCDirectorMac.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | // Only compile this code on Mac. These files should not be included on your iOS project. | ||
28 | // But in case they are included, it won't be compiled. | ||
29 | #import <Availability.h> | ||
30 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
31 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
32 | |||
33 | #import <QuartzCore/CVDisplayLink.h> | ||
34 | #import "../../CCDirector.h" | ||
35 | |||
36 | enum { | ||
37 | /// If the window is resized, it won't be autoscaled | ||
38 | kCCDirectorResize_NoScale, | ||
39 | /// If the window is resized, it will be autoscaled (default behavior) | ||
40 | kCCDirectorResize_AutoScale, | ||
41 | }; | ||
42 | |||
43 | @interface CCDirector (MacExtension) | ||
44 | /** converts an NSEvent to GL coordinates */ | ||
45 | -(CGPoint) convertEventToGL:(NSEvent*)event; | ||
46 | @end | ||
47 | |||
48 | /** Base class of Mac directors | ||
49 | @since v0.99.5 | ||
50 | */ | ||
51 | @interface CCDirectorMac : CCDirector | ||
52 | { | ||
53 | BOOL isFullScreen_; | ||
54 | int resizeMode_; | ||
55 | CGPoint winOffset_; | ||
56 | CGSize originalWinSize_; | ||
57 | |||
58 | NSWindow *fullScreenWindow_; | ||
59 | |||
60 | // cache | ||
61 | NSWindow *windowGLView_; | ||
62 | NSView *superViewGLView_; | ||
63 | NSRect originalWinRect_; // Original size and position | ||
64 | } | ||
65 | |||
66 | // whether or not the view is in fullscreen mode | ||
67 | @property (nonatomic, readonly) BOOL isFullScreen; | ||
68 | |||
69 | // resize mode: with or without scaling | ||
70 | @property (nonatomic, readwrite) int resizeMode; | ||
71 | |||
72 | @property (nonatomic, readwrite) CGSize originalWinSize; | ||
73 | |||
74 | /** Sets the view in fullscreen or window mode */ | ||
75 | - (void) setFullScreen:(BOOL)fullscreen; | ||
76 | |||
77 | /** Converts window size coordiantes to logical coordinates. | ||
78 | Useful only if resizeMode is kCCDirectorResize_Scale. | ||
79 | If resizeMode is kCCDirectorResize_NoScale, then no conversion will be done. | ||
80 | */ | ||
81 | - (CGPoint) convertToLogicalCoordinates:(CGPoint)coordinates; | ||
82 | @end | ||
83 | |||
84 | |||
85 | /** DisplayLinkDirector is a Director that synchronizes timers with the refresh rate of the display. | ||
86 | * | ||
87 | * Features and Limitations: | ||
88 | * - Only available on 3.1+ | ||
89 | * - Scheduled timers & drawing are synchronizes with the refresh rate of the display | ||
90 | * - Only supports animation intervals of 1/60 1/30 & 1/15 | ||
91 | * | ||
92 | * It is the recommended Director if the SDK is 3.1 or newer | ||
93 | * | ||
94 | * @since v0.8.2 | ||
95 | */ | ||
96 | @interface CCDirectorDisplayLink : CCDirectorMac | ||
97 | { | ||
98 | CVDisplayLinkRef displayLink; | ||
99 | } | ||
100 | @end | ||
101 | |||
102 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
103 | |||
diff --git a/libs/cocos2d/Platforms/Mac/CCDirectorMac.m b/libs/cocos2d/Platforms/Mac/CCDirectorMac.m new file mode 100755 index 0000000..477081e --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/CCDirectorMac.m | |||
@@ -0,0 +1,479 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | // Only compile this code on Mac. These files should not be included on your iOS project. | ||
27 | // But in case they are included, it won't be compiled. | ||
28 | #import <Availability.h> | ||
29 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
30 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
31 | |||
32 | #import <sys/time.h> | ||
33 | |||
34 | #import "CCDirectorMac.h" | ||
35 | #import "CCEventDispatcher.h" | ||
36 | #import "MacGLView.h" | ||
37 | |||
38 | #import "../../CCNode.h" | ||
39 | #import "../../CCScheduler.h" | ||
40 | #import "../../ccMacros.h" | ||
41 | |||
42 | #pragma mark - | ||
43 | #pragma mark Director Mac extensions | ||
44 | |||
45 | |||
46 | @interface CCDirector () | ||
47 | -(void) setNextScene; | ||
48 | -(void) showFPS; | ||
49 | -(void) calculateDeltaTime; | ||
50 | @end | ||
51 | |||
52 | @implementation CCDirector (MacExtension) | ||
53 | -(CGPoint) convertEventToGL:(NSEvent*)event | ||
54 | { | ||
55 | NSPoint point = [openGLView_ convertPoint:[event locationInWindow] fromView:nil]; | ||
56 | CGPoint p = NSPointToCGPoint(point); | ||
57 | |||
58 | return [(CCDirectorMac*)self convertToLogicalCoordinates:p]; | ||
59 | } | ||
60 | |||
61 | @end | ||
62 | |||
63 | #pragma mark - | ||
64 | #pragma mark Director Mac | ||
65 | |||
66 | @implementation CCDirectorMac | ||
67 | |||
68 | @synthesize isFullScreen = isFullScreen_; | ||
69 | @synthesize originalWinSize = originalWinSize_; | ||
70 | |||
71 | -(id) init | ||
72 | { | ||
73 | if( (self = [super init]) ) { | ||
74 | isFullScreen_ = NO; | ||
75 | resizeMode_ = kCCDirectorResize_AutoScale; | ||
76 | |||
77 | originalWinSize_ = CGSizeZero; | ||
78 | fullScreenWindow_ = nil; | ||
79 | windowGLView_ = nil; | ||
80 | winOffset_ = CGPointZero; | ||
81 | } | ||
82 | |||
83 | return self; | ||
84 | } | ||
85 | |||
86 | - (void) dealloc | ||
87 | { | ||
88 | [superViewGLView_ release]; | ||
89 | [fullScreenWindow_ release]; | ||
90 | [windowGLView_ release]; | ||
91 | [super dealloc]; | ||
92 | } | ||
93 | |||
94 | // | ||
95 | // setFullScreen code taken from GLFullScreen example by Apple | ||
96 | // | ||
97 | - (void) setFullScreen:(BOOL)fullscreen | ||
98 | { | ||
99 | // Mac OS X 10.6 and later offer a simplified mechanism to create full-screen contexts | ||
100 | #if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5 | ||
101 | |||
102 | if (isFullScreen_ == fullscreen) return; | ||
103 | |||
104 | if( fullscreen ) { | ||
105 | originalWinRect_ = [openGLView_ frame]; | ||
106 | |||
107 | // Cache normal window and superview of openGLView | ||
108 | if(!windowGLView_) | ||
109 | windowGLView_ = [[openGLView_ window] retain]; | ||
110 | |||
111 | [superViewGLView_ release]; | ||
112 | superViewGLView_ = [[openGLView_ superview] retain]; | ||
113 | |||
114 | |||
115 | // Get screen size | ||
116 | NSRect displayRect = [[NSScreen mainScreen] frame]; | ||
117 | |||
118 | // Create a screen-sized window on the display you want to take over | ||
119 | fullScreenWindow_ = [[MacWindow alloc] initWithFrame:displayRect fullscreen:YES]; | ||
120 | |||
121 | // Remove glView from window | ||
122 | [openGLView_ removeFromSuperview]; | ||
123 | |||
124 | // Set new frame | ||
125 | [openGLView_ setFrame:displayRect]; | ||
126 | |||
127 | // Attach glView to fullscreen window | ||
128 | [fullScreenWindow_ setContentView:openGLView_]; | ||
129 | |||
130 | // Show the fullscreen window | ||
131 | [fullScreenWindow_ makeKeyAndOrderFront:self]; | ||
132 | [fullScreenWindow_ makeMainWindow]; | ||
133 | |||
134 | } else { | ||
135 | |||
136 | // Remove glView from fullscreen window | ||
137 | [openGLView_ removeFromSuperview]; | ||
138 | |||
139 | // Release fullscreen window | ||
140 | [fullScreenWindow_ release]; | ||
141 | fullScreenWindow_ = nil; | ||
142 | |||
143 | // Attach glView to superview | ||
144 | [superViewGLView_ addSubview:openGLView_]; | ||
145 | |||
146 | // Set new frame | ||
147 | [openGLView_ setFrame:originalWinRect_]; | ||
148 | |||
149 | // Show the window | ||
150 | [windowGLView_ makeKeyAndOrderFront:self]; | ||
151 | [windowGLView_ makeMainWindow]; | ||
152 | } | ||
153 | isFullScreen_ = fullscreen; | ||
154 | |||
155 | [openGLView_ retain]; // Retain +1 | ||
156 | |||
157 | // re-configure glView | ||
158 | [self setOpenGLView:openGLView_]; | ||
159 | |||
160 | [openGLView_ release]; // Retain -1 | ||
161 | |||
162 | [openGLView_ setNeedsDisplay:YES]; | ||
163 | #else | ||
164 | #error Full screen is not supported for Mac OS 10.5 or older yet | ||
165 | #error If you don't want FullScreen support, you can safely remove these 2 lines | ||
166 | #endif | ||
167 | } | ||
168 | |||
169 | -(void) setOpenGLView:(MacGLView *)view | ||
170 | { | ||
171 | [super setOpenGLView:view]; | ||
172 | |||
173 | // cache the NSWindow and NSOpenGLView created from the NIB | ||
174 | if( !isFullScreen_ && CGSizeEqualToSize(originalWinSize_, CGSizeZero)) | ||
175 | { | ||
176 | originalWinSize_ = winSizeInPixels_; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | -(int) resizeMode | ||
181 | { | ||
182 | return resizeMode_; | ||
183 | } | ||
184 | |||
185 | -(void) setResizeMode:(int)mode | ||
186 | { | ||
187 | if( mode != resizeMode_ ) { | ||
188 | |||
189 | resizeMode_ = mode; | ||
190 | |||
191 | [self setProjection:projection_]; | ||
192 | [openGLView_ setNeedsDisplay: YES]; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | -(void) setProjection:(ccDirectorProjection)projection | ||
197 | { | ||
198 | CGSize size = winSizeInPixels_; | ||
199 | |||
200 | CGPoint offset = CGPointZero; | ||
201 | float widthAspect = size.width; | ||
202 | float heightAspect = size.height; | ||
203 | |||
204 | |||
205 | if( resizeMode_ == kCCDirectorResize_AutoScale && ! CGSizeEqualToSize(originalWinSize_, CGSizeZero ) ) { | ||
206 | |||
207 | size = originalWinSize_; | ||
208 | |||
209 | float aspect = originalWinSize_.width / originalWinSize_.height; | ||
210 | widthAspect = winSizeInPixels_.width; | ||
211 | heightAspect = winSizeInPixels_.width / aspect; | ||
212 | |||
213 | if( heightAspect > winSizeInPixels_.height ) { | ||
214 | widthAspect = winSizeInPixels_.height * aspect; | ||
215 | heightAspect = winSizeInPixels_.height; | ||
216 | } | ||
217 | |||
218 | winOffset_.x = (winSizeInPixels_.width - widthAspect) / 2; | ||
219 | winOffset_.y = (winSizeInPixels_.height - heightAspect) / 2; | ||
220 | |||
221 | offset = winOffset_; | ||
222 | |||
223 | } | ||
224 | |||
225 | switch (projection) { | ||
226 | case kCCDirectorProjection2D: | ||
227 | glViewport(offset.x, offset.y, widthAspect, heightAspect); | ||
228 | glMatrixMode(GL_PROJECTION); | ||
229 | glLoadIdentity(); | ||
230 | ccglOrtho(0, size.width, 0, size.height, -1024, 1024); | ||
231 | glMatrixMode(GL_MODELVIEW); | ||
232 | glLoadIdentity(); | ||
233 | break; | ||
234 | |||
235 | case kCCDirectorProjection3D: | ||
236 | glViewport(offset.x, offset.y, widthAspect, heightAspect); | ||
237 | glMatrixMode(GL_PROJECTION); | ||
238 | glLoadIdentity(); | ||
239 | gluPerspective(60, (GLfloat)widthAspect/heightAspect, 0.1f, 1500.0f); | ||
240 | |||
241 | glMatrixMode(GL_MODELVIEW); | ||
242 | glLoadIdentity(); | ||
243 | |||
244 | float eyeZ = size.height * [self getZEye] / winSizeInPixels_.height; | ||
245 | |||
246 | gluLookAt( size.width/2, size.height/2, eyeZ, | ||
247 | size.width/2, size.height/2, 0, | ||
248 | 0.0f, 1.0f, 0.0f); | ||
249 | break; | ||
250 | |||
251 | case kCCDirectorProjectionCustom: | ||
252 | if( projectionDelegate_ ) | ||
253 | [projectionDelegate_ updateProjection]; | ||
254 | break; | ||
255 | |||
256 | default: | ||
257 | CCLOG(@"cocos2d: Director: unrecognized projecgtion"); | ||
258 | break; | ||
259 | } | ||
260 | |||
261 | projection_ = projection; | ||
262 | } | ||
263 | |||
264 | // If scaling is supported, then it should always return the original size | ||
265 | // otherwise it should return the "real" size. | ||
266 | -(CGSize) winSize | ||
267 | { | ||
268 | if( resizeMode_ == kCCDirectorResize_AutoScale ) | ||
269 | return originalWinSize_; | ||
270 | |||
271 | return winSizeInPixels_; | ||
272 | } | ||
273 | |||
274 | -(CGSize) winSizeInPixels | ||
275 | { | ||
276 | return [self winSize]; | ||
277 | } | ||
278 | |||
279 | - (CGPoint) convertToLogicalCoordinates:(CGPoint)coords | ||
280 | { | ||
281 | CGPoint ret; | ||
282 | |||
283 | if( resizeMode_ == kCCDirectorResize_NoScale ) | ||
284 | ret = coords; | ||
285 | |||
286 | else { | ||
287 | |||
288 | float x_diff = originalWinSize_.width / (winSizeInPixels_.width - winOffset_.x * 2); | ||
289 | float y_diff = originalWinSize_.height / (winSizeInPixels_.height - winOffset_.y * 2); | ||
290 | |||
291 | float adjust_x = (winSizeInPixels_.width * x_diff - originalWinSize_.width ) / 2; | ||
292 | float adjust_y = (winSizeInPixels_.height * y_diff - originalWinSize_.height ) / 2; | ||
293 | |||
294 | ret = CGPointMake( (x_diff * coords.x) - adjust_x, ( y_diff * coords.y ) - adjust_y ); | ||
295 | } | ||
296 | |||
297 | return ret; | ||
298 | } | ||
299 | @end | ||
300 | |||
301 | |||
302 | #pragma mark - | ||
303 | #pragma mark DirectorDisplayLink | ||
304 | |||
305 | |||
306 | @implementation CCDirectorDisplayLink | ||
307 | |||
308 | - (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime | ||
309 | { | ||
310 | #if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
311 | if( ! runningThread_ ) | ||
312 | runningThread_ = [NSThread currentThread]; | ||
313 | |||
314 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | ||
315 | |||
316 | [self drawScene]; | ||
317 | [[CCEventDispatcher sharedDispatcher] dispatchQueuedEvents]; | ||
318 | |||
319 | [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:nil]; | ||
320 | |||
321 | [pool release]; | ||
322 | |||
323 | #else | ||
324 | [self performSelector:@selector(drawScene) onThread:runningThread_ withObject:nil waitUntilDone:YES]; | ||
325 | #endif | ||
326 | |||
327 | return kCVReturnSuccess; | ||
328 | } | ||
329 | |||
330 | // This is the renderer output callback function | ||
331 | static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) | ||
332 | { | ||
333 | CVReturn result = [(CCDirectorDisplayLink*)displayLinkContext getFrameForTime:outputTime]; | ||
334 | return result; | ||
335 | } | ||
336 | |||
337 | - (void) startAnimation | ||
338 | { | ||
339 | #if ! CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
340 | runningThread_ = [[NSThread alloc] initWithTarget:self selector:@selector(mainLoop) object:nil]; | ||
341 | [runningThread_ start]; | ||
342 | #endif | ||
343 | |||
344 | gettimeofday( &lastUpdate_, NULL); | ||
345 | |||
346 | // Create a display link capable of being used with all active displays | ||
347 | CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); | ||
348 | |||
349 | // Set the renderer output callback function | ||
350 | CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, self); | ||
351 | |||
352 | // Set the display link for the current renderer | ||
353 | CGLContextObj cglContext = [[openGLView_ openGLContext] CGLContextObj]; | ||
354 | CGLPixelFormatObj cglPixelFormat = [[openGLView_ pixelFormat] CGLPixelFormatObj]; | ||
355 | CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat); | ||
356 | |||
357 | // Activate the display link | ||
358 | CVDisplayLinkStart(displayLink); | ||
359 | } | ||
360 | |||
361 | - (void) stopAnimation | ||
362 | { | ||
363 | if( displayLink ) { | ||
364 | CVDisplayLinkStop(displayLink); | ||
365 | CVDisplayLinkRelease(displayLink); | ||
366 | displayLink = NULL; | ||
367 | |||
368 | #if ! CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
369 | [runningThread_ cancel]; | ||
370 | [runningThread_ release]; | ||
371 | runningThread_ = nil; | ||
372 | #endif | ||
373 | } | ||
374 | } | ||
375 | |||
376 | -(void) dealloc | ||
377 | { | ||
378 | if( displayLink ) { | ||
379 | CVDisplayLinkStop(displayLink); | ||
380 | CVDisplayLinkRelease(displayLink); | ||
381 | } | ||
382 | [super dealloc]; | ||
383 | } | ||
384 | |||
385 | // | ||
386 | // Mac Director has its own thread | ||
387 | // | ||
388 | -(void) mainLoop | ||
389 | { | ||
390 | while( ![[NSThread currentThread] isCancelled] ) { | ||
391 | // There is no autorelease pool when this method is called because it will be called from a background thread | ||
392 | // It's important to create one or you will leak objects | ||
393 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | ||
394 | |||
395 | [[NSRunLoop currentRunLoop] run]; | ||
396 | |||
397 | [pool release]; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | // | ||
402 | // Draw the Scene | ||
403 | // | ||
404 | - (void) drawScene | ||
405 | { | ||
406 | // We draw on a secondary thread through the display link | ||
407 | // When resizing the view, -reshape is called automatically on the main thread | ||
408 | // Add a mutex around to avoid the threads accessing the context simultaneously when resizing | ||
409 | CGLLockContext([[openGLView_ openGLContext] CGLContextObj]); | ||
410 | [[openGLView_ openGLContext] makeCurrentContext]; | ||
411 | |||
412 | /* calculate "global" dt */ | ||
413 | [self calculateDeltaTime]; | ||
414 | |||
415 | /* tick before glClear: issue #533 */ | ||
416 | if( ! isPaused_ ) { | ||
417 | [[CCScheduler sharedScheduler] tick: dt]; | ||
418 | } | ||
419 | |||
420 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||
421 | |||
422 | /* to avoid flickr, nextScene MUST be here: after tick and before draw. | ||
423 | XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */ | ||
424 | if( nextScene_ ) | ||
425 | [self setNextScene]; | ||
426 | |||
427 | glPushMatrix(); | ||
428 | |||
429 | |||
430 | // By default enable VertexArray, ColorArray, TextureCoordArray and Texture2D | ||
431 | CC_ENABLE_DEFAULT_GL_STATES(); | ||
432 | |||
433 | /* draw the scene */ | ||
434 | [runningScene_ visit]; | ||
435 | |||
436 | /* draw the notification node */ | ||
437 | [notificationNode_ visit]; | ||
438 | |||
439 | if( displayFPS_ ) | ||
440 | [self showFPS]; | ||
441 | |||
442 | #if CC_ENABLE_PROFILERS | ||
443 | [self showProfilers]; | ||
444 | #endif | ||
445 | |||
446 | CC_DISABLE_DEFAULT_GL_STATES(); | ||
447 | |||
448 | glPopMatrix(); | ||
449 | |||
450 | [[openGLView_ openGLContext] flushBuffer]; | ||
451 | CGLUnlockContext([[openGLView_ openGLContext] CGLContextObj]); | ||
452 | } | ||
453 | |||
454 | // set the event dispatcher | ||
455 | -(void) setOpenGLView:(MacGLView *)view | ||
456 | { | ||
457 | if( view != openGLView_ ) { | ||
458 | |||
459 | [super setOpenGLView:view]; | ||
460 | |||
461 | CCEventDispatcher *eventDispatcher = [CCEventDispatcher sharedDispatcher]; | ||
462 | [openGLView_ setEventDelegate: eventDispatcher]; | ||
463 | [eventDispatcher setDispatchEvents: YES]; | ||
464 | |||
465 | // Enable Touches. Default no. | ||
466 | [view setAcceptsTouchEvents:NO]; | ||
467 | // [view setAcceptsTouchEvents:YES]; | ||
468 | |||
469 | |||
470 | // Synchronize buffer swaps with vertical refresh rate | ||
471 | [[view openGLContext] makeCurrentContext]; | ||
472 | GLint swapInt = 1; | ||
473 | [[view openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; | ||
474 | } | ||
475 | } | ||
476 | |||
477 | @end | ||
478 | |||
479 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/Mac/CCEventDispatcher.h b/libs/cocos2d/Platforms/Mac/CCEventDispatcher.h new file mode 100755 index 0000000..06889e8 --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/CCEventDispatcher.h | |||
@@ -0,0 +1,277 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | // Only compile this code on Mac. These files should not be included on your iOS project. | ||
27 | // But in case they are included, it won't be compiled. | ||
28 | #import <Availability.h> | ||
29 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
30 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
31 | |||
32 | #import <Cocoa/Cocoa.h> | ||
33 | |||
34 | #import "MacGLView.h" | ||
35 | #import "../../Support/uthash.h" // hack: uthash needs to be imported before utlist to prevent warning | ||
36 | #import "../../Support/utlist.h" | ||
37 | #import "../../ccConfig.h" | ||
38 | |||
39 | #pragma mark - | ||
40 | #pragma mark CCMouseEventDelegate | ||
41 | |||
42 | /** CCMouseEventDelegate protocol. | ||
43 | Implement it in your node to receive any of mouse events | ||
44 | */ | ||
45 | @protocol CCMouseEventDelegate <NSObject> | ||
46 | @optional | ||
47 | |||
48 | // | ||
49 | // left | ||
50 | // | ||
51 | /** called when the "mouseDown" event is received. | ||
52 | Return YES to avoid propagating the event to other delegates. | ||
53 | */ | ||
54 | -(BOOL) ccMouseDown:(NSEvent*)event; | ||
55 | |||
56 | /** called when the "mouseDragged" event is received. | ||
57 | Return YES to avoid propagating the event to other delegates. | ||
58 | */ | ||
59 | -(BOOL) ccMouseDragged:(NSEvent*)event; | ||
60 | |||
61 | /** called when the "mouseMoved" event is received. | ||
62 | Return YES to avoid propagating the event to other delegates. | ||
63 | By default, "mouseMoved" is disabled. To enable it, send the "setAcceptsMouseMovedEvents:YES" message to the main window. | ||
64 | */ | ||
65 | -(BOOL) ccMouseMoved:(NSEvent*)event; | ||
66 | |||
67 | /** called when the "mouseUp" event is received. | ||
68 | Return YES to avoid propagating the event to other delegates. | ||
69 | */ | ||
70 | -(BOOL) ccMouseUp:(NSEvent*)event; | ||
71 | |||
72 | |||
73 | // | ||
74 | // right | ||
75 | // | ||
76 | |||
77 | /** called when the "rightMouseDown" event is received. | ||
78 | Return YES to avoid propagating the event to other delegates. | ||
79 | */ | ||
80 | -(BOOL) ccRightMouseDown:(NSEvent*)event; | ||
81 | |||
82 | /** called when the "rightMouseDragged" event is received. | ||
83 | Return YES to avoid propagating the event to other delegates. | ||
84 | */ | ||
85 | -(BOOL) ccRightMouseDragged:(NSEvent*)event; | ||
86 | |||
87 | /** called when the "rightMouseUp" event is received. | ||
88 | Return YES to avoid propagating the event to other delegates. | ||
89 | */ | ||
90 | -(BOOL) ccRightMouseUp:(NSEvent*)event; | ||
91 | |||
92 | // | ||
93 | // other | ||
94 | // | ||
95 | |||
96 | /** called when the "otherMouseDown" event is received. | ||
97 | Return YES to avoid propagating the event to other delegates. | ||
98 | */ | ||
99 | -(BOOL) ccOtherMouseDown:(NSEvent*)event; | ||
100 | |||
101 | /** called when the "otherMouseDragged" event is received. | ||
102 | Return YES to avoid propagating the event to other delegates. | ||
103 | */ | ||
104 | -(BOOL) ccOtherMouseDragged:(NSEvent*)event; | ||
105 | |||
106 | /** called when the "otherMouseUp" event is received. | ||
107 | Return YES to avoid propagating the event to other delegates. | ||
108 | */ | ||
109 | -(BOOL) ccOtherMouseUp:(NSEvent*)event; | ||
110 | |||
111 | // | ||
112 | // scroll wheel | ||
113 | // | ||
114 | |||
115 | /** called when the "scrollWheel" event is received. | ||
116 | Return YES to avoid propagating the event to other delegates. | ||
117 | */ | ||
118 | - (BOOL)ccScrollWheel:(NSEvent *)theEvent; | ||
119 | |||
120 | |||
121 | // | ||
122 | // enter / exit | ||
123 | // | ||
124 | |||
125 | /** called when the "mouseEntered" event is received. | ||
126 | Return YES to avoid propagating the event to other delegates. | ||
127 | */ | ||
128 | - (void)ccMouseEntered:(NSEvent *)theEvent; | ||
129 | |||
130 | /** called when the "mouseExited" event is received. | ||
131 | Return YES to avoid propagating the event to other delegates. | ||
132 | */ | ||
133 | - (void)ccMouseExited:(NSEvent *)theEvent; | ||
134 | |||
135 | @end | ||
136 | |||
137 | #pragma mark - | ||
138 | #pragma mark CCKeyboardEventDelegate | ||
139 | |||
140 | /** CCKeyboardEventDelegate protocol. | ||
141 | Implement it in your node to receive any of keyboard events | ||
142 | */ | ||
143 | @protocol CCKeyboardEventDelegate <NSObject> | ||
144 | @optional | ||
145 | /** called when the "keyUp" event is received. | ||
146 | Return YES to avoid propagating the event to other delegates. | ||
147 | */ | ||
148 | -(BOOL) ccKeyUp:(NSEvent*)event; | ||
149 | |||
150 | /** called when the "keyDown" event is received. | ||
151 | Return YES to avoid propagating the event to other delegates. | ||
152 | */ | ||
153 | -(BOOL) ccKeyDown:(NSEvent*)event; | ||
154 | /** called when the "flagsChanged" event is received. | ||
155 | Return YES to avoid propagating the event to other delegates. | ||
156 | */ | ||
157 | -(BOOL) ccFlagsChanged:(NSEvent*)event; | ||
158 | @end | ||
159 | |||
160 | #pragma mark - | ||
161 | #pragma mark CCTouchEventDelegate | ||
162 | |||
163 | /** CCTouchEventDelegate protocol. | ||
164 | Implement it in your node to receive any of touch events | ||
165 | */ | ||
166 | @protocol CCTouchEventDelegate <NSObject> | ||
167 | @optional | ||
168 | /** called when the "touchesBegan" event is received. | ||
169 | Return YES to avoid propagating the event to other delegates. | ||
170 | */ | ||
171 | - (BOOL)ccTouchesBeganWithEvent:(NSEvent *)event; | ||
172 | |||
173 | /** called when the "touchesMoved" event is received. | ||
174 | Return YES to avoid propagating the event to other delegates. | ||
175 | */ | ||
176 | - (BOOL)ccTouchesMovedWithEvent:(NSEvent *)event; | ||
177 | |||
178 | /** called when the "touchesEnded" event is received. | ||
179 | Return YES to avoid propagating the event to other delegates. | ||
180 | */ | ||
181 | - (BOOL)ccTouchesEndedWithEvent:(NSEvent *)event; | ||
182 | |||
183 | /** called when the "touchesCancelled" event is received. | ||
184 | Return YES to avoid propagating the event to other delegates. | ||
185 | */ | ||
186 | - (BOOL)ccTouchesCancelledWithEvent:(NSEvent *)event; | ||
187 | |||
188 | @end | ||
189 | |||
190 | |||
191 | #pragma mark - | ||
192 | #pragma mark CCEventDispatcher | ||
193 | |||
194 | struct _listEntry; | ||
195 | |||
196 | /** CCEventDispatcher | ||
197 | |||
198 | This is object is responsible for dispatching the events: | ||
199 | - Mouse events | ||
200 | - Keyboard events | ||
201 | - Touch events | ||
202 | |||
203 | Only available on Mac | ||
204 | */ | ||
205 | @interface CCEventDispatcher : NSObject <MacEventDelegate> { | ||
206 | |||
207 | BOOL dispatchEvents_; | ||
208 | |||
209 | struct _listEntry *keyboardDelegates_; | ||
210 | struct _listEntry *mouseDelegates_; | ||
211 | struct _listEntry *touchDelegates_; | ||
212 | } | ||
213 | |||
214 | @property (nonatomic, readwrite) BOOL dispatchEvents; | ||
215 | |||
216 | |||
217 | /** CCEventDispatcher singleton */ | ||
218 | +(CCEventDispatcher*) sharedDispatcher; | ||
219 | |||
220 | #pragma mark CCEventDispatcher - Mouse | ||
221 | |||
222 | /** Adds a mouse delegate to the dispatcher's list. | ||
223 | Delegates with a lower priority value will be called before higher priority values. | ||
224 | All the events will be propgated to all the delegates, unless the one delegate returns YES. | ||
225 | |||
226 | IMPORTANT: The delegate will be retained. | ||
227 | */ | ||
228 | -(void) addMouseDelegate:(id<CCMouseEventDelegate>) delegate priority:(NSInteger)priority; | ||
229 | |||
230 | /** removes a mouse delegate */ | ||
231 | -(void) removeMouseDelegate:(id) delegate; | ||
232 | |||
233 | /** Removes all mouse delegates, releasing all the delegates */ | ||
234 | -(void) removeAllMouseDelegates; | ||
235 | |||
236 | #pragma mark CCEventDispatcher - Keyboard | ||
237 | |||
238 | /** Adds a Keyboard delegate to the dispatcher's list. | ||
239 | Delegates with a lower priority value will be called before higher priority values. | ||
240 | All the events will be propgated to all the delegates, unless the one delegate returns YES. | ||
241 | |||
242 | IMPORTANT: The delegate will be retained. | ||
243 | */ | ||
244 | -(void) addKeyboardDelegate:(id<CCKeyboardEventDelegate>) delegate priority:(NSInteger)priority; | ||
245 | |||
246 | /** removes a mouse delegate */ | ||
247 | -(void) removeKeyboardDelegate:(id) delegate; | ||
248 | |||
249 | /** Removes all mouse delegates, releasing all the delegates */ | ||
250 | -(void) removeAllKeyboardDelegates; | ||
251 | |||
252 | #pragma mark CCEventDispatcher - Touches | ||
253 | |||
254 | /** Adds a Touch delegate to the dispatcher's list. | ||
255 | Delegates with a lower priority value will be called before higher priority values. | ||
256 | All the events will be propgated to all the delegates, unless the one delegate returns YES. | ||
257 | |||
258 | IMPORTANT: The delegate will be retained. | ||
259 | */ | ||
260 | - (void)addTouchDelegate:(id<CCTouchEventDelegate>)delegate priority:(NSInteger)priority; | ||
261 | |||
262 | /** Removes a touch delegate */ | ||
263 | - (void)removeTouchDelegate:(id) delegate; | ||
264 | |||
265 | /** Removes all touch delegates, releasing all the delegates */ | ||
266 | - (void)removeAllTouchDelegates; | ||
267 | |||
268 | #pragma mark CCEventDispatcher - Dispatch Events | ||
269 | |||
270 | #if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
271 | -(void) dispatchQueuedEvents; | ||
272 | #endif | ||
273 | |||
274 | @end | ||
275 | |||
276 | |||
277 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/Mac/CCEventDispatcher.m b/libs/cocos2d/Platforms/Mac/CCEventDispatcher.m new file mode 100755 index 0000000..1d1740e --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/CCEventDispatcher.m | |||
@@ -0,0 +1,645 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | // Only compile this code on Mac. These files should not be included on your iOS project. | ||
27 | // But in case they are included, it won't be compiled. | ||
28 | #import <Availability.h> | ||
29 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
30 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
31 | |||
32 | #import "CCEventDispatcher.h" | ||
33 | #import "../../ccConfig.h" | ||
34 | |||
35 | static CCEventDispatcher *sharedDispatcher = nil; | ||
36 | |||
37 | enum { | ||
38 | // mouse | ||
39 | kCCImplementsMouseDown = 1 << 0, | ||
40 | kCCImplementsMouseMoved = 1 << 1, | ||
41 | kCCImplementsMouseDragged = 1 << 2, | ||
42 | kCCImplementsMouseUp = 1 << 3, | ||
43 | kCCImplementsRightMouseDown = 1 << 4, | ||
44 | kCCImplementsRightMouseDragged = 1 << 5, | ||
45 | kCCImplementsRightMouseUp = 1 << 6, | ||
46 | kCCImplementsOtherMouseDown = 1 << 7, | ||
47 | kCCImplementsOtherMouseDragged = 1 << 8, | ||
48 | kCCImplementsOtherMouseUp = 1 << 9, | ||
49 | kCCImplementsScrollWheel = 1 << 10, | ||
50 | kCCImplementsMouseEntered = 1 << 11, | ||
51 | kCCImplementsMouseExited = 1 << 12, | ||
52 | |||
53 | kCCImplementsTouchesBegan = 1 << 13, | ||
54 | kCCImplementsTouchesMoved = 1 << 14, | ||
55 | kCCImplementsTouchesEnded = 1 << 15, | ||
56 | kCCImplementsTouchesCancelled = 1 << 16, | ||
57 | |||
58 | // keyboard | ||
59 | kCCImplementsKeyUp = 1 << 0, | ||
60 | kCCImplementsKeyDown = 1 << 1, | ||
61 | kCCImplementsFlagsChanged = 1 << 2, | ||
62 | }; | ||
63 | |||
64 | |||
65 | typedef struct _listEntry | ||
66 | { | ||
67 | struct _listEntry *prev, *next; | ||
68 | id delegate; | ||
69 | NSInteger priority; | ||
70 | NSUInteger flags; | ||
71 | } tListEntry; | ||
72 | |||
73 | |||
74 | #if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
75 | |||
76 | #define QUEUE_EVENT_MAX 128 | ||
77 | struct _eventQueue { | ||
78 | SEL selector; | ||
79 | NSEvent *event; | ||
80 | }; | ||
81 | |||
82 | static struct _eventQueue eventQueue[QUEUE_EVENT_MAX]; | ||
83 | static int eventQueueCount; | ||
84 | |||
85 | #endif // CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
86 | |||
87 | |||
88 | @implementation CCEventDispatcher | ||
89 | |||
90 | @synthesize dispatchEvents=dispatchEvents_; | ||
91 | |||
92 | |||
93 | +(CCEventDispatcher*) sharedDispatcher | ||
94 | { | ||
95 | @synchronized(self) { | ||
96 | if (sharedDispatcher == nil) | ||
97 | sharedDispatcher = [[self alloc] init]; // assignment not done here | ||
98 | } | ||
99 | return sharedDispatcher; | ||
100 | } | ||
101 | |||
102 | +(id) allocWithZone:(NSZone *)zone | ||
103 | { | ||
104 | @synchronized(self) { | ||
105 | NSAssert(sharedDispatcher == nil, @"Attempted to allocate a second instance of a singleton."); | ||
106 | return [super allocWithZone:zone]; | ||
107 | } | ||
108 | return nil; // on subsequent allocation attempts return nil | ||
109 | } | ||
110 | |||
111 | -(id) init | ||
112 | { | ||
113 | if( (self = [super init]) ) | ||
114 | { | ||
115 | // events enabled by default | ||
116 | dispatchEvents_ = YES; | ||
117 | |||
118 | // delegates | ||
119 | keyboardDelegates_ = NULL; | ||
120 | mouseDelegates_ = NULL; | ||
121 | touchDelegates_ = NULL; | ||
122 | |||
123 | #if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
124 | eventQueueCount = 0; | ||
125 | #endif | ||
126 | } | ||
127 | |||
128 | return self; | ||
129 | } | ||
130 | |||
131 | - (void) dealloc | ||
132 | { | ||
133 | [super dealloc]; | ||
134 | } | ||
135 | |||
136 | #pragma mark CCEventDispatcher - add / remove delegates | ||
137 | |||
138 | -(void) addDelegate:(id)delegate priority:(NSInteger)priority flags:(NSUInteger)flags list:(tListEntry**)list | ||
139 | { | ||
140 | tListEntry *listElement = malloc( sizeof(*listElement) ); | ||
141 | |||
142 | listElement->delegate = [delegate retain]; | ||
143 | listElement->priority = priority; | ||
144 | listElement->flags = flags; | ||
145 | listElement->next = listElement->prev = NULL; | ||
146 | |||
147 | // empty list ? | ||
148 | if( ! *list ) { | ||
149 | DL_APPEND( *list, listElement ); | ||
150 | |||
151 | } else { | ||
152 | BOOL added = NO; | ||
153 | |||
154 | for( tListEntry *elem = *list; elem ; elem = elem->next ) { | ||
155 | if( priority < elem->priority ) { | ||
156 | |||
157 | if( elem == *list ) | ||
158 | DL_PREPEND(*list, listElement); | ||
159 | else { | ||
160 | listElement->next = elem; | ||
161 | listElement->prev = elem->prev; | ||
162 | |||
163 | elem->prev->next = listElement; | ||
164 | elem->prev = listElement; | ||
165 | } | ||
166 | |||
167 | added = YES; | ||
168 | break; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | // Not added? priority has the higher value. Append it. | ||
173 | if( !added ) | ||
174 | DL_APPEND(*list, listElement); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | -(void) removeDelegate:(id)delegate fromList:(tListEntry**)list | ||
179 | { | ||
180 | tListEntry *entry, *tmp; | ||
181 | |||
182 | // updates with priority < 0 | ||
183 | DL_FOREACH_SAFE( *list, entry, tmp ) { | ||
184 | if( entry->delegate == delegate ) { | ||
185 | DL_DELETE( *list, entry ); | ||
186 | [delegate release]; | ||
187 | free(entry); | ||
188 | break; | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | |||
193 | -(void) removeAllDelegatesFromList:(tListEntry**)list | ||
194 | { | ||
195 | tListEntry *entry, *tmp; | ||
196 | |||
197 | DL_FOREACH_SAFE( *list, entry, tmp ) { | ||
198 | DL_DELETE( *list, entry ); | ||
199 | free(entry); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | |||
204 | -(void) addMouseDelegate:(id<CCMouseEventDelegate>) delegate priority:(NSInteger)priority | ||
205 | { | ||
206 | NSUInteger flags = 0; | ||
207 | |||
208 | flags |= ( [delegate respondsToSelector:@selector(ccMouseDown:)] ? kCCImplementsMouseDown : 0 ); | ||
209 | flags |= ( [delegate respondsToSelector:@selector(ccMouseDragged:)] ? kCCImplementsMouseDragged : 0 ); | ||
210 | flags |= ( [delegate respondsToSelector:@selector(ccMouseMoved:)] ? kCCImplementsMouseMoved : 0 ); | ||
211 | flags |= ( [delegate respondsToSelector:@selector(ccMouseUp:)] ? kCCImplementsMouseUp : 0 ); | ||
212 | |||
213 | flags |= ( [delegate respondsToSelector:@selector(ccRightMouseDown:)] ? kCCImplementsRightMouseDown : 0 ); | ||
214 | flags |= ( [delegate respondsToSelector:@selector(ccRightMouseDragged:)] ? kCCImplementsRightMouseDragged : 0 ); | ||
215 | flags |= ( [delegate respondsToSelector:@selector(ccRightMouseUp:)] ? kCCImplementsRightMouseUp : 0 ); | ||
216 | |||
217 | flags |= ( [delegate respondsToSelector:@selector(ccOtherMouseDown:)] ? kCCImplementsOtherMouseDown : 0 ); | ||
218 | flags |= ( [delegate respondsToSelector:@selector(ccOtherMouseDragged:)] ? kCCImplementsOtherMouseDragged : 0 ); | ||
219 | flags |= ( [delegate respondsToSelector:@selector(ccOtherMouseUp:)] ? kCCImplementsOtherMouseUp : 0 ); | ||
220 | |||
221 | flags |= ( [delegate respondsToSelector:@selector(ccMouseEntered:)] ? kCCImplementsMouseEntered : 0 ); | ||
222 | flags |= ( [delegate respondsToSelector:@selector(ccMouseExited:)] ? kCCImplementsMouseExited : 0 ); | ||
223 | |||
224 | flags |= ( [delegate respondsToSelector:@selector(ccScrollWheel:)] ? kCCImplementsScrollWheel : 0 ); | ||
225 | |||
226 | [self addDelegate:delegate priority:priority flags:flags list:&mouseDelegates_]; | ||
227 | } | ||
228 | |||
229 | -(void) removeMouseDelegate:(id) delegate | ||
230 | { | ||
231 | [self removeDelegate:delegate fromList:&mouseDelegates_]; | ||
232 | } | ||
233 | |||
234 | -(void) removeAllMouseDelegates | ||
235 | { | ||
236 | [self removeAllDelegatesFromList:&mouseDelegates_]; | ||
237 | } | ||
238 | |||
239 | -(void) addKeyboardDelegate:(id<CCKeyboardEventDelegate>) delegate priority:(NSInteger)priority | ||
240 | { | ||
241 | NSUInteger flags = 0; | ||
242 | |||
243 | flags |= ( [delegate respondsToSelector:@selector(ccKeyUp:)] ? kCCImplementsKeyUp : 0 ); | ||
244 | flags |= ( [delegate respondsToSelector:@selector(ccKeyDown:)] ? kCCImplementsKeyDown : 0 ); | ||
245 | flags |= ( [delegate respondsToSelector:@selector(ccFlagsChanged:)] ? kCCImplementsFlagsChanged : 0 ); | ||
246 | |||
247 | [self addDelegate:delegate priority:priority flags:flags list:&keyboardDelegates_]; | ||
248 | } | ||
249 | |||
250 | -(void) removeKeyboardDelegate:(id) delegate | ||
251 | { | ||
252 | [self removeDelegate:delegate fromList:&keyboardDelegates_]; | ||
253 | } | ||
254 | |||
255 | -(void) removeAllKeyboardDelegates | ||
256 | { | ||
257 | [self removeAllDelegatesFromList:&keyboardDelegates_]; | ||
258 | } | ||
259 | |||
260 | -(void) addTouchDelegate:(id<CCTouchEventDelegate>) delegate priority:(NSInteger)priority | ||
261 | { | ||
262 | NSUInteger flags = 0; | ||
263 | |||
264 | flags |= ( [delegate respondsToSelector:@selector(ccTouchesBeganWithEvent:)] ? kCCImplementsTouchesBegan : 0 ); | ||
265 | flags |= ( [delegate respondsToSelector:@selector(ccTouchesMovedWithEvent:)] ? kCCImplementsTouchesMoved : 0 ); | ||
266 | flags |= ( [delegate respondsToSelector:@selector(ccTouchesEndedWithEvent:)] ? kCCImplementsTouchesEnded : 0 ); | ||
267 | flags |= ( [delegate respondsToSelector:@selector(ccTouchesCancelledWithEvent:)] ? kCCImplementsTouchesCancelled : 0 ); | ||
268 | |||
269 | [self addDelegate:delegate priority:priority flags:flags list:&touchDelegates_]; | ||
270 | } | ||
271 | |||
272 | -(void) removeTouchDelegate:(id) delegate | ||
273 | { | ||
274 | [self removeDelegate:delegate fromList:&touchDelegates_]; | ||
275 | } | ||
276 | |||
277 | -(void) removeAllTouchDelegates | ||
278 | { | ||
279 | [self removeAllDelegatesFromList:&touchDelegates_]; | ||
280 | } | ||
281 | |||
282 | |||
283 | #pragma mark CCEventDispatcher - Mouse events | ||
284 | // | ||
285 | // Mouse events | ||
286 | // | ||
287 | |||
288 | // | ||
289 | // Left | ||
290 | // | ||
291 | - (void)mouseDown:(NSEvent *)event | ||
292 | { | ||
293 | if( dispatchEvents_ ) { | ||
294 | tListEntry *entry, *tmp; | ||
295 | |||
296 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
297 | if ( entry->flags & kCCImplementsMouseDown ) { | ||
298 | void *swallows = [entry->delegate performSelector:@selector(ccMouseDown:) withObject:event]; | ||
299 | if( swallows ) | ||
300 | break; | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | } | ||
305 | |||
306 | - (void)mouseMoved:(NSEvent *)event | ||
307 | { | ||
308 | if( dispatchEvents_ ) { | ||
309 | tListEntry *entry, *tmp; | ||
310 | |||
311 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
312 | if ( entry->flags & kCCImplementsMouseMoved ) { | ||
313 | void *swallows = [entry->delegate performSelector:@selector(ccMouseMoved:) withObject:event]; | ||
314 | if( swallows ) | ||
315 | break; | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | |||
321 | - (void)mouseDragged:(NSEvent *)event | ||
322 | { | ||
323 | if( dispatchEvents_ ) { | ||
324 | tListEntry *entry, *tmp; | ||
325 | |||
326 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
327 | if ( entry->flags & kCCImplementsMouseDragged ) { | ||
328 | void *swallows = [entry->delegate performSelector:@selector(ccMouseDragged:) withObject:event]; | ||
329 | if( swallows ) | ||
330 | break; | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | |||
336 | - (void)mouseUp:(NSEvent *)event | ||
337 | { | ||
338 | if( dispatchEvents_ ) { | ||
339 | tListEntry *entry, *tmp; | ||
340 | |||
341 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
342 | if ( entry->flags & kCCImplementsMouseUp ) { | ||
343 | void *swallows = [entry->delegate performSelector:@selector(ccMouseUp:) withObject:event]; | ||
344 | if( swallows ) | ||
345 | break; | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | |||
351 | // | ||
352 | // Mouse Right | ||
353 | // | ||
354 | - (void)rightMouseDown:(NSEvent *)event | ||
355 | { | ||
356 | if( dispatchEvents_ ) { | ||
357 | tListEntry *entry, *tmp; | ||
358 | |||
359 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
360 | if ( entry->flags & kCCImplementsRightMouseDown ) { | ||
361 | void *swallows = [entry->delegate performSelector:@selector(ccRightMouseDown:) withObject:event]; | ||
362 | if( swallows ) | ||
363 | break; | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | |||
369 | - (void)rightMouseDragged:(NSEvent *)event | ||
370 | { | ||
371 | if( dispatchEvents_ ) { | ||
372 | tListEntry *entry, *tmp; | ||
373 | |||
374 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
375 | if ( entry->flags & kCCImplementsRightMouseDragged ) { | ||
376 | void *swallows = [entry->delegate performSelector:@selector(ccRightMouseDragged:) withObject:event]; | ||
377 | if( swallows ) | ||
378 | break; | ||
379 | } | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | |||
384 | - (void)rightMouseUp:(NSEvent *)event | ||
385 | { | ||
386 | if( dispatchEvents_ ) { | ||
387 | tListEntry *entry, *tmp; | ||
388 | |||
389 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
390 | if ( entry->flags & kCCImplementsRightMouseUp ) { | ||
391 | void *swallows = [entry->delegate performSelector:@selector(ccRightMouseUp:) withObject:event]; | ||
392 | if( swallows ) | ||
393 | break; | ||
394 | } | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | |||
399 | // | ||
400 | // Mouse Other | ||
401 | // | ||
402 | - (void)otherMouseDown:(NSEvent *)event | ||
403 | { | ||
404 | if( dispatchEvents_ ) { | ||
405 | tListEntry *entry, *tmp; | ||
406 | |||
407 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
408 | if ( entry->flags & kCCImplementsOtherMouseDown ) { | ||
409 | void *swallows = [entry->delegate performSelector:@selector(ccOtherMouseDown:) withObject:event]; | ||
410 | if( swallows ) | ||
411 | break; | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | |||
417 | - (void)otherMouseDragged:(NSEvent *)event | ||
418 | { | ||
419 | if( dispatchEvents_ ) { | ||
420 | tListEntry *entry, *tmp; | ||
421 | |||
422 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
423 | if ( entry->flags & kCCImplementsOtherMouseDragged ) { | ||
424 | void *swallows = [entry->delegate performSelector:@selector(ccOtherMouseDragged:) withObject:event]; | ||
425 | if( swallows ) | ||
426 | break; | ||
427 | } | ||
428 | } | ||
429 | } | ||
430 | } | ||
431 | |||
432 | - (void)otherMouseUp:(NSEvent *)event | ||
433 | { | ||
434 | if( dispatchEvents_ ) { | ||
435 | tListEntry *entry, *tmp; | ||
436 | |||
437 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
438 | if ( entry->flags & kCCImplementsOtherMouseUp ) { | ||
439 | void *swallows = [entry->delegate performSelector:@selector(ccOtherMouseUp:) withObject:event]; | ||
440 | if( swallows ) | ||
441 | break; | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | |||
447 | // | ||
448 | // Scroll Wheel | ||
449 | // | ||
450 | - (void)scrollWheel:(NSEvent *)event | ||
451 | { | ||
452 | if( dispatchEvents_ ) { | ||
453 | tListEntry *entry, *tmp; | ||
454 | |||
455 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
456 | if ( entry->flags & kCCImplementsScrollWheel ) { | ||
457 | void *swallows = [entry->delegate performSelector:@selector(ccScrollWheel:) withObject:event]; | ||
458 | if( swallows ) | ||
459 | break; | ||
460 | } | ||
461 | } | ||
462 | } | ||
463 | } | ||
464 | |||
465 | // | ||
466 | // Mouse enter / exit | ||
467 | - (void)mouseExited:(NSEvent *)event | ||
468 | { | ||
469 | if( dispatchEvents_ ) { | ||
470 | tListEntry *entry, *tmp; | ||
471 | |||
472 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
473 | if ( entry->flags & kCCImplementsMouseEntered ) { | ||
474 | void *swallows = [entry->delegate performSelector:@selector(ccMouseEntered:) withObject:event]; | ||
475 | if( swallows ) | ||
476 | break; | ||
477 | } | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | |||
482 | - (void)mouseEntered:(NSEvent *)event | ||
483 | { | ||
484 | if( dispatchEvents_ ) { | ||
485 | tListEntry *entry, *tmp; | ||
486 | |||
487 | DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { | ||
488 | if ( entry->flags & kCCImplementsMouseExited) { | ||
489 | void *swallows = [entry->delegate performSelector:@selector(ccMouseExited:) withObject:event]; | ||
490 | if( swallows ) | ||
491 | break; | ||
492 | } | ||
493 | } | ||
494 | } | ||
495 | } | ||
496 | |||
497 | |||
498 | #pragma mark CCEventDispatcher - Keyboard events | ||
499 | |||
500 | // Keyboard events | ||
501 | - (void)keyDown:(NSEvent *)event | ||
502 | { | ||
503 | if( dispatchEvents_ ) { | ||
504 | tListEntry *entry, *tmp; | ||
505 | |||
506 | DL_FOREACH_SAFE( keyboardDelegates_, entry, tmp ) { | ||
507 | if ( entry->flags & kCCImplementsKeyDown ) { | ||
508 | void *swallows = [entry->delegate performSelector:@selector(ccKeyDown:) withObject:event]; | ||
509 | if( swallows ) | ||
510 | break; | ||
511 | } | ||
512 | } | ||
513 | } | ||
514 | } | ||
515 | |||
516 | - (void)keyUp:(NSEvent *)event | ||
517 | { | ||
518 | if( dispatchEvents_ ) { | ||
519 | tListEntry *entry, *tmp; | ||
520 | |||
521 | DL_FOREACH_SAFE( keyboardDelegates_, entry, tmp ) { | ||
522 | if ( entry->flags & kCCImplementsKeyUp ) { | ||
523 | void *swallows = [entry->delegate performSelector:@selector(ccKeyUp:) withObject:event]; | ||
524 | if( swallows ) | ||
525 | break; | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | } | ||
530 | |||
531 | - (void)flagsChanged:(NSEvent *)event | ||
532 | { | ||
533 | if( dispatchEvents_ ) { | ||
534 | tListEntry *entry, *tmp; | ||
535 | |||
536 | DL_FOREACH_SAFE( keyboardDelegates_, entry, tmp ) { | ||
537 | if ( entry->flags & kCCImplementsFlagsChanged ) { | ||
538 | void *swallows = [entry->delegate performSelector:@selector(ccFlagsChanged:) withObject:event]; | ||
539 | if( swallows ) | ||
540 | break; | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | } | ||
545 | |||
546 | |||
547 | #pragma mark CCEventDispatcher - Touch events | ||
548 | |||
549 | - (void)touchesBeganWithEvent:(NSEvent *)event | ||
550 | { | ||
551 | if( dispatchEvents_ ) { | ||
552 | tListEntry *entry, *tmp; | ||
553 | |||
554 | DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) { | ||
555 | if ( entry->flags & kCCImplementsTouchesBegan) { | ||
556 | void *swallows = [entry->delegate performSelector:@selector(ccTouchesBeganWithEvent:) withObject:event]; | ||
557 | if( swallows ) | ||
558 | break; | ||
559 | } | ||
560 | } | ||
561 | } | ||
562 | } | ||
563 | |||
564 | - (void)touchesMovedWithEvent:(NSEvent *)event | ||
565 | { | ||
566 | if( dispatchEvents_ ) { | ||
567 | tListEntry *entry, *tmp; | ||
568 | |||
569 | DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) { | ||
570 | if ( entry->flags & kCCImplementsTouchesMoved) { | ||
571 | void *swallows = [entry->delegate performSelector:@selector(ccTouchesMovedWithEvent:) withObject:event]; | ||
572 | if( swallows ) | ||
573 | break; | ||
574 | } | ||
575 | } | ||
576 | } | ||
577 | } | ||
578 | |||
579 | - (void)touchesEndedWithEvent:(NSEvent *)event | ||
580 | { | ||
581 | if( dispatchEvents_ ) { | ||
582 | tListEntry *entry, *tmp; | ||
583 | |||
584 | DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) { | ||
585 | if ( entry->flags & kCCImplementsTouchesEnded) { | ||
586 | void *swallows = [entry->delegate performSelector:@selector(ccTouchesEndedWithEvent:) withObject:event]; | ||
587 | if( swallows ) | ||
588 | break; | ||
589 | } | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | |||
594 | - (void)touchesCancelledWithEvent:(NSEvent *)event | ||
595 | { | ||
596 | if( dispatchEvents_ ) { | ||
597 | tListEntry *entry, *tmp; | ||
598 | |||
599 | DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) { | ||
600 | if ( entry->flags & kCCImplementsTouchesCancelled) { | ||
601 | void *swallows = [entry->delegate performSelector:@selector(ccTouchesCancelledWithEvent:) withObject:event]; | ||
602 | if( swallows ) | ||
603 | break; | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | } | ||
608 | |||
609 | |||
610 | #pragma mark CCEventDispatcher - queue events | ||
611 | |||
612 | #if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
613 | -(void) queueEvent:(NSEvent*)event selector:(SEL)selector | ||
614 | { | ||
615 | NSAssert( eventQueueCount < QUEUE_EVENT_MAX, @"CCEventDispatcher: recompile. Increment QUEUE_EVENT_MAX value"); | ||
616 | |||
617 | @synchronized (self) { | ||
618 | eventQueue[eventQueueCount].selector = selector; | ||
619 | eventQueue[eventQueueCount].event = [event copy]; | ||
620 | |||
621 | eventQueueCount++; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | -(void) dispatchQueuedEvents | ||
626 | { | ||
627 | @synchronized (self) { | ||
628 | for( int i=0; i < eventQueueCount; i++ ) { | ||
629 | SEL sel = eventQueue[i].selector; | ||
630 | NSEvent *event = eventQueue[i].event; | ||
631 | |||
632 | [self performSelector:sel withObject:event]; | ||
633 | |||
634 | [event release]; | ||
635 | } | ||
636 | |||
637 | eventQueueCount = 0; | ||
638 | } | ||
639 | } | ||
640 | #endif // CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
641 | |||
642 | |||
643 | @end | ||
644 | |||
645 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/Mac/MacGLView.h b/libs/cocos2d/Platforms/Mac/MacGLView.h new file mode 100755 index 0000000..8099273 --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/MacGLView.h | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | // Only compile this code on Mac. These files should not be included on your iOS project. | ||
27 | // But in case they are included, it won't be compiled. | ||
28 | #import <Availability.h> | ||
29 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
30 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
31 | |||
32 | #import <Cocoa/Cocoa.h> | ||
33 | |||
34 | #import "../../ccConfig.h" | ||
35 | |||
36 | //PROTOCOLS: | ||
37 | |||
38 | @protocol MacEventDelegate <NSObject> | ||
39 | // Mouse | ||
40 | - (void)mouseDown:(NSEvent *)theEvent; | ||
41 | - (void)mouseUp:(NSEvent *)theEvent; | ||
42 | - (void)mouseMoved:(NSEvent *)theEvent; | ||
43 | - (void)mouseDragged:(NSEvent *)theEvent; | ||
44 | - (void)rightMouseDown:(NSEvent*)event; | ||
45 | - (void)rightMouseDragged:(NSEvent*)event; | ||
46 | - (void)rightMouseUp:(NSEvent*)event; | ||
47 | - (void)otherMouseDown:(NSEvent*)event; | ||
48 | - (void)otherMouseDragged:(NSEvent*)event; | ||
49 | - (void)otherMouseUp:(NSEvent*)event; | ||
50 | - (void)scrollWheel:(NSEvent *)theEvent; | ||
51 | - (void)mouseEntered:(NSEvent *)theEvent; | ||
52 | - (void)mouseExited:(NSEvent *)theEvent; | ||
53 | |||
54 | |||
55 | // Keyboard | ||
56 | - (void)keyDown:(NSEvent *)theEvent; | ||
57 | - (void)keyUp:(NSEvent *)theEvent; | ||
58 | - (void)flagsChanged:(NSEvent *)theEvent; | ||
59 | |||
60 | // Touches | ||
61 | - (void)touchesBeganWithEvent:(NSEvent *)event; | ||
62 | - (void)touchesMovedWithEvent:(NSEvent *)event; | ||
63 | - (void)touchesEndedWithEvent:(NSEvent *)event; | ||
64 | - (void)touchesCancelledWithEvent:(NSEvent *)event; | ||
65 | |||
66 | #if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
67 | - (void)queueEvent:(NSEvent*)event selector:(SEL)selector; | ||
68 | #endif | ||
69 | |||
70 | @end | ||
71 | |||
72 | /** MacGLView | ||
73 | |||
74 | Only available for Mac OS X | ||
75 | */ | ||
76 | @interface MacGLView : NSOpenGLView { | ||
77 | id<MacEventDelegate> eventDelegate_; | ||
78 | } | ||
79 | |||
80 | @property (nonatomic, readwrite, assign) id<MacEventDelegate> eventDelegate; | ||
81 | |||
82 | // initializes the MacGLView with a frame rect and an OpenGL context | ||
83 | - (id) initWithFrame:(NSRect)frameRect shareContext:(NSOpenGLContext*)context; | ||
84 | |||
85 | // private | ||
86 | +(void) load_; | ||
87 | @end | ||
88 | |||
89 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED \ No newline at end of file | ||
diff --git a/libs/cocos2d/Platforms/Mac/MacGLView.m b/libs/cocos2d/Platforms/Mac/MacGLView.m new file mode 100755 index 0000000..a041dc8 --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/MacGLView.m | |||
@@ -0,0 +1,242 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | * Idea of subclassing NSOpenGLView was taken from "TextureUpload" Apple's sample | ||
28 | */ | ||
29 | |||
30 | // Only compile this code on Mac. These files should not be included on your iOS project. | ||
31 | // But in case they are included, it won't be compiled. | ||
32 | #import <Availability.h> | ||
33 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
34 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
35 | |||
36 | #import "MacGLView.h" | ||
37 | #import <OpenGL/gl.h> | ||
38 | |||
39 | #import "CCDirectorMac.h" | ||
40 | #import "../../ccConfig.h" | ||
41 | |||
42 | |||
43 | @implementation MacGLView | ||
44 | |||
45 | @synthesize eventDelegate = eventDelegate_; | ||
46 | |||
47 | +(void) load_ | ||
48 | { | ||
49 | NSLog(@"%@ loaded", self); | ||
50 | } | ||
51 | |||
52 | - (id) initWithFrame:(NSRect)frameRect | ||
53 | { | ||
54 | self = [self initWithFrame:frameRect shareContext:nil]; | ||
55 | return self; | ||
56 | } | ||
57 | |||
58 | - (id) initWithFrame:(NSRect)frameRect shareContext:(NSOpenGLContext*)context | ||
59 | { | ||
60 | NSOpenGLPixelFormatAttribute attribs[] = | ||
61 | { | ||
62 | NSOpenGLPFAAccelerated, | ||
63 | NSOpenGLPFANoRecovery, | ||
64 | NSOpenGLPFADoubleBuffer, | ||
65 | NSOpenGLPFADepthSize, 24, | ||
66 | |||
67 | 0 | ||
68 | }; | ||
69 | |||
70 | NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; | ||
71 | |||
72 | if (!pixelFormat) | ||
73 | NSLog(@"No OpenGL pixel format"); | ||
74 | |||
75 | if( (self = [super initWithFrame:frameRect pixelFormat:[pixelFormat autorelease]]) ) { | ||
76 | |||
77 | if( context ) | ||
78 | [self setOpenGLContext:context]; | ||
79 | |||
80 | // Synchronize buffer swaps with vertical refresh rate | ||
81 | GLint swapInt = 1; | ||
82 | [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; | ||
83 | |||
84 | // GLint order = -1; | ||
85 | // [[self openGLContext] setValues:&order forParameter:NSOpenGLCPSurfaceOrder]; | ||
86 | |||
87 | // event delegate | ||
88 | eventDelegate_ = nil; | ||
89 | } | ||
90 | |||
91 | return self; | ||
92 | } | ||
93 | |||
94 | - (void) reshape | ||
95 | { | ||
96 | // We draw on a secondary thread through the display link | ||
97 | // When resizing the view, -reshape is called automatically on the main thread | ||
98 | // Add a mutex around to avoid the threads accessing the context simultaneously when resizing | ||
99 | CGLLockContext([[self openGLContext] CGLContextObj]); | ||
100 | |||
101 | NSRect rect = [self bounds]; | ||
102 | |||
103 | CCDirector *director = [CCDirector sharedDirector]; | ||
104 | [director reshapeProjection: NSSizeToCGSize(rect.size) ]; | ||
105 | |||
106 | // avoid flicker | ||
107 | [director drawScene]; | ||
108 | // [self setNeedsDisplay:YES]; | ||
109 | |||
110 | CGLUnlockContext([[self openGLContext] CGLContextObj]); | ||
111 | } | ||
112 | |||
113 | - (void) dealloc | ||
114 | { | ||
115 | |||
116 | [super dealloc]; | ||
117 | } | ||
118 | |||
119 | #if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
120 | #define DISPATCH_EVENT(__event__, __selector__) [eventDelegate_ queueEvent:__event__ selector:__selector__]; | ||
121 | #else | ||
122 | #define DISPATCH_EVENT(__event__, __selector__) \ | ||
123 | id obj = eventDelegate_; \ | ||
124 | [obj performSelector:__selector__ \ | ||
125 | onThread:[(CCDirectorMac*)[CCDirector sharedDirector] runningThread] \ | ||
126 | withObject:__event__ \ | ||
127 | waitUntilDone:NO]; | ||
128 | #endif | ||
129 | |||
130 | #pragma mark MacGLView - Mouse events | ||
131 | - (void)mouseDown:(NSEvent *)theEvent | ||
132 | { | ||
133 | DISPATCH_EVENT(theEvent, _cmd); | ||
134 | } | ||
135 | |||
136 | - (void)mouseMoved:(NSEvent *)theEvent | ||
137 | { | ||
138 | DISPATCH_EVENT(theEvent, _cmd); | ||
139 | } | ||
140 | |||
141 | - (void)mouseDragged:(NSEvent *)theEvent | ||
142 | { | ||
143 | DISPATCH_EVENT(theEvent, _cmd); | ||
144 | } | ||
145 | |||
146 | - (void)mouseUp:(NSEvent *)theEvent | ||
147 | { | ||
148 | DISPATCH_EVENT(theEvent, _cmd); | ||
149 | } | ||
150 | |||
151 | - (void)rightMouseDown:(NSEvent *)theEvent { | ||
152 | DISPATCH_EVENT(theEvent, _cmd); | ||
153 | } | ||
154 | |||
155 | - (void)rightMouseDragged:(NSEvent *)theEvent { | ||
156 | DISPATCH_EVENT(theEvent, _cmd); | ||
157 | } | ||
158 | |||
159 | - (void)rightMouseUp:(NSEvent *)theEvent { | ||
160 | DISPATCH_EVENT(theEvent, _cmd); | ||
161 | } | ||
162 | |||
163 | - (void)otherMouseDown:(NSEvent *)theEvent { | ||
164 | DISPATCH_EVENT(theEvent, _cmd); | ||
165 | } | ||
166 | |||
167 | - (void)otherMouseDragged:(NSEvent *)theEvent { | ||
168 | DISPATCH_EVENT(theEvent, _cmd); | ||
169 | } | ||
170 | |||
171 | - (void)otherMouseUp:(NSEvent *)theEvent { | ||
172 | DISPATCH_EVENT(theEvent, _cmd); | ||
173 | } | ||
174 | |||
175 | - (void)mouseEntered:(NSEvent *)theEvent { | ||
176 | DISPATCH_EVENT(theEvent, _cmd); | ||
177 | } | ||
178 | |||
179 | - (void)mouseExited:(NSEvent *)theEvent { | ||
180 | DISPATCH_EVENT(theEvent, _cmd); | ||
181 | } | ||
182 | |||
183 | -(void) scrollWheel:(NSEvent *)theEvent { | ||
184 | DISPATCH_EVENT(theEvent, _cmd); | ||
185 | } | ||
186 | |||
187 | #pragma mark MacGLView - Key events | ||
188 | |||
189 | -(BOOL) becomeFirstResponder | ||
190 | { | ||
191 | return YES; | ||
192 | } | ||
193 | |||
194 | -(BOOL) acceptsFirstResponder | ||
195 | { | ||
196 | return YES; | ||
197 | } | ||
198 | |||
199 | -(BOOL) resignFirstResponder | ||
200 | { | ||
201 | return YES; | ||
202 | } | ||
203 | |||
204 | - (void)keyDown:(NSEvent *)theEvent | ||
205 | { | ||
206 | DISPATCH_EVENT(theEvent, _cmd); | ||
207 | } | ||
208 | |||
209 | - (void)keyUp:(NSEvent *)theEvent | ||
210 | { | ||
211 | DISPATCH_EVENT(theEvent, _cmd); | ||
212 | } | ||
213 | |||
214 | - (void)flagsChanged:(NSEvent *)theEvent | ||
215 | { | ||
216 | DISPATCH_EVENT(theEvent, _cmd); | ||
217 | } | ||
218 | |||
219 | #pragma mark MacGLView - Touch events | ||
220 | - (void)touchesBeganWithEvent:(NSEvent *)theEvent | ||
221 | { | ||
222 | DISPATCH_EVENT(theEvent, _cmd); | ||
223 | } | ||
224 | |||
225 | - (void)touchesMovedWithEvent:(NSEvent *)theEvent | ||
226 | { | ||
227 | DISPATCH_EVENT(theEvent, _cmd); | ||
228 | } | ||
229 | |||
230 | - (void)touchesEndedWithEvent:(NSEvent *)theEvent | ||
231 | { | ||
232 | DISPATCH_EVENT(theEvent, _cmd); | ||
233 | } | ||
234 | |||
235 | - (void)touchesCancelledWithEvent:(NSEvent *)theEvent | ||
236 | { | ||
237 | DISPATCH_EVENT(theEvent, _cmd); | ||
238 | } | ||
239 | |||
240 | @end | ||
241 | |||
242 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/Mac/MacWindow.h b/libs/cocos2d/Platforms/Mac/MacWindow.h new file mode 100755 index 0000000..716fe9b --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/MacWindow.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Ricardo Quesada | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | // Only compile this code on Mac. These files should not be included on your iOS project. | ||
26 | // But in case they are included, it won't be compiled. | ||
27 | #import <Availability.h> | ||
28 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
29 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
30 | |||
31 | #import <Cocoa/Cocoa.h> | ||
32 | |||
33 | |||
34 | @interface MacWindow : NSWindow | ||
35 | { | ||
36 | } | ||
37 | - (id) initWithFrame:(NSRect)frame fullscreen:(BOOL)fullscreen; | ||
38 | |||
39 | @end | ||
40 | |||
41 | |||
42 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED \ No newline at end of file | ||
diff --git a/libs/cocos2d/Platforms/Mac/MacWindow.m b/libs/cocos2d/Platforms/Mac/MacWindow.m new file mode 100755 index 0000000..28736a3 --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/MacWindow.m | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Ricardo Quesada | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | // Only compile this code on Mac. These files should not be included on your iOS project. | ||
26 | // But in case they are included, it won't be compiled. | ||
27 | #import <Availability.h> | ||
28 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
29 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
30 | |||
31 | #import "MacWindow.h" | ||
32 | |||
33 | |||
34 | @implementation MacWindow | ||
35 | |||
36 | - (id) initWithFrame:(NSRect)frame fullscreen:(BOOL)fullscreen | ||
37 | { | ||
38 | int styleMask = fullscreen ? NSBackingStoreBuffered : ( NSTitledWindowMask | NSClosableWindowMask ); | ||
39 | self = [self initWithContentRect:frame | ||
40 | styleMask:styleMask | ||
41 | backing:NSBackingStoreBuffered | ||
42 | defer:YES]; | ||
43 | |||
44 | if (self != nil) | ||
45 | { | ||
46 | if(fullscreen) | ||
47 | { | ||
48 | [self setLevel:NSMainMenuWindowLevel+1]; | ||
49 | [self setHidesOnDeactivate:YES]; | ||
50 | [self setHasShadow:NO]; | ||
51 | } | ||
52 | |||
53 | [self setAcceptsMouseMovedEvents:NO]; | ||
54 | [self setOpaque:YES]; | ||
55 | } | ||
56 | return self; | ||
57 | } | ||
58 | |||
59 | - (BOOL) canBecomeKeyWindow | ||
60 | { | ||
61 | return YES; | ||
62 | } | ||
63 | |||
64 | - (BOOL) canBecomeMainWindow | ||
65 | { | ||
66 | return YES; | ||
67 | } | ||
68 | @end | ||
69 | |||
70 | #endif // __MAC_OS_X_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/CCDirectorIOS.h b/libs/cocos2d/Platforms/iOS/CCDirectorIOS.h new file mode 100755 index 0000000..1c264e4 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/CCDirectorIOS.h | |||
@@ -0,0 +1,255 @@ | |||
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 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
28 | // But in case they are included, it won't be compiled. | ||
29 | #import <Availability.h> | ||
30 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
31 | |||
32 | #import "../../CCDirector.h" | ||
33 | |||
34 | /** @typedef ccDeviceOrientation | ||
35 | Possible device orientations | ||
36 | */ | ||
37 | typedef enum { | ||
38 | /// Device oriented vertically, home button on the bottom | ||
39 | kCCDeviceOrientationPortrait = UIDeviceOrientationPortrait, | ||
40 | /// Device oriented vertically, home button on the top | ||
41 | kCCDeviceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown, | ||
42 | /// Device oriented horizontally, home button on the right | ||
43 | kCCDeviceOrientationLandscapeLeft = UIDeviceOrientationLandscapeLeft, | ||
44 | /// Device oriented horizontally, home button on the left | ||
45 | kCCDeviceOrientationLandscapeRight = UIDeviceOrientationLandscapeRight, | ||
46 | |||
47 | // Backward compatibility stuff | ||
48 | CCDeviceOrientationPortrait = kCCDeviceOrientationPortrait, | ||
49 | CCDeviceOrientationPortraitUpsideDown = kCCDeviceOrientationPortraitUpsideDown, | ||
50 | CCDeviceOrientationLandscapeLeft = kCCDeviceOrientationLandscapeLeft, | ||
51 | CCDeviceOrientationLandscapeRight = kCCDeviceOrientationLandscapeRight, | ||
52 | } ccDeviceOrientation; | ||
53 | |||
54 | /** @typedef ccDirectorType | ||
55 | Possible Director Types. | ||
56 | @since v0.8.2 | ||
57 | */ | ||
58 | typedef enum { | ||
59 | /** Will use a Director that triggers the main loop from an NSTimer object | ||
60 | * | ||
61 | * Features and Limitations: | ||
62 | * - Integrates OK with UIKit objects | ||
63 | * - It the slowest director | ||
64 | * - The invertal update is customizable from 1 to 60 | ||
65 | */ | ||
66 | kCCDirectorTypeNSTimer, | ||
67 | |||
68 | /** will use a Director that triggers the main loop from a custom main loop. | ||
69 | * | ||
70 | * Features and Limitations: | ||
71 | * - Faster than NSTimer Director | ||
72 | * - It doesn't integrate well with UIKit objecgts | ||
73 | * - The interval update can't be customizable | ||
74 | */ | ||
75 | kCCDirectorTypeMainLoop, | ||
76 | |||
77 | /** Will use a Director that triggers the main loop from a thread, but the main loop will be executed on the main thread. | ||
78 | * | ||
79 | * Features and Limitations: | ||
80 | * - Faster than NSTimer Director | ||
81 | * - It doesn't integrate well with UIKit objecgts | ||
82 | * - The interval update can't be customizable | ||
83 | */ | ||
84 | kCCDirectorTypeThreadMainLoop, | ||
85 | |||
86 | /** Will use a Director that synchronizes timers with the refresh rate of the display. | ||
87 | * | ||
88 | * Features and Limitations: | ||
89 | * - Faster than NSTimer Director | ||
90 | * - Only available on 3.1+ | ||
91 | * - Scheduled timers & drawing are synchronizes with the refresh rate of the display | ||
92 | * - Integrates OK with UIKit objects | ||
93 | * - The interval update can be 1/60, 1/30, 1/15 | ||
94 | */ | ||
95 | kCCDirectorTypeDisplayLink, | ||
96 | |||
97 | /** Default director is the NSTimer directory */ | ||
98 | kCCDirectorTypeDefault = kCCDirectorTypeNSTimer, | ||
99 | |||
100 | // backward compatibility stuff | ||
101 | CCDirectorTypeNSTimer = kCCDirectorTypeNSTimer, | ||
102 | CCDirectorTypeMainLoop = kCCDirectorTypeMainLoop, | ||
103 | CCDirectorTypeThreadMainLoop = kCCDirectorTypeThreadMainLoop, | ||
104 | CCDirectorTypeDisplayLink = kCCDirectorTypeDisplayLink, | ||
105 | CCDirectorTypeDefault = kCCDirectorTypeDefault, | ||
106 | |||
107 | |||
108 | } ccDirectorType; | ||
109 | |||
110 | /** CCDirector extensions for iPhone | ||
111 | */ | ||
112 | @interface CCDirector (iOSExtension) | ||
113 | |||
114 | // rotates the screen if an orientation differnent than Portrait is used | ||
115 | -(void) applyOrientation; | ||
116 | |||
117 | /** Sets the device orientation. | ||
118 | If the orientation is going to be controlled by an UIViewController, then the orientation should be Portrait | ||
119 | */ | ||
120 | -(void) setDeviceOrientation:(ccDeviceOrientation)orientation; | ||
121 | |||
122 | /** returns the device orientation */ | ||
123 | -(ccDeviceOrientation) deviceOrientation; | ||
124 | |||
125 | /** The size in pixels of the surface. It could be different than the screen size. | ||
126 | High-res devices might have a higher surface size than the screen size. | ||
127 | In non High-res device the contentScale will be emulated. | ||
128 | |||
129 | The recommend way to enable Retina Display is by using the "enableRetinaDisplay:(BOOL)enabled" method. | ||
130 | |||
131 | @since v0.99.4 | ||
132 | */ | ||
133 | -(void) setContentScaleFactor:(CGFloat)scaleFactor; | ||
134 | |||
135 | /** Will enable Retina Display on devices that supports it. | ||
136 | It will enable Retina Display on iPhone4 and iPod Touch 4. | ||
137 | It will return YES, if it could enabled it, otherwise it will return NO. | ||
138 | |||
139 | This is the recommened way to enable Retina Display. | ||
140 | @since v0.99.5 | ||
141 | */ | ||
142 | -(BOOL) enableRetinaDisplay:(BOOL)yes; | ||
143 | |||
144 | |||
145 | /** returns the content scale factor */ | ||
146 | -(CGFloat) contentScaleFactor; | ||
147 | @end | ||
148 | |||
149 | @interface CCDirector (iOSExtensionClassMethods) | ||
150 | |||
151 | /** There are 4 types of Director. | ||
152 | - kCCDirectorTypeNSTimer (default) | ||
153 | - kCCDirectorTypeMainLoop | ||
154 | - kCCDirectorTypeThreadMainLoop | ||
155 | - kCCDirectorTypeDisplayLink | ||
156 | |||
157 | Each Director has it's own benefits, limitations. | ||
158 | If you are using SDK 3.1 or newer it is recommed to use the DisplayLink director | ||
159 | |||
160 | This method should be called before any other call to the director. | ||
161 | |||
162 | It will return NO if the director type is kCCDirectorTypeDisplayLink and the running SDK is < 3.1. Otherwise it will return YES. | ||
163 | |||
164 | @since v0.8.2 | ||
165 | */ | ||
166 | +(BOOL) setDirectorType:(ccDirectorType) directorType; | ||
167 | @end | ||
168 | |||
169 | #pragma mark - | ||
170 | #pragma mark CCDirectorIOS | ||
171 | |||
172 | /** CCDirectorIOS: Base class of iOS directors | ||
173 | @since v0.99.5 | ||
174 | */ | ||
175 | @interface CCDirectorIOS : CCDirector | ||
176 | { | ||
177 | /* orientation */ | ||
178 | ccDeviceOrientation deviceOrientation_; | ||
179 | |||
180 | /* contentScaleFactor could be simulated */ | ||
181 | BOOL isContentScaleSupported_; | ||
182 | |||
183 | } | ||
184 | @end | ||
185 | |||
186 | /** FastDirector is a Director that triggers the main loop as fast as possible. | ||
187 | * | ||
188 | * Features and Limitations: | ||
189 | * - Faster than "normal" director | ||
190 | * - Consumes more battery than the "normal" director | ||
191 | * - It has some issues while using UIKit objects | ||
192 | */ | ||
193 | @interface CCDirectorFast : CCDirectorIOS | ||
194 | { | ||
195 | BOOL isRunning; | ||
196 | |||
197 | NSAutoreleasePool *autoreleasePool; | ||
198 | } | ||
199 | -(void) mainLoop; | ||
200 | @end | ||
201 | |||
202 | /** ThreadedFastDirector is a Director that triggers the main loop from a thread. | ||
203 | * | ||
204 | * Features and Limitations: | ||
205 | * - Faster than "normal" director | ||
206 | * - Consumes more battery than the "normal" director | ||
207 | * - It can be used with UIKit objects | ||
208 | * | ||
209 | * @since v0.8.2 | ||
210 | */ | ||
211 | @interface CCDirectorFastThreaded : CCDirectorIOS | ||
212 | { | ||
213 | BOOL isRunning; | ||
214 | } | ||
215 | -(void) mainLoop; | ||
216 | @end | ||
217 | |||
218 | /** DisplayLinkDirector is a Director that synchronizes timers with the refresh rate of the display. | ||
219 | * | ||
220 | * Features and Limitations: | ||
221 | * - Only available on 3.1+ | ||
222 | * - Scheduled timers & drawing are synchronizes with the refresh rate of the display | ||
223 | * - Only supports animation intervals of 1/60 1/30 & 1/15 | ||
224 | * | ||
225 | * It is the recommended Director if the SDK is 3.1 or newer | ||
226 | * | ||
227 | * @since v0.8.2 | ||
228 | */ | ||
229 | @interface CCDirectorDisplayLink : CCDirectorIOS | ||
230 | { | ||
231 | id displayLink; | ||
232 | } | ||
233 | -(void) mainLoop:(id)sender; | ||
234 | @end | ||
235 | |||
236 | /** TimerDirector is a Director that calls the main loop from an NSTimer object | ||
237 | * | ||
238 | * Features and Limitations: | ||
239 | * - Integrates OK with UIKit objects | ||
240 | * - It the slowest director | ||
241 | * - The invertal update is customizable from 1 to 60 | ||
242 | * | ||
243 | * It is the default Director. | ||
244 | */ | ||
245 | @interface CCDirectorTimer : CCDirectorIOS | ||
246 | { | ||
247 | NSTimer *animationTimer; | ||
248 | } | ||
249 | -(void) mainLoop; | ||
250 | @end | ||
251 | |||
252 | // optimization. Should only be used to read it. Never to write it. | ||
253 | extern CGFloat __ccContentScaleFactor; | ||
254 | |||
255 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/CCDirectorIOS.m b/libs/cocos2d/Platforms/iOS/CCDirectorIOS.m new file mode 100755 index 0000000..c483665 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/CCDirectorIOS.m | |||
@@ -0,0 +1,735 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
28 | // But in case they are included, it won't be compiled. | ||
29 | #import <Availability.h> | ||
30 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
31 | |||
32 | #import <unistd.h> | ||
33 | |||
34 | // cocos2d imports | ||
35 | #import "CCDirectorIOS.h" | ||
36 | #import "CCTouchDelegateProtocol.h" | ||
37 | #import "CCTouchDispatcher.h" | ||
38 | #import "../../CCScheduler.h" | ||
39 | #import "../../CCActionManager.h" | ||
40 | #import "../../CCTextureCache.h" | ||
41 | #import "../../ccMacros.h" | ||
42 | #import "../../CCScene.h" | ||
43 | |||
44 | // support imports | ||
45 | #import "glu.h" | ||
46 | #import "../../Support/OpenGL_Internal.h" | ||
47 | #import "../../Support/CGPointExtension.h" | ||
48 | |||
49 | #import "CCLayer.h" | ||
50 | |||
51 | #if CC_ENABLE_PROFILERS | ||
52 | #import "../../Support/CCProfiling.h" | ||
53 | #endif | ||
54 | |||
55 | |||
56 | #pragma mark - | ||
57 | #pragma mark Director - global variables (optimization) | ||
58 | |||
59 | CGFloat __ccContentScaleFactor = 1; | ||
60 | |||
61 | #pragma mark - | ||
62 | #pragma mark Director iOS | ||
63 | |||
64 | @interface CCDirector () | ||
65 | -(void) setNextScene; | ||
66 | -(void) showFPS; | ||
67 | -(void) calculateDeltaTime; | ||
68 | @end | ||
69 | |||
70 | @implementation CCDirector (iOSExtensionClassMethods) | ||
71 | |||
72 | +(Class) defaultDirector | ||
73 | { | ||
74 | return [CCDirectorTimer class]; | ||
75 | } | ||
76 | |||
77 | + (BOOL) setDirectorType:(ccDirectorType)type | ||
78 | { | ||
79 | if( type == CCDirectorTypeDisplayLink ) { | ||
80 | NSString *reqSysVer = @"3.1"; | ||
81 | NSString *currSysVer = [[UIDevice currentDevice] systemVersion]; | ||
82 | |||
83 | if([currSysVer compare:reqSysVer options:NSNumericSearch] == NSOrderedAscending) | ||
84 | return NO; | ||
85 | } | ||
86 | switch (type) { | ||
87 | case CCDirectorTypeNSTimer: | ||
88 | [CCDirectorTimer sharedDirector]; | ||
89 | break; | ||
90 | case CCDirectorTypeDisplayLink: | ||
91 | [CCDirectorDisplayLink sharedDirector]; | ||
92 | break; | ||
93 | case CCDirectorTypeMainLoop: | ||
94 | [CCDirectorFast sharedDirector]; | ||
95 | break; | ||
96 | case CCDirectorTypeThreadMainLoop: | ||
97 | [CCDirectorFastThreaded sharedDirector]; | ||
98 | break; | ||
99 | default: | ||
100 | NSAssert(NO,@"Unknown director type"); | ||
101 | } | ||
102 | |||
103 | return YES; | ||
104 | } | ||
105 | |||
106 | @end | ||
107 | |||
108 | |||
109 | |||
110 | #pragma mark - | ||
111 | #pragma mark CCDirectorIOS | ||
112 | |||
113 | @interface CCDirectorIOS () | ||
114 | -(void) updateContentScaleFactor; | ||
115 | |||
116 | @end | ||
117 | |||
118 | @implementation CCDirectorIOS | ||
119 | |||
120 | - (id) init | ||
121 | { | ||
122 | if( (self=[super init]) ) { | ||
123 | |||
124 | // portrait mode default | ||
125 | deviceOrientation_ = CCDeviceOrientationPortrait; | ||
126 | |||
127 | __ccContentScaleFactor = 1; | ||
128 | isContentScaleSupported_ = NO; | ||
129 | |||
130 | // running thread is main thread on iOS | ||
131 | runningThread_ = [NSThread currentThread]; | ||
132 | } | ||
133 | |||
134 | return self; | ||
135 | } | ||
136 | |||
137 | - (void) dealloc | ||
138 | { | ||
139 | [super dealloc]; | ||
140 | } | ||
141 | |||
142 | // | ||
143 | // Draw the Scene | ||
144 | // | ||
145 | - (void) drawScene | ||
146 | { | ||
147 | /* calculate "global" dt */ | ||
148 | [self calculateDeltaTime]; | ||
149 | |||
150 | /* tick before glClear: issue #533 */ | ||
151 | if( ! isPaused_ ) { | ||
152 | [[CCScheduler sharedScheduler] tick: dt]; | ||
153 | } | ||
154 | |||
155 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||
156 | |||
157 | /* to avoid flickr, nextScene MUST be here: after tick and before draw. | ||
158 | XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */ | ||
159 | if( nextScene_ ) | ||
160 | [self setNextScene]; | ||
161 | |||
162 | glPushMatrix(); | ||
163 | |||
164 | [self applyOrientation]; | ||
165 | |||
166 | // By default enable VertexArray, ColorArray, TextureCoordArray and Texture2D | ||
167 | CC_ENABLE_DEFAULT_GL_STATES(); | ||
168 | |||
169 | /* draw the scene */ | ||
170 | [runningScene_ visit]; | ||
171 | |||
172 | /* draw the notification node */ | ||
173 | [notificationNode_ visit]; | ||
174 | |||
175 | if( displayFPS_ ) | ||
176 | [self showFPS]; | ||
177 | |||
178 | #if CC_ENABLE_PROFILERS | ||
179 | [self showProfilers]; | ||
180 | #endif | ||
181 | |||
182 | CC_DISABLE_DEFAULT_GL_STATES(); | ||
183 | |||
184 | glPopMatrix(); | ||
185 | |||
186 | [openGLView_ swapBuffers]; | ||
187 | } | ||
188 | |||
189 | -(void) setProjection:(ccDirectorProjection)projection | ||
190 | { | ||
191 | CGSize size = winSizeInPixels_; | ||
192 | |||
193 | switch (projection) { | ||
194 | case kCCDirectorProjection2D: | ||
195 | glViewport(0, 0, size.width, size.height); | ||
196 | glMatrixMode(GL_PROJECTION); | ||
197 | glLoadIdentity(); | ||
198 | ccglOrtho(0, size.width, 0, size.height, -1024 * CC_CONTENT_SCALE_FACTOR(), 1024 * CC_CONTENT_SCALE_FACTOR()); | ||
199 | glMatrixMode(GL_MODELVIEW); | ||
200 | glLoadIdentity(); | ||
201 | break; | ||
202 | |||
203 | case kCCDirectorProjection3D: | ||
204 | { | ||
205 | float zeye = [self getZEye]; | ||
206 | |||
207 | glViewport(0, 0, size.width, size.height); | ||
208 | glMatrixMode(GL_PROJECTION); | ||
209 | glLoadIdentity(); | ||
210 | // gluPerspective(60, (GLfloat)size.width/size.height, zeye-size.height/2, zeye+size.height/2 ); | ||
211 | gluPerspective(60, (GLfloat)size.width/size.height, 0.5f, 1500); | ||
212 | |||
213 | glMatrixMode(GL_MODELVIEW); | ||
214 | glLoadIdentity(); | ||
215 | gluLookAt( size.width/2, size.height/2, zeye, | ||
216 | size.width/2, size.height/2, 0, | ||
217 | 0.0f, 1.0f, 0.0f); | ||
218 | break; | ||
219 | } | ||
220 | |||
221 | case kCCDirectorProjectionCustom: | ||
222 | if( projectionDelegate_ ) | ||
223 | [projectionDelegate_ updateProjection]; | ||
224 | break; | ||
225 | |||
226 | default: | ||
227 | CCLOG(@"cocos2d: Director: unrecognized projecgtion"); | ||
228 | break; | ||
229 | } | ||
230 | |||
231 | projection_ = projection; | ||
232 | } | ||
233 | |||
234 | #pragma mark Director Integration with a UIKit view | ||
235 | |||
236 | -(void) setOpenGLView:(EAGLView *)view | ||
237 | { | ||
238 | if( view != openGLView_ ) { | ||
239 | |||
240 | [super setOpenGLView:view]; | ||
241 | |||
242 | // set size | ||
243 | winSizeInPixels_ = CGSizeMake(winSizeInPoints_.width * __ccContentScaleFactor, winSizeInPoints_.height *__ccContentScaleFactor); | ||
244 | |||
245 | if( __ccContentScaleFactor != 1 ) | ||
246 | [self updateContentScaleFactor]; | ||
247 | |||
248 | CCTouchDispatcher *touchDispatcher = [CCTouchDispatcher sharedDispatcher]; | ||
249 | [openGLView_ setTouchDelegate: touchDispatcher]; | ||
250 | [touchDispatcher setDispatchEvents: YES]; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | #pragma mark Director - Retina Display | ||
255 | |||
256 | -(CGFloat) contentScaleFactor | ||
257 | { | ||
258 | return __ccContentScaleFactor; | ||
259 | } | ||
260 | |||
261 | -(void) setContentScaleFactor:(CGFloat)scaleFactor | ||
262 | { | ||
263 | if( scaleFactor != __ccContentScaleFactor ) { | ||
264 | |||
265 | __ccContentScaleFactor = scaleFactor; | ||
266 | winSizeInPixels_ = CGSizeMake( winSizeInPoints_.width * scaleFactor, winSizeInPoints_.height * scaleFactor ); | ||
267 | |||
268 | if( openGLView_ ) | ||
269 | [self updateContentScaleFactor]; | ||
270 | |||
271 | // update projection | ||
272 | [self setProjection:projection_]; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | -(void) updateContentScaleFactor | ||
277 | { | ||
278 | // Based on code snippet from: http://developer.apple.com/iphone/prerelease/library/snippets/sp2010/sp28.html | ||
279 | if ([openGLView_ respondsToSelector:@selector(setContentScaleFactor:)]) | ||
280 | { | ||
281 | [openGLView_ setContentScaleFactor: __ccContentScaleFactor]; | ||
282 | |||
283 | isContentScaleSupported_ = YES; | ||
284 | } | ||
285 | else | ||
286 | CCLOG(@"cocos2d: 'setContentScaleFactor:' is not supported on this device"); | ||
287 | } | ||
288 | |||
289 | -(BOOL) enableRetinaDisplay:(BOOL)enabled | ||
290 | { | ||
291 | // Already enabled ? | ||
292 | if( enabled && __ccContentScaleFactor == 2 ) | ||
293 | return YES; | ||
294 | |||
295 | // Already disabled | ||
296 | if( ! enabled && __ccContentScaleFactor == 1 ) | ||
297 | return YES; | ||
298 | |||
299 | // setContentScaleFactor is not supported | ||
300 | if (! [openGLView_ respondsToSelector:@selector(setContentScaleFactor:)]) | ||
301 | return NO; | ||
302 | |||
303 | // SD device | ||
304 | if ([[UIScreen mainScreen] scale] == 1.0) | ||
305 | return NO; | ||
306 | |||
307 | float newScale = enabled ? 2 : 1; | ||
308 | [self setContentScaleFactor:newScale]; | ||
309 | |||
310 | return YES; | ||
311 | } | ||
312 | |||
313 | // overriden, don't call super | ||
314 | -(void) reshapeProjection:(CGSize)size | ||
315 | { | ||
316 | winSizeInPoints_ = [openGLView_ bounds].size; | ||
317 | winSizeInPixels_ = CGSizeMake(winSizeInPoints_.width * __ccContentScaleFactor, winSizeInPoints_.height *__ccContentScaleFactor); | ||
318 | |||
319 | [self setProjection:projection_]; | ||
320 | } | ||
321 | |||
322 | #pragma mark Director Scene Landscape | ||
323 | |||
324 | -(CGPoint)convertToGL:(CGPoint)uiPoint | ||
325 | { | ||
326 | CGSize s = winSizeInPoints_; | ||
327 | float newY = s.height - uiPoint.y; | ||
328 | float newX = s.width - uiPoint.x; | ||
329 | |||
330 | CGPoint ret = CGPointZero; | ||
331 | switch ( deviceOrientation_) { | ||
332 | case CCDeviceOrientationPortrait: | ||
333 | ret = ccp( uiPoint.x, newY ); | ||
334 | break; | ||
335 | case CCDeviceOrientationPortraitUpsideDown: | ||
336 | ret = ccp(newX, uiPoint.y); | ||
337 | break; | ||
338 | case CCDeviceOrientationLandscapeLeft: | ||
339 | ret.x = uiPoint.y; | ||
340 | ret.y = uiPoint.x; | ||
341 | break; | ||
342 | case CCDeviceOrientationLandscapeRight: | ||
343 | ret.x = newY; | ||
344 | ret.y = newX; | ||
345 | break; | ||
346 | } | ||
347 | return ret; | ||
348 | } | ||
349 | |||
350 | -(CGPoint)convertToUI:(CGPoint)glPoint | ||
351 | { | ||
352 | CGSize winSize = winSizeInPoints_; | ||
353 | int oppositeX = winSize.width - glPoint.x; | ||
354 | int oppositeY = winSize.height - glPoint.y; | ||
355 | CGPoint uiPoint = CGPointZero; | ||
356 | switch ( deviceOrientation_) { | ||
357 | case CCDeviceOrientationPortrait: | ||
358 | uiPoint = ccp(glPoint.x, oppositeY); | ||
359 | break; | ||
360 | case CCDeviceOrientationPortraitUpsideDown: | ||
361 | uiPoint = ccp(oppositeX, glPoint.y); | ||
362 | break; | ||
363 | case CCDeviceOrientationLandscapeLeft: | ||
364 | uiPoint = ccp(glPoint.y, glPoint.x); | ||
365 | break; | ||
366 | case CCDeviceOrientationLandscapeRight: | ||
367 | // Can't use oppositeX/Y because x/y are flipped | ||
368 | uiPoint = ccp(winSize.width-glPoint.y, winSize.height-glPoint.x); | ||
369 | break; | ||
370 | } | ||
371 | return uiPoint; | ||
372 | } | ||
373 | |||
374 | // get the current size of the glview | ||
375 | -(CGSize) winSize | ||
376 | { | ||
377 | CGSize s = winSizeInPoints_; | ||
378 | |||
379 | if( deviceOrientation_ == CCDeviceOrientationLandscapeLeft || deviceOrientation_ == CCDeviceOrientationLandscapeRight ) { | ||
380 | // swap x,y in landscape mode | ||
381 | CGSize tmp = s; | ||
382 | s.width = tmp.height; | ||
383 | s.height = tmp.width; | ||
384 | } | ||
385 | return s; | ||
386 | } | ||
387 | |||
388 | -(CGSize) winSizeInPixels | ||
389 | { | ||
390 | CGSize s = [self winSize]; | ||
391 | |||
392 | s.width *= CC_CONTENT_SCALE_FACTOR(); | ||
393 | s.height *= CC_CONTENT_SCALE_FACTOR(); | ||
394 | |||
395 | return s; | ||
396 | } | ||
397 | |||
398 | -(ccDeviceOrientation) deviceOrientation | ||
399 | { | ||
400 | return deviceOrientation_; | ||
401 | } | ||
402 | |||
403 | - (void) setDeviceOrientation:(ccDeviceOrientation) orientation | ||
404 | { | ||
405 | if( deviceOrientation_ != orientation ) { | ||
406 | deviceOrientation_ = orientation; | ||
407 | switch( deviceOrientation_) { | ||
408 | case CCDeviceOrientationPortrait: | ||
409 | [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationPortrait animated:NO]; | ||
410 | break; | ||
411 | case CCDeviceOrientationPortraitUpsideDown: | ||
412 | [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationPortraitUpsideDown animated:NO]; | ||
413 | break; | ||
414 | case CCDeviceOrientationLandscapeLeft: | ||
415 | [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeRight animated:NO]; | ||
416 | break; | ||
417 | case CCDeviceOrientationLandscapeRight: | ||
418 | [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeLeft animated:NO]; | ||
419 | break; | ||
420 | default: | ||
421 | NSLog(@"Director: Unknown device orientation"); | ||
422 | break; | ||
423 | } | ||
424 | } | ||
425 | } | ||
426 | |||
427 | -(void) applyOrientation | ||
428 | { | ||
429 | CGSize s = winSizeInPixels_; | ||
430 | float w = s.width / 2; | ||
431 | float h = s.height / 2; | ||
432 | |||
433 | // XXX it's using hardcoded values. | ||
434 | // What if the the screen size changes in the future? | ||
435 | switch ( deviceOrientation_ ) { | ||
436 | case CCDeviceOrientationPortrait: | ||
437 | // nothing | ||
438 | break; | ||
439 | case CCDeviceOrientationPortraitUpsideDown: | ||
440 | // upside down | ||
441 | glTranslatef(w,h,0); | ||
442 | glRotatef(180,0,0,1); | ||
443 | glTranslatef(-w,-h,0); | ||
444 | break; | ||
445 | case CCDeviceOrientationLandscapeRight: | ||
446 | glTranslatef(w,h,0); | ||
447 | glRotatef(90,0,0,1); | ||
448 | glTranslatef(-h,-w,0); | ||
449 | break; | ||
450 | case CCDeviceOrientationLandscapeLeft: | ||
451 | glTranslatef(w,h,0); | ||
452 | glRotatef(-90,0,0,1); | ||
453 | glTranslatef(-h,-w,0); | ||
454 | break; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | -(void) end | ||
459 | { | ||
460 | // don't release the event handlers | ||
461 | // They are needed in case the director is run again | ||
462 | [[CCTouchDispatcher sharedDispatcher] removeAllDelegates]; | ||
463 | |||
464 | [super end]; | ||
465 | } | ||
466 | |||
467 | @end | ||
468 | |||
469 | |||
470 | #pragma mark - | ||
471 | #pragma mark Director TimerDirector | ||
472 | |||
473 | @implementation CCDirectorTimer | ||
474 | - (void)startAnimation | ||
475 | { | ||
476 | NSAssert( animationTimer == nil, @"animationTimer must be nil. Calling startAnimation twice?"); | ||
477 | |||
478 | if( gettimeofday( &lastUpdate_, NULL) != 0 ) { | ||
479 | CCLOG(@"cocos2d: Director: Error in gettimeofday"); | ||
480 | } | ||
481 | |||
482 | animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval_ target:self selector:@selector(mainLoop) userInfo:nil repeats:YES]; | ||
483 | |||
484 | // | ||
485 | // If you want to attach the opengl view into UIScrollView | ||
486 | // uncomment this line to prevent 'freezing'. | ||
487 | // It doesn't work on with the Fast Director | ||
488 | // | ||
489 | // [[NSRunLoop currentRunLoop] addTimer:animationTimer | ||
490 | // forMode:NSRunLoopCommonModes]; | ||
491 | } | ||
492 | |||
493 | -(void) mainLoop | ||
494 | { | ||
495 | [self drawScene]; | ||
496 | } | ||
497 | |||
498 | - (void)stopAnimation | ||
499 | { | ||
500 | [animationTimer invalidate]; | ||
501 | animationTimer = nil; | ||
502 | } | ||
503 | |||
504 | - (void)setAnimationInterval:(NSTimeInterval)interval | ||
505 | { | ||
506 | animationInterval_ = interval; | ||
507 | |||
508 | if(animationTimer) { | ||
509 | [self stopAnimation]; | ||
510 | [self startAnimation]; | ||
511 | } | ||
512 | } | ||
513 | |||
514 | -(void) dealloc | ||
515 | { | ||
516 | [animationTimer release]; | ||
517 | [super dealloc]; | ||
518 | } | ||
519 | @end | ||
520 | |||
521 | |||
522 | #pragma mark - | ||
523 | #pragma mark Director DirectorFast | ||
524 | |||
525 | @implementation CCDirectorFast | ||
526 | |||
527 | - (id) init | ||
528 | { | ||
529 | if(( self = [super init] )) { | ||
530 | |||
531 | #if CC_DIRECTOR_DISPATCH_FAST_EVENTS | ||
532 | CCLOG(@"cocos2d: Fast Events enabled"); | ||
533 | #else | ||
534 | CCLOG(@"cocos2d: Fast Events disabled"); | ||
535 | #endif | ||
536 | isRunning = NO; | ||
537 | |||
538 | // XXX: | ||
539 | // XXX: Don't create any autorelease object before calling "fast director" | ||
540 | // XXX: else it will be leaked | ||
541 | // XXX: | ||
542 | autoreleasePool = [NSAutoreleasePool new]; | ||
543 | } | ||
544 | |||
545 | return self; | ||
546 | } | ||
547 | |||
548 | - (void) startAnimation | ||
549 | { | ||
550 | NSAssert( isRunning == NO, @"isRunning must be NO. Calling startAnimation twice?"); | ||
551 | |||
552 | // XXX: | ||
553 | // XXX: release autorelease objects created | ||
554 | // XXX: between "use fast director" and "runWithScene" | ||
555 | // XXX: | ||
556 | [autoreleasePool release]; | ||
557 | autoreleasePool = nil; | ||
558 | |||
559 | if ( gettimeofday( &lastUpdate_, NULL) != 0 ) { | ||
560 | CCLOG(@"cocos2d: Director: Error in gettimeofday"); | ||
561 | } | ||
562 | |||
563 | |||
564 | isRunning = YES; | ||
565 | |||
566 | SEL selector = @selector(mainLoop); | ||
567 | NSMethodSignature* sig = [[[CCDirector sharedDirector] class] | ||
568 | instanceMethodSignatureForSelector:selector]; | ||
569 | NSInvocation* invocation = [NSInvocation | ||
570 | invocationWithMethodSignature:sig]; | ||
571 | [invocation setTarget:[CCDirector sharedDirector]]; | ||
572 | [invocation setSelector:selector]; | ||
573 | [invocation performSelectorOnMainThread:@selector(invokeWithTarget:) | ||
574 | withObject:[CCDirector sharedDirector] waitUntilDone:NO]; | ||
575 | |||
576 | // NSInvocationOperation *loopOperation = [[[NSInvocationOperation alloc] | ||
577 | // initWithTarget:self selector:@selector(mainLoop) object:nil] | ||
578 | // autorelease]; | ||
579 | // | ||
580 | // [loopOperation performSelectorOnMainThread:@selector(start) withObject:nil | ||
581 | // waitUntilDone:NO]; | ||
582 | } | ||
583 | |||
584 | -(void) mainLoop | ||
585 | { | ||
586 | while (isRunning) { | ||
587 | |||
588 | NSAutoreleasePool *loopPool = [NSAutoreleasePool new]; | ||
589 | |||
590 | #if CC_DIRECTOR_DISPATCH_FAST_EVENTS | ||
591 | while( CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.004f, FALSE) == kCFRunLoopRunHandledSource); | ||
592 | #else | ||
593 | while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource); | ||
594 | #endif | ||
595 | |||
596 | if (isPaused_) { | ||
597 | usleep(250000); // Sleep for a quarter of a second (250,000 microseconds) so that the framerate is 4 fps. | ||
598 | } | ||
599 | |||
600 | [self drawScene]; | ||
601 | |||
602 | #if CC_DIRECTOR_DISPATCH_FAST_EVENTS | ||
603 | while( CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.004f, FALSE) == kCFRunLoopRunHandledSource); | ||
604 | #else | ||
605 | while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource); | ||
606 | #endif | ||
607 | |||
608 | [loopPool release]; | ||
609 | } | ||
610 | } | ||
611 | - (void) stopAnimation | ||
612 | { | ||
613 | isRunning = NO; | ||
614 | } | ||
615 | |||
616 | - (void)setAnimationInterval:(NSTimeInterval)interval | ||
617 | { | ||
618 | NSLog(@"FastDirectory doesn't support setAnimationInterval, yet"); | ||
619 | } | ||
620 | @end | ||
621 | |||
622 | #pragma mark - | ||
623 | #pragma mark Director DirectorThreadedFast | ||
624 | |||
625 | @implementation CCDirectorFastThreaded | ||
626 | |||
627 | - (id) init | ||
628 | { | ||
629 | if(( self = [super init] )) { | ||
630 | isRunning = NO; | ||
631 | } | ||
632 | |||
633 | return self; | ||
634 | } | ||
635 | |||
636 | - (void) startAnimation | ||
637 | { | ||
638 | NSAssert( isRunning == NO, @"isRunning must be NO. Calling startAnimation twice?"); | ||
639 | |||
640 | if ( gettimeofday( &lastUpdate_, NULL) != 0 ) { | ||
641 | CCLOG(@"cocos2d: ThreadedFastDirector: Error on gettimeofday"); | ||
642 | } | ||
643 | |||
644 | isRunning = YES; | ||
645 | |||
646 | NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(mainLoop) object:nil]; | ||
647 | [thread start]; | ||
648 | [thread release]; | ||
649 | } | ||
650 | |||
651 | -(void) mainLoop | ||
652 | { | ||
653 | while( ![[NSThread currentThread] isCancelled] ) { | ||
654 | if( isRunning ) | ||
655 | [self performSelectorOnMainThread:@selector(drawScene) withObject:nil waitUntilDone:YES]; | ||
656 | |||
657 | if (isPaused_) { | ||
658 | usleep(250000); // Sleep for a quarter of a second (250,000 microseconds) so that the framerate is 4 fps. | ||
659 | } else { | ||
660 | // usleep(2000); | ||
661 | } | ||
662 | } | ||
663 | } | ||
664 | - (void) stopAnimation | ||
665 | { | ||
666 | isRunning = NO; | ||
667 | } | ||
668 | |||
669 | - (void)setAnimationInterval:(NSTimeInterval)interval | ||
670 | { | ||
671 | NSLog(@"FastDirector doesn't support setAnimationInterval, yet"); | ||
672 | } | ||
673 | @end | ||
674 | |||
675 | #pragma mark - | ||
676 | #pragma mark DirectorDisplayLink | ||
677 | |||
678 | // Allows building DisplayLinkDirector for pre-3.1 SDKS | ||
679 | // without getting compiler warnings. | ||
680 | @interface NSObject(CADisplayLink) | ||
681 | + (id) displayLinkWithTarget:(id)arg1 selector:(SEL)arg2; | ||
682 | - (void) addToRunLoop:(id)arg1 forMode:(id)arg2; | ||
683 | - (void) setFrameInterval:(int)interval; | ||
684 | - (void) invalidate; | ||
685 | @end | ||
686 | |||
687 | @implementation CCDirectorDisplayLink | ||
688 | |||
689 | - (void)setAnimationInterval:(NSTimeInterval)interval | ||
690 | { | ||
691 | animationInterval_ = interval; | ||
692 | if(displayLink){ | ||
693 | [self stopAnimation]; | ||
694 | [self startAnimation]; | ||
695 | } | ||
696 | } | ||
697 | |||
698 | - (void) startAnimation | ||
699 | { | ||
700 | NSAssert( displayLink == nil, @"displayLink must be nil. Calling startAnimation twice?"); | ||
701 | |||
702 | if ( gettimeofday( &lastUpdate_, NULL) != 0 ) { | ||
703 | CCLOG(@"cocos2d: DisplayLinkDirector: Error on gettimeofday"); | ||
704 | } | ||
705 | |||
706 | // approximate frame rate | ||
707 | // assumes device refreshes at 60 fps | ||
708 | int frameInterval = (int) floor(animationInterval_ * 60.0f); | ||
709 | |||
710 | CCLOG(@"cocos2d: Frame interval: %d", frameInterval); | ||
711 | |||
712 | displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(mainLoop:)]; | ||
713 | [displayLink setFrameInterval:frameInterval]; | ||
714 | [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; | ||
715 | } | ||
716 | |||
717 | -(void) mainLoop:(id)sender | ||
718 | { | ||
719 | [self drawScene]; | ||
720 | } | ||
721 | |||
722 | - (void) stopAnimation | ||
723 | { | ||
724 | [displayLink invalidate]; | ||
725 | displayLink = nil; | ||
726 | } | ||
727 | |||
728 | -(void) dealloc | ||
729 | { | ||
730 | [displayLink release]; | ||
731 | [super dealloc]; | ||
732 | } | ||
733 | @end | ||
734 | |||
735 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/CCTouchDelegateProtocol.h b/libs/cocos2d/Platforms/iOS/CCTouchDelegateProtocol.h new file mode 100755 index 0000000..20ba036 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/CCTouchDelegateProtocol.h | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
27 | // But in case they are included, it won't be compiled. | ||
28 | #import <Availability.h> | ||
29 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
30 | |||
31 | #import <UIKit/UIKit.h> | ||
32 | |||
33 | /** | ||
34 | CCTargetedTouchDelegate. | ||
35 | |||
36 | Using this type of delegate results in two benefits: | ||
37 | 1. You don't need to deal with NSSets, the dispatcher does the job of splitting | ||
38 | them. You get exactly one UITouch per call. | ||
39 | 2. You can *claim* a UITouch by returning YES in ccTouchBegan. Updates of claimed | ||
40 | touches are sent only to the delegate(s) that claimed them. So if you get a move/ | ||
41 | ended/cancelled update you're sure it's your touch. This frees you from doing a | ||
42 | lot of checks when doing multi-touch. | ||
43 | |||
44 | (The name TargetedTouchDelegate relates to updates "targeting" their specific | ||
45 | handler, without bothering the other handlers.) | ||
46 | @since v0.8 | ||
47 | */ | ||
48 | @protocol CCTargetedTouchDelegate <NSObject> | ||
49 | |||
50 | /** Return YES to claim the touch. | ||
51 | @since v0.8 | ||
52 | */ | ||
53 | - (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event; | ||
54 | @optional | ||
55 | // touch updates: | ||
56 | - (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event; | ||
57 | - (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event; | ||
58 | - (void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event; | ||
59 | @end | ||
60 | |||
61 | /** | ||
62 | CCStandardTouchDelegate. | ||
63 | |||
64 | This type of delegate is the same one used by CocoaTouch. You will receive all the events (Began,Moved,Ended,Cancelled). | ||
65 | @since v0.8 | ||
66 | */ | ||
67 | @protocol CCStandardTouchDelegate <NSObject> | ||
68 | @optional | ||
69 | - (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; | ||
70 | - (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; | ||
71 | - (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; | ||
72 | - (void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; | ||
73 | @end | ||
74 | |||
75 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.h b/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.h new file mode 100755 index 0000000..9931189 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
27 | // But in case they are included, it won't be compiled. | ||
28 | #import <Availability.h> | ||
29 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
30 | |||
31 | #import "CCTouchDelegateProtocol.h" | ||
32 | #import "EAGLView.h" | ||
33 | |||
34 | |||
35 | typedef enum | ||
36 | { | ||
37 | kCCTouchSelectorBeganBit = 1 << 0, | ||
38 | kCCTouchSelectorMovedBit = 1 << 1, | ||
39 | kCCTouchSelectorEndedBit = 1 << 2, | ||
40 | kCCTouchSelectorCancelledBit = 1 << 3, | ||
41 | kCCTouchSelectorAllBits = ( kCCTouchSelectorBeganBit | kCCTouchSelectorMovedBit | kCCTouchSelectorEndedBit | kCCTouchSelectorCancelledBit), | ||
42 | } ccTouchSelectorFlag; | ||
43 | |||
44 | |||
45 | enum { | ||
46 | kCCTouchBegan, | ||
47 | kCCTouchMoved, | ||
48 | kCCTouchEnded, | ||
49 | kCCTouchCancelled, | ||
50 | |||
51 | kCCTouchMax, | ||
52 | }; | ||
53 | |||
54 | struct ccTouchHandlerHelperData { | ||
55 | SEL touchesSel; | ||
56 | SEL touchSel; | ||
57 | ccTouchSelectorFlag type; | ||
58 | }; | ||
59 | |||
60 | /** CCTouchDispatcher. | ||
61 | Singleton that handles all the touch events. | ||
62 | The dispatcher dispatches events to the registered TouchHandlers. | ||
63 | There are 2 different type of touch handlers: | ||
64 | - Standard Touch Handlers | ||
65 | - Targeted Touch Handlers | ||
66 | |||
67 | The Standard Touch Handlers work like the CocoaTouch touch handler: a set of touches is passed to the delegate. | ||
68 | On the other hand, the Targeted Touch Handlers only receive 1 touch at the time, and they can "swallow" touches (avoid the propagation of the event). | ||
69 | |||
70 | Firstly, the dispatcher sends the received touches to the targeted touches. | ||
71 | These touches can be swallowed by the Targeted Touch Handlers. If there are still remaining touches, then the remaining touches will be sent | ||
72 | to the Standard Touch Handlers. | ||
73 | |||
74 | @since v0.8.0 | ||
75 | */ | ||
76 | @interface CCTouchDispatcher : NSObject <EAGLTouchDelegate> | ||
77 | { | ||
78 | NSMutableArray *targetedHandlers; | ||
79 | NSMutableArray *standardHandlers; | ||
80 | |||
81 | BOOL locked; | ||
82 | BOOL toAdd; | ||
83 | BOOL toRemove; | ||
84 | NSMutableArray *handlersToAdd; | ||
85 | NSMutableArray *handlersToRemove; | ||
86 | BOOL toQuit; | ||
87 | |||
88 | BOOL dispatchEvents; | ||
89 | |||
90 | // 4, 1 for each type of event | ||
91 | struct ccTouchHandlerHelperData handlerHelperData[kCCTouchMax]; | ||
92 | } | ||
93 | |||
94 | /** singleton of the CCTouchDispatcher */ | ||
95 | + (CCTouchDispatcher*)sharedDispatcher; | ||
96 | |||
97 | /** Whether or not the events are going to be dispatched. Default: YES */ | ||
98 | @property (nonatomic,readwrite, assign) BOOL dispatchEvents; | ||
99 | |||
100 | /** Adds a standard touch delegate to the dispatcher's list. | ||
101 | See StandardTouchDelegate description. | ||
102 | IMPORTANT: The delegate will be retained. | ||
103 | */ | ||
104 | -(void) addStandardDelegate:(id<CCStandardTouchDelegate>) delegate priority:(int)priority; | ||
105 | /** Adds a targeted touch delegate to the dispatcher's list. | ||
106 | See TargetedTouchDelegate description. | ||
107 | IMPORTANT: The delegate will be retained. | ||
108 | */ | ||
109 | -(void) addTargetedDelegate:(id<CCTargetedTouchDelegate>) delegate priority:(int)priority swallowsTouches:(BOOL)swallowsTouches; | ||
110 | /** Removes a touch delegate. | ||
111 | The delegate will be released | ||
112 | */ | ||
113 | -(void) removeDelegate:(id) delegate; | ||
114 | /** Removes all touch delegates, releasing all the delegates */ | ||
115 | -(void) removeAllDelegates; | ||
116 | /** Changes the priority of a previously added delegate. The lower the number, | ||
117 | the higher the priority */ | ||
118 | -(void) setPriority:(int) priority forDelegate:(id) delegate; | ||
119 | |||
120 | NSComparisonResult sortByPriority(id first, id second, void *context); | ||
121 | @end | ||
122 | |||
123 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m b/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m new file mode 100755 index 0000000..1553b48 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m | |||
@@ -0,0 +1,347 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
27 | // But in case they are included, it won't be compiled. | ||
28 | #import <Availability.h> | ||
29 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
30 | |||
31 | |||
32 | #import "CCTouchDispatcher.h" | ||
33 | #import "CCTouchHandler.h" | ||
34 | |||
35 | @implementation CCTouchDispatcher | ||
36 | |||
37 | @synthesize dispatchEvents; | ||
38 | |||
39 | static CCTouchDispatcher *sharedDispatcher = nil; | ||
40 | |||
41 | +(CCTouchDispatcher*) sharedDispatcher | ||
42 | { | ||
43 | @synchronized(self) { | ||
44 | if (sharedDispatcher == nil) | ||
45 | sharedDispatcher = [[self alloc] init]; // assignment not done here | ||
46 | } | ||
47 | return sharedDispatcher; | ||
48 | } | ||
49 | |||
50 | +(id) allocWithZone:(NSZone *)zone | ||
51 | { | ||
52 | @synchronized(self) { | ||
53 | NSAssert(sharedDispatcher == nil, @"Attempted to allocate a second instance of a singleton."); | ||
54 | return [super allocWithZone:zone]; | ||
55 | } | ||
56 | return nil; // on subsequent allocation attempts return nil | ||
57 | } | ||
58 | |||
59 | -(id) init | ||
60 | { | ||
61 | if((self = [super init])) { | ||
62 | |||
63 | dispatchEvents = YES; | ||
64 | targetedHandlers = [[NSMutableArray alloc] initWithCapacity:8]; | ||
65 | standardHandlers = [[NSMutableArray alloc] initWithCapacity:4]; | ||
66 | |||
67 | handlersToAdd = [[NSMutableArray alloc] initWithCapacity:8]; | ||
68 | handlersToRemove = [[NSMutableArray alloc] initWithCapacity:8]; | ||
69 | |||
70 | toRemove = NO; | ||
71 | toAdd = NO; | ||
72 | toQuit = NO; | ||
73 | locked = NO; | ||
74 | |||
75 | handlerHelperData[kCCTouchBegan] = (struct ccTouchHandlerHelperData) {@selector(ccTouchesBegan:withEvent:),@selector(ccTouchBegan:withEvent:),kCCTouchSelectorBeganBit}; | ||
76 | handlerHelperData[kCCTouchMoved] = (struct ccTouchHandlerHelperData) {@selector(ccTouchesMoved:withEvent:),@selector(ccTouchMoved:withEvent:),kCCTouchSelectorMovedBit}; | ||
77 | handlerHelperData[kCCTouchEnded] = (struct ccTouchHandlerHelperData) {@selector(ccTouchesEnded:withEvent:),@selector(ccTouchEnded:withEvent:),kCCTouchSelectorEndedBit}; | ||
78 | handlerHelperData[kCCTouchCancelled] = (struct ccTouchHandlerHelperData) {@selector(ccTouchesCancelled:withEvent:),@selector(ccTouchCancelled:withEvent:),kCCTouchSelectorCancelledBit}; | ||
79 | |||
80 | } | ||
81 | |||
82 | return self; | ||
83 | } | ||
84 | |||
85 | -(void) dealloc | ||
86 | { | ||
87 | [targetedHandlers release]; | ||
88 | [standardHandlers release]; | ||
89 | [handlersToAdd release]; | ||
90 | [handlersToRemove release]; | ||
91 | [super dealloc]; | ||
92 | } | ||
93 | |||
94 | // | ||
95 | // handlers management | ||
96 | // | ||
97 | |||
98 | #pragma mark TouchDispatcher - Add Hanlder | ||
99 | |||
100 | -(void) forceAddHandler:(CCTouchHandler*)handler array:(NSMutableArray*)array | ||
101 | { | ||
102 | NSUInteger i = 0; | ||
103 | |||
104 | for( CCTouchHandler *h in array ) { | ||
105 | if( h.priority < handler.priority ) | ||
106 | i++; | ||
107 | |||
108 | NSAssert( h.delegate != handler.delegate, @"Delegate already added to touch dispatcher."); | ||
109 | } | ||
110 | [array insertObject:handler atIndex:i]; | ||
111 | } | ||
112 | |||
113 | -(void) addStandardDelegate:(id<CCStandardTouchDelegate>) delegate priority:(int)priority | ||
114 | { | ||
115 | CCTouchHandler *handler = [CCStandardTouchHandler handlerWithDelegate:delegate priority:priority]; | ||
116 | if( ! locked ) { | ||
117 | [self forceAddHandler:handler array:standardHandlers]; | ||
118 | } else { | ||
119 | [handlersToAdd addObject:handler]; | ||
120 | toAdd = YES; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | -(void) addTargetedDelegate:(id<CCTargetedTouchDelegate>) delegate priority:(int)priority swallowsTouches:(BOOL)swallowsTouches | ||
125 | { | ||
126 | CCTouchHandler *handler = [CCTargetedTouchHandler handlerWithDelegate:delegate priority:priority swallowsTouches:swallowsTouches]; | ||
127 | if( ! locked ) { | ||
128 | [self forceAddHandler:handler array:targetedHandlers]; | ||
129 | } else { | ||
130 | [handlersToAdd addObject:handler]; | ||
131 | toAdd = YES; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | #pragma mark TouchDispatcher - removeDelegate | ||
136 | |||
137 | -(void) forceRemoveDelegate:(id)delegate | ||
138 | { | ||
139 | // XXX: remove it from both handlers ??? | ||
140 | |||
141 | for( CCTouchHandler *handler in targetedHandlers ) { | ||
142 | if( handler.delegate == delegate ) { | ||
143 | [targetedHandlers removeObject:handler]; | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | for( CCTouchHandler *handler in standardHandlers ) { | ||
149 | if( handler.delegate == delegate ) { | ||
150 | [standardHandlers removeObject:handler]; | ||
151 | break; | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | -(void) removeDelegate:(id) delegate | ||
157 | { | ||
158 | if( delegate == nil ) | ||
159 | return; | ||
160 | |||
161 | if( ! locked ) { | ||
162 | [self forceRemoveDelegate:delegate]; | ||
163 | } else { | ||
164 | [handlersToRemove addObject:delegate]; | ||
165 | toRemove = YES; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | #pragma mark TouchDispatcher - removeAllDelegates | ||
170 | |||
171 | -(void) forceRemoveAllDelegates | ||
172 | { | ||
173 | [standardHandlers removeAllObjects]; | ||
174 | [targetedHandlers removeAllObjects]; | ||
175 | } | ||
176 | -(void) removeAllDelegates | ||
177 | { | ||
178 | if( ! locked ) | ||
179 | [self forceRemoveAllDelegates]; | ||
180 | else | ||
181 | toQuit = YES; | ||
182 | } | ||
183 | |||
184 | #pragma mark Changing priority of added handlers | ||
185 | |||
186 | -(CCTouchHandler*) findHandler:(id)delegate | ||
187 | { | ||
188 | for( CCTouchHandler *handler in targetedHandlers ) { | ||
189 | if( handler.delegate == delegate ) { | ||
190 | return handler; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | for( CCTouchHandler *handler in standardHandlers ) { | ||
195 | if( handler.delegate == delegate ) { | ||
196 | return handler; | ||
197 | } | ||
198 | } | ||
199 | return nil; | ||
200 | } | ||
201 | |||
202 | NSComparisonResult sortByPriority(id first, id second, void *context) | ||
203 | { | ||
204 | if (((CCTouchHandler*)first).priority < ((CCTouchHandler*)second).priority) | ||
205 | return NSOrderedAscending; | ||
206 | else if (((CCTouchHandler*)first).priority > ((CCTouchHandler*)second).priority) | ||
207 | return NSOrderedDescending; | ||
208 | else | ||
209 | return NSOrderedSame; | ||
210 | } | ||
211 | |||
212 | -(void) rearrangeHandlers:(NSMutableArray*)array | ||
213 | { | ||
214 | [array sortUsingFunction:sortByPriority context:nil]; | ||
215 | } | ||
216 | |||
217 | -(void) setPriority:(int) priority forDelegate:(id) delegate | ||
218 | { | ||
219 | NSAssert(delegate != nil, @"Got nil touch delegate!"); | ||
220 | |||
221 | CCTouchHandler *handler = nil; | ||
222 | handler = [self findHandler:delegate]; | ||
223 | |||
224 | NSAssert(handler != nil, @"Delegate not found!"); | ||
225 | |||
226 | handler.priority = priority; | ||
227 | |||
228 | [self rearrangeHandlers:targetedHandlers]; | ||
229 | [self rearrangeHandlers:standardHandlers]; | ||
230 | } | ||
231 | |||
232 | // | ||
233 | // dispatch events | ||
234 | // | ||
235 | -(void) touches:(NSSet*)touches withEvent:(UIEvent*)event withTouchType:(unsigned int)idx | ||
236 | { | ||
237 | NSAssert(idx < 4, @"Invalid idx value"); | ||
238 | |||
239 | id mutableTouches; | ||
240 | locked = YES; | ||
241 | |||
242 | // optimization to prevent a mutable copy when it is not necessary | ||
243 | unsigned int targetedHandlersCount = [targetedHandlers count]; | ||
244 | unsigned int standardHandlersCount = [standardHandlers count]; | ||
245 | BOOL needsMutableSet = (targetedHandlersCount && standardHandlersCount); | ||
246 | |||
247 | mutableTouches = (needsMutableSet ? [touches mutableCopy] : touches); | ||
248 | |||
249 | struct ccTouchHandlerHelperData helper = handlerHelperData[idx]; | ||
250 | // | ||
251 | // process the target handlers 1st | ||
252 | // | ||
253 | if( targetedHandlersCount > 0 ) { | ||
254 | for( UITouch *touch in touches ) { | ||
255 | for(CCTargetedTouchHandler *handler in targetedHandlers) { | ||
256 | |||
257 | BOOL claimed = NO; | ||
258 | if( idx == kCCTouchBegan ) { | ||
259 | claimed = [handler.delegate ccTouchBegan:touch withEvent:event]; | ||
260 | if( claimed ) | ||
261 | [handler.claimedTouches addObject:touch]; | ||
262 | } | ||
263 | |||
264 | // else (moved, ended, cancelled) | ||
265 | else if( [handler.claimedTouches containsObject:touch] ) { | ||
266 | claimed = YES; | ||
267 | if( handler.enabledSelectors & helper.type ) | ||
268 | [handler.delegate performSelector:helper.touchSel withObject:touch withObject:event]; | ||
269 | |||
270 | if( helper.type & (kCCTouchSelectorCancelledBit | kCCTouchSelectorEndedBit) ) | ||
271 | [handler.claimedTouches removeObject:touch]; | ||
272 | } | ||
273 | |||
274 | if( claimed && handler.swallowsTouches ) { | ||
275 | if( needsMutableSet ) | ||
276 | [mutableTouches removeObject:touch]; | ||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | |||
283 | // | ||
284 | // process standard handlers 2nd | ||
285 | // | ||
286 | if( standardHandlersCount > 0 && [mutableTouches count]>0 ) { | ||
287 | for( CCTouchHandler *handler in standardHandlers ) { | ||
288 | if( handler.enabledSelectors & helper.type ) | ||
289 | [handler.delegate performSelector:helper.touchesSel withObject:mutableTouches withObject:event]; | ||
290 | } | ||
291 | } | ||
292 | if( needsMutableSet ) | ||
293 | [mutableTouches release]; | ||
294 | |||
295 | // | ||
296 | // Optimization. To prevent a [handlers copy] which is expensive | ||
297 | // the add/removes/quit is done after the iterations | ||
298 | // | ||
299 | locked = NO; | ||
300 | if( toRemove ) { | ||
301 | toRemove = NO; | ||
302 | for( id delegate in handlersToRemove ) | ||
303 | [self forceRemoveDelegate:delegate]; | ||
304 | [handlersToRemove removeAllObjects]; | ||
305 | } | ||
306 | if( toAdd ) { | ||
307 | toAdd = NO; | ||
308 | for( CCTouchHandler *handler in handlersToAdd ) { | ||
309 | Class targetedClass = [CCTargetedTouchHandler class]; | ||
310 | if( [handler isKindOfClass:targetedClass] ) | ||
311 | [self forceAddHandler:handler array:targetedHandlers]; | ||
312 | else | ||
313 | [self forceAddHandler:handler array:standardHandlers]; | ||
314 | } | ||
315 | [handlersToAdd removeAllObjects]; | ||
316 | } | ||
317 | if( toQuit ) { | ||
318 | toQuit = NO; | ||
319 | [self forceRemoveAllDelegates]; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event | ||
324 | { | ||
325 | if( dispatchEvents ) | ||
326 | [self touches:touches withEvent:event withTouchType:kCCTouchBegan]; | ||
327 | } | ||
328 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event | ||
329 | { | ||
330 | if( dispatchEvents ) | ||
331 | [self touches:touches withEvent:event withTouchType:kCCTouchMoved]; | ||
332 | } | ||
333 | |||
334 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event | ||
335 | { | ||
336 | if( dispatchEvents ) | ||
337 | [self touches:touches withEvent:event withTouchType:kCCTouchEnded]; | ||
338 | } | ||
339 | |||
340 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event | ||
341 | { | ||
342 | if( dispatchEvents ) | ||
343 | [self touches:touches withEvent:event withTouchType:kCCTouchCancelled]; | ||
344 | } | ||
345 | @end | ||
346 | |||
347 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/CCTouchHandler.h b/libs/cocos2d/Platforms/iOS/CCTouchHandler.h new file mode 100755 index 0000000..31a3e36 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/CCTouchHandler.h | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
27 | // But in case they are included, it won't be compiled. | ||
28 | #import <Availability.h> | ||
29 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
30 | |||
31 | /* | ||
32 | * This file contains the delegates of the touches | ||
33 | * There are 2 possible delegates: | ||
34 | * - CCStandardTouchHandler: propagates all the events at once | ||
35 | * - CCTargetedTouchHandler: propagates 1 event at the time | ||
36 | */ | ||
37 | |||
38 | #import "CCTouchDelegateProtocol.h" | ||
39 | #import "CCTouchDispatcher.h" | ||
40 | |||
41 | /** | ||
42 | CCTouchHandler | ||
43 | Object than contains the delegate and priority of the event handler. | ||
44 | */ | ||
45 | @interface CCTouchHandler : NSObject { | ||
46 | id delegate; | ||
47 | int priority; | ||
48 | ccTouchSelectorFlag enabledSelectors_; | ||
49 | } | ||
50 | |||
51 | /** delegate */ | ||
52 | @property(nonatomic, readwrite, retain) id delegate; | ||
53 | /** priority */ | ||
54 | @property(nonatomic, readwrite) int priority; // default 0 | ||
55 | /** enabled selectors */ | ||
56 | @property(nonatomic,readwrite) ccTouchSelectorFlag enabledSelectors; | ||
57 | |||
58 | /** allocates a TouchHandler with a delegate and a priority */ | ||
59 | + (id)handlerWithDelegate:(id)aDelegate priority:(int)priority; | ||
60 | /** initializes a TouchHandler with a delegate and a priority */ | ||
61 | - (id)initWithDelegate:(id)aDelegate priority:(int)priority; | ||
62 | @end | ||
63 | |||
64 | /** CCStandardTouchHandler | ||
65 | It forwardes each event to the delegate. | ||
66 | */ | ||
67 | @interface CCStandardTouchHandler : CCTouchHandler | ||
68 | { | ||
69 | } | ||
70 | @end | ||
71 | |||
72 | /** | ||
73 | CCTargetedTouchHandler | ||
74 | Object than contains the claimed touches and if it swallos touches. | ||
75 | Used internally by TouchDispatcher | ||
76 | */ | ||
77 | @interface CCTargetedTouchHandler : CCTouchHandler { | ||
78 | BOOL swallowsTouches; | ||
79 | NSMutableSet *claimedTouches; | ||
80 | } | ||
81 | /** whether or not the touches are swallowed */ | ||
82 | @property(nonatomic, readwrite) BOOL swallowsTouches; // default NO | ||
83 | /** MutableSet that contains the claimed touches */ | ||
84 | @property(nonatomic, readonly) NSMutableSet *claimedTouches; | ||
85 | |||
86 | /** allocates a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */ | ||
87 | + (id)handlerWithDelegate:(id) aDelegate priority:(int)priority swallowsTouches:(BOOL)swallowsTouches; | ||
88 | /** initializes a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */ | ||
89 | - (id)initWithDelegate:(id) aDelegate priority:(int)priority swallowsTouches:(BOOL)swallowsTouches; | ||
90 | |||
91 | @end | ||
92 | |||
93 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/CCTouchHandler.m b/libs/cocos2d/Platforms/iOS/CCTouchHandler.m new file mode 100755 index 0000000..a52103b --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/CCTouchHandler.m | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
28 | // But in case they are included, it won't be compiled. | ||
29 | #import <Availability.h> | ||
30 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
31 | |||
32 | /* | ||
33 | * This file contains the delegates of the touches | ||
34 | * There are 2 possible delegates: | ||
35 | * - CCStandardTouchHandler: propagates all the events at once | ||
36 | * - CCTargetedTouchHandler: propagates 1 event at the time | ||
37 | */ | ||
38 | |||
39 | #import "CCTouchHandler.h" | ||
40 | #import "../../ccMacros.h" | ||
41 | |||
42 | #pragma mark - | ||
43 | #pragma mark TouchHandler | ||
44 | @implementation CCTouchHandler | ||
45 | |||
46 | @synthesize delegate, priority; | ||
47 | @synthesize enabledSelectors=enabledSelectors_; | ||
48 | |||
49 | + (id)handlerWithDelegate:(id) aDelegate priority:(int)aPriority | ||
50 | { | ||
51 | return [[[self alloc] initWithDelegate:aDelegate priority:aPriority] autorelease]; | ||
52 | } | ||
53 | |||
54 | - (id)initWithDelegate:(id) aDelegate priority:(int)aPriority | ||
55 | { | ||
56 | NSAssert(aDelegate != nil, @"Touch delegate may not be nil"); | ||
57 | |||
58 | if ((self = [super init])) { | ||
59 | self.delegate = aDelegate; | ||
60 | priority = aPriority; | ||
61 | enabledSelectors_ = 0; | ||
62 | } | ||
63 | |||
64 | return self; | ||
65 | } | ||
66 | |||
67 | - (void)dealloc { | ||
68 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
69 | [delegate release]; | ||
70 | [super dealloc]; | ||
71 | } | ||
72 | @end | ||
73 | |||
74 | #pragma mark - | ||
75 | #pragma mark StandardTouchHandler | ||
76 | @implementation CCStandardTouchHandler | ||
77 | -(id) initWithDelegate:(id)del priority:(int)pri | ||
78 | { | ||
79 | if( (self=[super initWithDelegate:del priority:pri]) ) { | ||
80 | if( [del respondsToSelector:@selector(ccTouchesBegan:withEvent:)] ) | ||
81 | enabledSelectors_ |= kCCTouchSelectorBeganBit; | ||
82 | if( [del respondsToSelector:@selector(ccTouchesMoved:withEvent:)] ) | ||
83 | enabledSelectors_ |= kCCTouchSelectorMovedBit; | ||
84 | if( [del respondsToSelector:@selector(ccTouchesEnded:withEvent:)] ) | ||
85 | enabledSelectors_ |= kCCTouchSelectorEndedBit; | ||
86 | if( [del respondsToSelector:@selector(ccTouchesCancelled:withEvent:)] ) | ||
87 | enabledSelectors_ |= kCCTouchSelectorCancelledBit; | ||
88 | } | ||
89 | return self; | ||
90 | } | ||
91 | @end | ||
92 | |||
93 | #pragma mark - | ||
94 | #pragma mark TargetedTouchHandler | ||
95 | |||
96 | @interface CCTargetedTouchHandler (private) | ||
97 | -(void) updateKnownTouches:(NSMutableSet *)touches withEvent:(UIEvent *)event selector:(SEL)selector unclaim:(BOOL)doUnclaim; | ||
98 | @end | ||
99 | |||
100 | @implementation CCTargetedTouchHandler | ||
101 | |||
102 | @synthesize swallowsTouches, claimedTouches; | ||
103 | |||
104 | + (id)handlerWithDelegate:(id)aDelegate priority:(int)priority swallowsTouches:(BOOL)swallow | ||
105 | { | ||
106 | return [[[self alloc] initWithDelegate:aDelegate priority:priority swallowsTouches:swallow] autorelease]; | ||
107 | } | ||
108 | |||
109 | - (id)initWithDelegate:(id)aDelegate priority:(int)aPriority swallowsTouches:(BOOL)swallow | ||
110 | { | ||
111 | if ((self = [super initWithDelegate:aDelegate priority:aPriority])) { | ||
112 | claimedTouches = [[NSMutableSet alloc] initWithCapacity:2]; | ||
113 | swallowsTouches = swallow; | ||
114 | |||
115 | if( [aDelegate respondsToSelector:@selector(ccTouchBegan:withEvent:)] ) | ||
116 | enabledSelectors_ |= kCCTouchSelectorBeganBit; | ||
117 | if( [aDelegate respondsToSelector:@selector(ccTouchMoved:withEvent:)] ) | ||
118 | enabledSelectors_ |= kCCTouchSelectorMovedBit; | ||
119 | if( [aDelegate respondsToSelector:@selector(ccTouchEnded:withEvent:)] ) | ||
120 | enabledSelectors_ |= kCCTouchSelectorEndedBit; | ||
121 | if( [aDelegate respondsToSelector:@selector(ccTouchCancelled:withEvent:)] ) | ||
122 | enabledSelectors_ |= kCCTouchSelectorCancelledBit; | ||
123 | } | ||
124 | |||
125 | return self; | ||
126 | } | ||
127 | |||
128 | - (void)dealloc { | ||
129 | [claimedTouches release]; | ||
130 | [super dealloc]; | ||
131 | } | ||
132 | @end | ||
133 | |||
134 | |||
135 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED \ No newline at end of file | ||
diff --git a/libs/cocos2d/Platforms/iOS/EAGLView.h b/libs/cocos2d/Platforms/iOS/EAGLView.h new file mode 100755 index 0000000..3b6c2f3 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/EAGLView.h | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | |||
3 | ===== IMPORTANT ===== | ||
4 | |||
5 | This is sample code demonstrating API, technology or techniques in development. | ||
6 | Although this sample code has been reviewed for technical accuracy, it is not | ||
7 | final. Apple is supplying this information to help you plan for the adoption of | ||
8 | the technologies and programming interfaces described herein. This information | ||
9 | is subject to change, and software implemented based on this sample code should | ||
10 | be tested with final operating system software and final documentation. Newer | ||
11 | versions of this sample code may be provided with future seeds of the API or | ||
12 | technology. For information about updates to this and other developer | ||
13 | documentation, view the New & Updated sidebars in subsequent documentation | ||
14 | seeds. | ||
15 | |||
16 | ===================== | ||
17 | |||
18 | File: EAGLView.h | ||
19 | Abstract: Convenience class that wraps the CAEAGLLayer from CoreAnimation into a | ||
20 | UIView subclass. | ||
21 | |||
22 | Version: 1.3 | ||
23 | |||
24 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. | ||
25 | ("Apple") in consideration of your agreement to the following terms, and your | ||
26 | use, installation, modification or redistribution of this Apple software | ||
27 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
28 | please do not use, install, modify or redistribute this Apple software. | ||
29 | |||
30 | In consideration of your agreement to abide by the following terms, and subject | ||
31 | to these terms, Apple grants you a personal, non-exclusive license, under | ||
32 | Apple's copyrights in this original Apple software (the "Apple Software"), to | ||
33 | use, reproduce, modify and redistribute the Apple Software, with or without | ||
34 | modifications, in source and/or binary forms; provided that if you redistribute | ||
35 | the Apple Software in its entirety and without modifications, you must retain | ||
36 | this notice and the following text and disclaimers in all such redistributions | ||
37 | of the Apple Software. | ||
38 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used | ||
39 | to endorse or promote products derived from the Apple Software without specific | ||
40 | prior written permission from Apple. Except as expressly stated in this notice, | ||
41 | no other rights or licenses, express or implied, are granted by Apple herein, | ||
42 | including but not limited to any patent rights that may be infringed by your | ||
43 | derivative works or by other works in which the Apple Software may be | ||
44 | incorporated. | ||
45 | |||
46 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
47 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
48 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
49 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
50 | COMBINATION WITH YOUR PRODUCTS. | ||
51 | |||
52 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
53 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
54 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
55 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR | ||
56 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF | ||
57 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF | ||
58 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
59 | |||
60 | Copyright (C) 2008 Apple Inc. All Rights Reserved. | ||
61 | |||
62 | */ | ||
63 | |||
64 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
65 | // But in case they are included, it won't be compiled. | ||
66 | #import <Availability.h> | ||
67 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
68 | |||
69 | #import <UIKit/UIKit.h> | ||
70 | #import <OpenGLES/EAGL.h> | ||
71 | #import <OpenGLES/EAGLDrawable.h> | ||
72 | #import <OpenGLES/ES1/gl.h> | ||
73 | #import <OpenGLES/ES1/glext.h> | ||
74 | |||
75 | #import "ESRenderer.h" | ||
76 | |||
77 | //CLASSES: | ||
78 | |||
79 | @class EAGLView; | ||
80 | @class EAGLSharegroup; | ||
81 | |||
82 | //PROTOCOLS: | ||
83 | |||
84 | @protocol EAGLTouchDelegate <NSObject> | ||
85 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; | ||
86 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; | ||
87 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; | ||
88 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; | ||
89 | @end | ||
90 | |||
91 | //CLASS INTERFACE: | ||
92 | |||
93 | /** EAGLView Class. | ||
94 | * This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass. | ||
95 | * The view content is basically an EAGL surface you render your OpenGL scene into. | ||
96 | * Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel. | ||
97 | */ | ||
98 | @interface EAGLView : UIView | ||
99 | { | ||
100 | id<ESRenderer> renderer_; | ||
101 | EAGLContext *context_; // weak ref | ||
102 | |||
103 | NSString *pixelformat_; | ||
104 | GLuint depthFormat_; | ||
105 | BOOL preserveBackbuffer_; | ||
106 | |||
107 | CGSize size_; | ||
108 | BOOL discardFramebufferSupported_; | ||
109 | id<EAGLTouchDelegate> touchDelegate_; | ||
110 | |||
111 | //fsaa addition | ||
112 | BOOL multisampling_; | ||
113 | unsigned int requestedSamples_; | ||
114 | } | ||
115 | |||
116 | /** creates an initializes an EAGLView with a frame and 0-bit depth buffer, and a RGB565 color buffer. */ | ||
117 | + (id) viewWithFrame:(CGRect)frame; | ||
118 | /** creates an initializes an EAGLView with a frame, a color buffer format, and 0-bit depth buffer. */ | ||
119 | + (id) viewWithFrame:(CGRect)frame pixelFormat:(NSString*)format; | ||
120 | /** creates an initializes an EAGLView with a frame, a color buffer format, and a depth buffer. */ | ||
121 | + (id) viewWithFrame:(CGRect)frame pixelFormat:(NSString*)format depthFormat:(GLuint)depth; | ||
122 | /** creates an initializes an EAGLView with a frame, a color buffer format, a depth buffer format, a sharegroup, and multisamping */ | ||
123 | + (id) viewWithFrame:(CGRect)frame pixelFormat:(NSString*)format depthFormat:(GLuint)depth preserveBackbuffer:(BOOL)retained sharegroup:(EAGLSharegroup*)sharegroup multiSampling:(BOOL)multisampling numberOfSamples:(unsigned int)samples; | ||
124 | |||
125 | /** Initializes an EAGLView with a frame and 0-bit depth buffer, and a RGB565 color buffer */ | ||
126 | - (id) initWithFrame:(CGRect)frame; //These also set the current context | ||
127 | /** Initializes an EAGLView with a frame, a color buffer format, and 0-bit depth buffer */ | ||
128 | - (id) initWithFrame:(CGRect)frame pixelFormat:(NSString*)format; | ||
129 | /** Initializes an EAGLView with a frame, a color buffer format, a depth buffer format, a sharegroup and multisampling support */ | ||
130 | - (id) initWithFrame:(CGRect)frame pixelFormat:(NSString*)format depthFormat:(GLuint)depth preserveBackbuffer:(BOOL)retained sharegroup:(EAGLSharegroup*)sharegroup multiSampling:(BOOL)sampling numberOfSamples:(unsigned int)nSamples; | ||
131 | |||
132 | /** pixel format: it could be RGBA8 (32-bit) or RGB565 (16-bit) */ | ||
133 | @property(nonatomic,readonly) NSString* pixelFormat; | ||
134 | /** depth format of the render buffer: 0, 16 or 24 bits*/ | ||
135 | @property(nonatomic,readonly) GLuint depthFormat; | ||
136 | |||
137 | /** returns surface size in pixels */ | ||
138 | @property(nonatomic,readonly) CGSize surfaceSize; | ||
139 | |||
140 | /** OpenGL context */ | ||
141 | @property(nonatomic,readonly) EAGLContext *context; | ||
142 | |||
143 | @property(nonatomic,readwrite) BOOL multiSampling; | ||
144 | |||
145 | /** touch delegate */ | ||
146 | @property(nonatomic,readwrite,assign) id<EAGLTouchDelegate> touchDelegate; | ||
147 | |||
148 | /** EAGLView uses double-buffer. This method swaps the buffers */ | ||
149 | -(void) swapBuffers; | ||
150 | |||
151 | - (CGPoint) convertPointFromViewToSurface:(CGPoint)point; | ||
152 | - (CGRect) convertRectFromViewToSurface:(CGRect)rect; | ||
153 | @end | ||
154 | |||
155 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/EAGLView.m b/libs/cocos2d/Platforms/iOS/EAGLView.m new file mode 100755 index 0000000..d5ead65 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/EAGLView.m | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | |||
3 | ===== IMPORTANT ===== | ||
4 | |||
5 | This is sample code demonstrating API, technology or techniques in development. | ||
6 | Although this sample code has been reviewed for technical accuracy, it is not | ||
7 | final. Apple is supplying this information to help you plan for the adoption of | ||
8 | the technologies and programming interfaces described herein. This information | ||
9 | is subject to change, and software implemented based on this sample code should | ||
10 | be tested with final operating system software and final documentation. Newer | ||
11 | versions of this sample code may be provided with future seeds of the API or | ||
12 | technology. For information about updates to this and other developer | ||
13 | documentation, view the New & Updated sidebars in subsequent documentation | ||
14 | seeds. | ||
15 | |||
16 | ===================== | ||
17 | |||
18 | File: EAGLView.m | ||
19 | Abstract: Convenience class that wraps the CAEAGLLayer from CoreAnimation into a | ||
20 | UIView subclass. | ||
21 | |||
22 | Version: 1.3 | ||
23 | |||
24 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. | ||
25 | ("Apple") in consideration of your agreement to the following terms, and your | ||
26 | use, installation, modification or redistribution of this Apple software | ||
27 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
28 | please do not use, install, modify or redistribute this Apple software. | ||
29 | |||
30 | In consideration of your agreement to abide by the following terms, and subject | ||
31 | to these terms, Apple grants you a personal, non-exclusive license, under | ||
32 | Apple's copyrights in this original Apple software (the "Apple Software"), to | ||
33 | use, reproduce, modify and redistribute the Apple Software, with or without | ||
34 | modifications, in source and/or binary forms; provided that if you redistribute | ||
35 | the Apple Software in its entirety and without modifications, you must retain | ||
36 | this notice and the following text and disclaimers in all such redistributions | ||
37 | of the Apple Software. | ||
38 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used | ||
39 | to endorse or promote products derived from the Apple Software without specific | ||
40 | prior written permission from Apple. Except as expressly stated in this notice, | ||
41 | no other rights or licenses, express or implied, are granted by Apple herein, | ||
42 | including but not limited to any patent rights that may be infringed by your | ||
43 | derivative works or by other works in which the Apple Software may be | ||
44 | incorporated. | ||
45 | |||
46 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
47 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
48 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
49 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
50 | COMBINATION WITH YOUR PRODUCTS. | ||
51 | |||
52 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
53 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
54 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
55 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR | ||
56 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF | ||
57 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF | ||
58 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
59 | |||
60 | Copyright (C) 2008 Apple Inc. All Rights Reserved. | ||
61 | |||
62 | */ | ||
63 | |||
64 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
65 | // But in case they are included, it won't be compiled. | ||
66 | #import <Availability.h> | ||
67 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
68 | |||
69 | #import <QuartzCore/QuartzCore.h> | ||
70 | |||
71 | #import "EAGLView.h" | ||
72 | #import "ES1Renderer.h" | ||
73 | #import "../../CCDirector.h" | ||
74 | #import "../../ccMacros.h" | ||
75 | #import "../../CCConfiguration.h" | ||
76 | #import "../../Support/OpenGL_Internal.h" | ||
77 | |||
78 | |||
79 | //CLASS IMPLEMENTATIONS: | ||
80 | |||
81 | @interface EAGLView (Private) | ||
82 | - (BOOL) setupSurfaceWithSharegroup:(EAGLSharegroup*)sharegroup; | ||
83 | - (unsigned int) convertPixelFormat:(NSString*) pixelFormat; | ||
84 | @end | ||
85 | |||
86 | @implementation EAGLView | ||
87 | |||
88 | @synthesize surfaceSize=size_; | ||
89 | @synthesize pixelFormat=pixelformat_, depthFormat=depthFormat_; | ||
90 | @synthesize touchDelegate=touchDelegate_; | ||
91 | @synthesize context=context_; | ||
92 | @synthesize multiSampling=multiSampling_; | ||
93 | |||
94 | + (Class) layerClass | ||
95 | { | ||
96 | return [CAEAGLLayer class]; | ||
97 | } | ||
98 | |||
99 | + (id) viewWithFrame:(CGRect)frame | ||
100 | { | ||
101 | return [[[self alloc] initWithFrame:frame] autorelease]; | ||
102 | } | ||
103 | |||
104 | + (id) viewWithFrame:(CGRect)frame pixelFormat:(NSString*)format | ||
105 | { | ||
106 | return [[[self alloc] initWithFrame:frame pixelFormat:format] autorelease]; | ||
107 | } | ||
108 | |||
109 | + (id) viewWithFrame:(CGRect)frame pixelFormat:(NSString*)format depthFormat:(GLuint)depth | ||
110 | { | ||
111 | return [[[self alloc] initWithFrame:frame pixelFormat:format depthFormat:depth preserveBackbuffer:NO sharegroup:nil multiSampling:NO numberOfSamples:0] autorelease]; | ||
112 | } | ||
113 | |||
114 | + (id) viewWithFrame:(CGRect)frame pixelFormat:(NSString*)format depthFormat:(GLuint)depth preserveBackbuffer:(BOOL)retained sharegroup:(EAGLSharegroup*)sharegroup multiSampling:(BOOL)multisampling numberOfSamples:(unsigned int)samples | ||
115 | { | ||
116 | return [[[self alloc] initWithFrame:frame pixelFormat:format depthFormat:depth preserveBackbuffer:retained sharegroup:sharegroup multiSampling:multisampling numberOfSamples:samples] autorelease]; | ||
117 | } | ||
118 | |||
119 | - (id) initWithFrame:(CGRect)frame | ||
120 | { | ||
121 | return [self initWithFrame:frame pixelFormat:kEAGLColorFormatRGB565 depthFormat:0 preserveBackbuffer:NO sharegroup:nil multiSampling:NO numberOfSamples:0]; | ||
122 | } | ||
123 | |||
124 | - (id) initWithFrame:(CGRect)frame pixelFormat:(NSString*)format | ||
125 | { | ||
126 | return [self initWithFrame:frame pixelFormat:format depthFormat:0 preserveBackbuffer:NO sharegroup:nil multiSampling:NO numberOfSamples:0]; | ||
127 | } | ||
128 | |||
129 | - (id) initWithFrame:(CGRect)frame pixelFormat:(NSString*)format depthFormat:(GLuint)depth preserveBackbuffer:(BOOL)retained sharegroup:(EAGLSharegroup*)sharegroup multiSampling:(BOOL)sampling numberOfSamples:(unsigned int)nSamples | ||
130 | { | ||
131 | if((self = [super initWithFrame:frame])) | ||
132 | { | ||
133 | pixelformat_ = format; | ||
134 | depthFormat_ = depth; | ||
135 | multiSampling_ = sampling; | ||
136 | requestedSamples_ = nSamples; | ||
137 | preserveBackbuffer_ = retained; | ||
138 | |||
139 | if( ! [self setupSurfaceWithSharegroup:sharegroup] ) { | ||
140 | [self release]; | ||
141 | return nil; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | return self; | ||
146 | } | ||
147 | |||
148 | -(id) initWithCoder:(NSCoder *)aDecoder | ||
149 | { | ||
150 | if( (self = [super initWithCoder:aDecoder]) ) { | ||
151 | |||
152 | CAEAGLLayer* eaglLayer = (CAEAGLLayer*)[self layer]; | ||
153 | |||
154 | pixelformat_ = kEAGLColorFormatRGB565; | ||
155 | depthFormat_ = 0; // GL_DEPTH_COMPONENT24_OES; | ||
156 | multiSampling_= NO; | ||
157 | requestedSamples_ = 0; | ||
158 | size_ = [eaglLayer bounds].size; | ||
159 | |||
160 | if( ! [self setupSurfaceWithSharegroup:nil] ) { | ||
161 | [self release]; | ||
162 | return nil; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | return self; | ||
167 | } | ||
168 | |||
169 | -(BOOL) setupSurfaceWithSharegroup:(EAGLSharegroup*)sharegroup | ||
170 | { | ||
171 | CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; | ||
172 | |||
173 | eaglLayer.opaque = YES; | ||
174 | eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: | ||
175 | [NSNumber numberWithBool:preserveBackbuffer_], kEAGLDrawablePropertyRetainedBacking, | ||
176 | pixelformat_, kEAGLDrawablePropertyColorFormat, nil]; | ||
177 | |||
178 | |||
179 | renderer_ = [[ES1Renderer alloc] initWithDepthFormat:depthFormat_ | ||
180 | withPixelFormat:[self convertPixelFormat:pixelformat_] | ||
181 | withSharegroup:sharegroup | ||
182 | withMultiSampling:multiSampling_ | ||
183 | withNumberOfSamples:requestedSamples_]; | ||
184 | if (!renderer_) | ||
185 | return NO; | ||
186 | |||
187 | context_ = [renderer_ context]; | ||
188 | [context_ renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:eaglLayer]; | ||
189 | |||
190 | discardFramebufferSupported_ = [[CCConfiguration sharedConfiguration] supportsDiscardFramebuffer]; | ||
191 | |||
192 | return YES; | ||
193 | } | ||
194 | |||
195 | - (void) dealloc | ||
196 | { | ||
197 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
198 | |||
199 | |||
200 | [renderer_ release]; | ||
201 | [super dealloc]; | ||
202 | } | ||
203 | |||
204 | - (void) layoutSubviews | ||
205 | { | ||
206 | size_ = [renderer_ backingSize]; | ||
207 | |||
208 | [renderer_ resizeFromLayer:(CAEAGLLayer*)self.layer]; | ||
209 | |||
210 | // Issue #914 #924 | ||
211 | CCDirector *director = [CCDirector sharedDirector]; | ||
212 | [director reshapeProjection:size_]; | ||
213 | |||
214 | // Avoid flicker. Issue #350 | ||
215 | [director performSelectorOnMainThread:@selector(drawScene) withObject:nil waitUntilDone:YES]; | ||
216 | } | ||
217 | |||
218 | - (void) swapBuffers | ||
219 | { | ||
220 | // IMPORTANT: | ||
221 | // - preconditions | ||
222 | // -> context_ MUST be the OpenGL context | ||
223 | // -> renderbuffer_ must be the the RENDER BUFFER | ||
224 | |||
225 | #ifdef __IPHONE_4_0 | ||
226 | |||
227 | if (multiSampling_) | ||
228 | { | ||
229 | /* Resolve from msaaFramebuffer to resolveFramebuffer */ | ||
230 | //glDisable(GL_SCISSOR_TEST); | ||
231 | glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, [renderer_ msaaFrameBuffer]); | ||
232 | glBindFramebufferOES(GL_DRAW_FRAMEBUFFER_APPLE, [renderer_ defaultFrameBuffer]); | ||
233 | glResolveMultisampleFramebufferAPPLE(); | ||
234 | } | ||
235 | |||
236 | if( discardFramebufferSupported_) | ||
237 | { | ||
238 | if (multiSampling_) | ||
239 | { | ||
240 | if (depthFormat_) | ||
241 | { | ||
242 | GLenum attachments[] = {GL_COLOR_ATTACHMENT0_OES, GL_DEPTH_ATTACHMENT_OES}; | ||
243 | glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, attachments); | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | GLenum attachments[] = {GL_COLOR_ATTACHMENT0_OES}; | ||
248 | glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 1, attachments); | ||
249 | } | ||
250 | |||
251 | glBindRenderbufferOES(GL_RENDERBUFFER_OES, [renderer_ colorRenderBuffer]); | ||
252 | |||
253 | } | ||
254 | |||
255 | // not MSAA | ||
256 | else if (depthFormat_ ) { | ||
257 | GLenum attachments[] = { GL_DEPTH_ATTACHMENT_OES}; | ||
258 | glDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 1, attachments); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | #endif // __IPHONE_4_0 | ||
263 | |||
264 | if(![context_ presentRenderbuffer:GL_RENDERBUFFER_OES]) | ||
265 | CCLOG(@"cocos2d: Failed to swap renderbuffer in %s\n", __FUNCTION__); | ||
266 | |||
267 | #if COCOS2D_DEBUG | ||
268 | CHECK_GL_ERROR(); | ||
269 | #endif | ||
270 | |||
271 | // We can safely re-bind the framebuffer here, since this will be the | ||
272 | // 1st instruction of the new main loop | ||
273 | if( multiSampling_ ) | ||
274 | glBindFramebufferOES(GL_FRAMEBUFFER_OES, [renderer_ msaaFrameBuffer]); | ||
275 | } | ||
276 | |||
277 | - (unsigned int) convertPixelFormat:(NSString*) pixelFormat | ||
278 | { | ||
279 | // define the pixel format | ||
280 | GLenum pFormat; | ||
281 | |||
282 | |||
283 | if([pixelFormat isEqualToString:@"EAGLColorFormat565"]) | ||
284 | pFormat = GL_RGB565_OES; | ||
285 | else | ||
286 | pFormat = GL_RGBA8_OES; | ||
287 | |||
288 | return pFormat; | ||
289 | } | ||
290 | |||
291 | #pragma mark EAGLView - Point conversion | ||
292 | |||
293 | - (CGPoint) convertPointFromViewToSurface:(CGPoint)point | ||
294 | { | ||
295 | CGRect bounds = [self bounds]; | ||
296 | |||
297 | return CGPointMake((point.x - bounds.origin.x) / bounds.size.width * size_.width, (point.y - bounds.origin.y) / bounds.size.height * size_.height); | ||
298 | } | ||
299 | |||
300 | - (CGRect) convertRectFromViewToSurface:(CGRect)rect | ||
301 | { | ||
302 | CGRect bounds = [self bounds]; | ||
303 | |||
304 | return CGRectMake((rect.origin.x - bounds.origin.x) / bounds.size.width * size_.width, (rect.origin.y - bounds.origin.y) / bounds.size.height * size_.height, rect.size.width / bounds.size.width * size_.width, rect.size.height / bounds.size.height * size_.height); | ||
305 | } | ||
306 | |||
307 | // Pass the touches to the superview | ||
308 | #pragma mark EAGLView - Touch Delegate | ||
309 | |||
310 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event | ||
311 | { | ||
312 | if(touchDelegate_) | ||
313 | { | ||
314 | [touchDelegate_ touchesBegan:touches withEvent:event]; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event | ||
319 | { | ||
320 | if(touchDelegate_) | ||
321 | { | ||
322 | [touchDelegate_ touchesMoved:touches withEvent:event]; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event | ||
327 | { | ||
328 | if(touchDelegate_) | ||
329 | { | ||
330 | [touchDelegate_ touchesEnded:touches withEvent:event]; | ||
331 | } | ||
332 | } | ||
333 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event | ||
334 | { | ||
335 | if(touchDelegate_) | ||
336 | { | ||
337 | [touchDelegate_ touchesCancelled:touches withEvent:event]; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | @end | ||
342 | |||
343 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED \ No newline at end of file | ||
diff --git a/libs/cocos2d/Platforms/iOS/ES1Renderer.h b/libs/cocos2d/Platforms/iOS/ES1Renderer.h new file mode 100755 index 0000000..fd946a7 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/ES1Renderer.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | * File autogenerated with Xcode. Adapted for cocos2d needs. | ||
27 | */ | ||
28 | |||
29 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
30 | // But in case they are included, it won't be compiled. | ||
31 | #import <Availability.h> | ||
32 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
33 | |||
34 | |||
35 | #import "ESRenderer.h" | ||
36 | |||
37 | #import <OpenGLES/ES1/gl.h> | ||
38 | #import <OpenGLES/ES1/glext.h> | ||
39 | |||
40 | @interface ES1Renderer : NSObject <ESRenderer> | ||
41 | { | ||
42 | // The pixel dimensions of the CAEAGLLayer | ||
43 | GLint backingWidth_; | ||
44 | GLint backingHeight_; | ||
45 | |||
46 | unsigned int samplesToUse_; | ||
47 | BOOL multiSampling_; | ||
48 | |||
49 | unsigned int depthFormat_; | ||
50 | unsigned int pixelFormat_; | ||
51 | |||
52 | // The OpenGL ES names for the framebuffer and renderbuffer used to render to this view | ||
53 | GLuint defaultFramebuffer_; | ||
54 | GLuint colorRenderbuffer_; | ||
55 | GLuint depthBuffer_; | ||
56 | |||
57 | |||
58 | //buffers for MSAA | ||
59 | GLuint msaaFramebuffer_; | ||
60 | GLuint msaaColorbuffer_; | ||
61 | |||
62 | EAGLContext *context_; | ||
63 | } | ||
64 | |||
65 | /** EAGLContext */ | ||
66 | @property (nonatomic,readonly) EAGLContext* context; | ||
67 | |||
68 | - (BOOL)resizeFromLayer:(CAEAGLLayer *)layer; | ||
69 | |||
70 | @end | ||
71 | |||
72 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/ES1Renderer.m b/libs/cocos2d/Platforms/iOS/ES1Renderer.m new file mode 100755 index 0000000..398d946 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/ES1Renderer.m | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | * File autogenerated with Xcode. Adapted for cocos2d needs. | ||
27 | */ | ||
28 | |||
29 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
30 | // But in case they are included, it won't be compiled. | ||
31 | #import <Availability.h> | ||
32 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
33 | |||
34 | #import "ES1Renderer.h" | ||
35 | #import "../../Support/OpenGL_Internal.h" | ||
36 | #import "../../ccMacros.h" | ||
37 | |||
38 | |||
39 | @interface ES1Renderer (private) | ||
40 | |||
41 | - (GLenum) convertPixelFormat:(int) pixelFormat; | ||
42 | |||
43 | @end | ||
44 | |||
45 | |||
46 | @implementation ES1Renderer | ||
47 | |||
48 | @synthesize context=context_; | ||
49 | |||
50 | - (id) initWithDepthFormat:(unsigned int)depthFormat withPixelFormat:(unsigned int)pixelFormat withSharegroup:(EAGLSharegroup*)sharegroup withMultiSampling:(BOOL) multiSampling withNumberOfSamples:(unsigned int) requestedSamples | ||
51 | { | ||
52 | if ((self = [super init])) | ||
53 | { | ||
54 | if ( sharegroup == nil ) | ||
55 | { | ||
56 | context_ = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; | ||
57 | } | ||
58 | else | ||
59 | { | ||
60 | context_ = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:sharegroup]; | ||
61 | } | ||
62 | |||
63 | if (!context_ || ![EAGLContext setCurrentContext:context_]) | ||
64 | { | ||
65 | [self release]; | ||
66 | return nil; | ||
67 | } | ||
68 | |||
69 | // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer | ||
70 | glGenFramebuffersOES(1, &defaultFramebuffer_); | ||
71 | NSAssert( defaultFramebuffer_, @"Can't create default frame buffer"); | ||
72 | glGenRenderbuffersOES(1, &colorRenderbuffer_); | ||
73 | NSAssert( colorRenderbuffer_, @"Can't create default render buffer"); | ||
74 | |||
75 | glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer_); | ||
76 | glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer_); | ||
77 | glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer_); | ||
78 | |||
79 | depthFormat_ = depthFormat; | ||
80 | |||
81 | if( depthFormat_ ) { | ||
82 | // glGenRenderbuffersOES(1, &depthBuffer_); | ||
83 | // glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthBuffer_); | ||
84 | // glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthFormat_, 100, 100); | ||
85 | // glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthBuffer_); | ||
86 | |||
87 | // default buffer | ||
88 | // glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer_); | ||
89 | } | ||
90 | |||
91 | pixelFormat_ = pixelFormat; | ||
92 | multiSampling_ = multiSampling; | ||
93 | if (multiSampling_) | ||
94 | { | ||
95 | GLint maxSamplesAllowed; | ||
96 | glGetIntegerv(GL_MAX_SAMPLES_APPLE, &maxSamplesAllowed); | ||
97 | samplesToUse_ = MIN(maxSamplesAllowed,requestedSamples); | ||
98 | |||
99 | /* Create the MSAA framebuffer (offscreen) */ | ||
100 | glGenFramebuffersOES(1, &msaaFramebuffer_); | ||
101 | glBindFramebufferOES(GL_FRAMEBUFFER_OES, msaaFramebuffer_); | ||
102 | |||
103 | } | ||
104 | |||
105 | CHECK_GL_ERROR(); | ||
106 | } | ||
107 | |||
108 | return self; | ||
109 | } | ||
110 | |||
111 | - (BOOL)resizeFromLayer:(CAEAGLLayer *)layer | ||
112 | { | ||
113 | // Allocate color buffer backing based on the current layer size | ||
114 | |||
115 | glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer_); | ||
116 | |||
117 | if (![context_ renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer]) | ||
118 | { | ||
119 | CCLOG(@"failed to call context"); | ||
120 | } | ||
121 | |||
122 | glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth_); | ||
123 | glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight_); | ||
124 | |||
125 | CCLOG(@"cocos2d: surface size: %dx%d", (int)backingWidth_, (int)backingHeight_); | ||
126 | |||
127 | if (multiSampling_) | ||
128 | { | ||
129 | |||
130 | if ( msaaColorbuffer_) { | ||
131 | glDeleteRenderbuffersOES(1, &msaaColorbuffer_); | ||
132 | msaaColorbuffer_ = 0; | ||
133 | } | ||
134 | |||
135 | /* Create the offscreen MSAA color buffer. | ||
136 | After rendering, the contents of this will be blitted into ColorRenderbuffer */ | ||
137 | |||
138 | //msaaFrameBuffer needs to be binded | ||
139 | glBindFramebufferOES(GL_FRAMEBUFFER_OES, msaaFramebuffer_); | ||
140 | glGenRenderbuffersOES(1, &msaaColorbuffer_); | ||
141 | glBindRenderbufferOES(GL_RENDERBUFFER_OES, msaaColorbuffer_); | ||
142 | glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, samplesToUse_,pixelFormat_ , backingWidth_, backingHeight_); | ||
143 | glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, msaaColorbuffer_); | ||
144 | |||
145 | if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) | ||
146 | { | ||
147 | CCLOG(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); | ||
148 | return NO; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | if (depthFormat_) | ||
153 | { | ||
154 | if( ! depthBuffer_ ) | ||
155 | glGenRenderbuffersOES(1, &depthBuffer_); | ||
156 | |||
157 | glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthBuffer_); | ||
158 | if( multiSampling_ ) | ||
159 | glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, samplesToUse_, depthFormat_,backingWidth_, backingHeight_); | ||
160 | else | ||
161 | glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthFormat_, backingWidth_, backingHeight_); | ||
162 | glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthBuffer_); | ||
163 | |||
164 | // bind color buffer | ||
165 | glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer_); | ||
166 | } | ||
167 | |||
168 | glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer_); | ||
169 | |||
170 | if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) | ||
171 | { | ||
172 | CCLOG(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); | ||
173 | return NO; | ||
174 | } | ||
175 | |||
176 | CHECK_GL_ERROR(); | ||
177 | |||
178 | return YES; | ||
179 | } | ||
180 | |||
181 | -(CGSize) backingSize | ||
182 | { | ||
183 | return CGSizeMake( backingWidth_, backingHeight_); | ||
184 | } | ||
185 | |||
186 | - (NSString*) description | ||
187 | { | ||
188 | return [NSString stringWithFormat:@"<%@ = %08X | size = %ix%i>", [self class], self, backingWidth_, backingHeight_]; | ||
189 | } | ||
190 | |||
191 | |||
192 | - (void)dealloc | ||
193 | { | ||
194 | CCLOGINFO(@"cocos2d: deallocing %@", self); | ||
195 | |||
196 | // Tear down GL | ||
197 | if(defaultFramebuffer_) | ||
198 | { | ||
199 | glDeleteFramebuffersOES(1, &defaultFramebuffer_); | ||
200 | defaultFramebuffer_ = 0; | ||
201 | } | ||
202 | |||
203 | if(colorRenderbuffer_) | ||
204 | { | ||
205 | glDeleteRenderbuffersOES(1, &colorRenderbuffer_); | ||
206 | colorRenderbuffer_ = 0; | ||
207 | } | ||
208 | |||
209 | if( depthBuffer_ ) | ||
210 | { | ||
211 | glDeleteRenderbuffersOES(1, &depthBuffer_); | ||
212 | depthBuffer_ = 0; | ||
213 | } | ||
214 | |||
215 | if ( msaaColorbuffer_) | ||
216 | { | ||
217 | glDeleteRenderbuffersOES(1, &msaaColorbuffer_); | ||
218 | msaaColorbuffer_ = 0; | ||
219 | } | ||
220 | |||
221 | if ( msaaFramebuffer_) | ||
222 | { | ||
223 | glDeleteRenderbuffersOES(1, &msaaFramebuffer_); | ||
224 | msaaFramebuffer_ = 0; | ||
225 | } | ||
226 | |||
227 | // Tear down context | ||
228 | if ([EAGLContext currentContext] == context_) | ||
229 | [EAGLContext setCurrentContext:nil]; | ||
230 | |||
231 | [context_ release]; | ||
232 | context_ = nil; | ||
233 | |||
234 | [super dealloc]; | ||
235 | } | ||
236 | |||
237 | - (unsigned int) colorRenderBuffer | ||
238 | { | ||
239 | return colorRenderbuffer_; | ||
240 | } | ||
241 | |||
242 | - (unsigned int) defaultFrameBuffer | ||
243 | { | ||
244 | return defaultFramebuffer_; | ||
245 | } | ||
246 | |||
247 | - (unsigned int) msaaFrameBuffer | ||
248 | { | ||
249 | return msaaFramebuffer_; | ||
250 | } | ||
251 | |||
252 | - (unsigned int) msaaColorBuffer | ||
253 | { | ||
254 | return msaaColorbuffer_; | ||
255 | } | ||
256 | |||
257 | @end | ||
258 | |||
259 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/ESRenderer.h b/libs/cocos2d/Platforms/iOS/ESRenderer.h new file mode 100755 index 0000000..e612eee --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/ESRenderer.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 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 | * File autogenerated with Xcode. Adapted for cocos2d needs. | ||
27 | */ | ||
28 | |||
29 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
30 | // But in case they are included, it won't be compiled. | ||
31 | #import <Availability.h> | ||
32 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
33 | |||
34 | #import <QuartzCore/QuartzCore.h> | ||
35 | |||
36 | #import <OpenGLES/EAGL.h> | ||
37 | #import <OpenGLES/EAGLDrawable.h> | ||
38 | |||
39 | @protocol ESRenderer <NSObject> | ||
40 | |||
41 | - (id) initWithDepthFormat:(unsigned int)depthFormat withPixelFormat:(unsigned int)pixelFormat withSharegroup:(EAGLSharegroup*)sharegroup withMultiSampling:(BOOL) multiSampling withNumberOfSamples:(unsigned int) requestedSamples; | ||
42 | |||
43 | - (BOOL) resizeFromLayer:(CAEAGLLayer *)layer; | ||
44 | |||
45 | - (EAGLContext*) context; | ||
46 | - (CGSize) backingSize; | ||
47 | |||
48 | - (unsigned int) colorRenderBuffer; | ||
49 | - (unsigned int) defaultFrameBuffer; | ||
50 | - (unsigned int) msaaFrameBuffer; | ||
51 | - (unsigned int) msaaColorBuffer; | ||
52 | @end | ||
53 | |||
54 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/glu.c b/libs/cocos2d/Platforms/iOS/glu.c new file mode 100755 index 0000000..2e00d5f --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/glu.c | |||
@@ -0,0 +1,113 @@ | |||
1 | // | ||
2 | // cocos2d (incomplete) GLU implementation | ||
3 | // | ||
4 | // gluLookAt and gluPerspective from: | ||
5 | // http://jet.ro/creations (San Angeles Observation) | ||
6 | // | ||
7 | // | ||
8 | |||
9 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
10 | // But in case they are included, it won't be compiled. | ||
11 | #import <Availability.h> | ||
12 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
13 | |||
14 | #import <OpenGLES/ES1/gl.h> | ||
15 | #import <math.h> | ||
16 | #import "../../Support/OpenGL_Internal.h" | ||
17 | #include "glu.h" | ||
18 | |||
19 | void gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar) | ||
20 | { | ||
21 | GLfloat xmin, xmax, ymin, ymax; | ||
22 | |||
23 | ymax = zNear * (GLfloat)tanf(fovy * (float)M_PI / 360); | ||
24 | ymin = -ymax; | ||
25 | xmin = ymin * aspect; | ||
26 | xmax = ymax * aspect; | ||
27 | |||
28 | glFrustumf(xmin, xmax, | ||
29 | ymin, ymax, | ||
30 | zNear, zFar); | ||
31 | } | ||
32 | |||
33 | void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, | ||
34 | GLfloat centerx, GLfloat centery, GLfloat centerz, | ||
35 | GLfloat upx, GLfloat upy, GLfloat upz) | ||
36 | { | ||
37 | GLfloat m[16]; | ||
38 | GLfloat x[3], y[3], z[3]; | ||
39 | GLfloat mag; | ||
40 | |||
41 | /* Make rotation matrix */ | ||
42 | |||
43 | /* Z vector */ | ||
44 | z[0] = eyex - centerx; | ||
45 | z[1] = eyey - centery; | ||
46 | z[2] = eyez - centerz; | ||
47 | mag = (float)sqrtf(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); | ||
48 | if (mag) { | ||
49 | z[0] /= mag; | ||
50 | z[1] /= mag; | ||
51 | z[2] /= mag; | ||
52 | } | ||
53 | |||
54 | /* Y vector */ | ||
55 | y[0] = upx; | ||
56 | y[1] = upy; | ||
57 | y[2] = upz; | ||
58 | |||
59 | /* X vector = Y cross Z */ | ||
60 | x[0] = y[1] * z[2] - y[2] * z[1]; | ||
61 | x[1] = -y[0] * z[2] + y[2] * z[0]; | ||
62 | x[2] = y[0] * z[1] - y[1] * z[0]; | ||
63 | |||
64 | /* Recompute Y = Z cross X */ | ||
65 | y[0] = z[1] * x[2] - z[2] * x[1]; | ||
66 | y[1] = -z[0] * x[2] + z[2] * x[0]; | ||
67 | y[2] = z[0] * x[1] - z[1] * x[0]; | ||
68 | |||
69 | /* cross product gives area of parallelogram, which is < 1.0 for | ||
70 | * non-perpendicular unit-length vectors; so normalize x, y here | ||
71 | */ | ||
72 | |||
73 | mag = (float)sqrtf(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); | ||
74 | if (mag) { | ||
75 | x[0] /= mag; | ||
76 | x[1] /= mag; | ||
77 | x[2] /= mag; | ||
78 | } | ||
79 | |||
80 | mag = (float)sqrtf(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); | ||
81 | if (mag) { | ||
82 | y[0] /= mag; | ||
83 | y[1] /= mag; | ||
84 | y[2] /= mag; | ||
85 | } | ||
86 | |||
87 | #define M(row,col) m[col*4+row] | ||
88 | M(0, 0) = x[0]; | ||
89 | M(0, 1) = x[1]; | ||
90 | M(0, 2) = x[2]; | ||
91 | M(0, 3) = 0.0f; | ||
92 | M(1, 0) = y[0]; | ||
93 | M(1, 1) = y[1]; | ||
94 | M(1, 2) = y[2]; | ||
95 | M(1, 3) = 0.0f; | ||
96 | M(2, 0) = z[0]; | ||
97 | M(2, 1) = z[1]; | ||
98 | M(2, 2) = z[2]; | ||
99 | M(2, 3) = 0.0f; | ||
100 | M(3, 0) = 0.0f; | ||
101 | M(3, 1) = 0.0f; | ||
102 | M(3, 2) = 0.0f; | ||
103 | M(3, 3) = 1.0f; | ||
104 | #undef M | ||
105 | |||
106 | glMultMatrixf(m); | ||
107 | |||
108 | |||
109 | /* Translate Eye to Origin */ | ||
110 | glTranslatef(-eyex, -eyey, -eyez); | ||
111 | } | ||
112 | |||
113 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
diff --git a/libs/cocos2d/Platforms/iOS/glu.h b/libs/cocos2d/Platforms/iOS/glu.h new file mode 100755 index 0000000..86dcac7 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/glu.h | |||
@@ -0,0 +1,29 @@ | |||
1 | // | ||
2 | // cocos2d GLU implementation | ||
3 | // | ||
4 | // implementation of GLU functions | ||
5 | // | ||
6 | #ifndef __COCOS2D_GLU_H | ||
7 | #define __COCOS2D_GLU_H | ||
8 | |||
9 | // Only compile this code on iOS. These files should NOT be included on your Mac project. | ||
10 | // But in case they are included, it won't be compiled. | ||
11 | #import <Availability.h> | ||
12 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
13 | |||
14 | #import <OpenGLES/ES1/gl.h> | ||
15 | |||
16 | /** | ||
17 | @file | ||
18 | cocos2d OpenGL GLU implementation | ||
19 | */ | ||
20 | |||
21 | /** OpenGL gluLookAt implementation */ | ||
22 | void gluLookAt(float eyeX, float eyeY, float eyeZ, float lookAtX, float lookAtY, float lookAtZ, float upX, float upY, float upZ); | ||
23 | /** OpenGL gluPerspective implementation */ | ||
24 | void gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar); | ||
25 | |||
26 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
27 | |||
28 | #endif /* __COCOS2D_GLU_H */ | ||
29 | |||
diff --git a/libs/cocos2d/Support/CCArray.h b/libs/cocos2d/Support/CCArray.h new file mode 100755 index 0000000..0c7b2b8 --- /dev/null +++ b/libs/cocos2d/Support/CCArray.h | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | |||
26 | #import "ccCArray.h" | ||
27 | |||
28 | |||
29 | /** A faster alternative of NSArray. | ||
30 | CCArray uses internally a c-array. | ||
31 | @since v0.99.4 | ||
32 | */ | ||
33 | |||
34 | |||
35 | /** @def CCARRAY_FOREACH | ||
36 | A convience macro to iterate over a CCArray using. It is faster than the "fast enumeration" interface. | ||
37 | @since v0.99.4 | ||
38 | */ | ||
39 | |||
40 | #define CCARRAY_FOREACH(__array__, __object__) \ | ||
41 | if (__array__ && __array__->data->num > 0) \ | ||
42 | for(id *__arr__ = __array__->data->arr, *end = __array__->data->arr + __array__->data->num-1; \ | ||
43 | __arr__ <= end && ((__object__ = *__arr__) != nil || true); \ | ||
44 | __arr__++) | ||
45 | |||
46 | @interface CCArray : NSObject <NSFastEnumeration, NSCoding, NSCopying> | ||
47 | { | ||
48 | @public ccArray *data; | ||
49 | } | ||
50 | |||
51 | + (id) array; | ||
52 | + (id) arrayWithCapacity:(NSUInteger)capacity; | ||
53 | + (id) arrayWithArray:(CCArray*)otherArray; | ||
54 | + (id) arrayWithNSArray:(NSArray*)otherArray; | ||
55 | |||
56 | |||
57 | - (id) initWithCapacity:(NSUInteger)capacity; | ||
58 | - (id) initWithArray:(CCArray*)otherArray; | ||
59 | - (id) initWithNSArray:(NSArray*)otherArray; | ||
60 | |||
61 | |||
62 | // Querying an Array | ||
63 | |||
64 | - (NSUInteger) count; | ||
65 | - (NSUInteger) capacity; | ||
66 | - (NSUInteger) indexOfObject:(id)object; | ||
67 | - (id) objectAtIndex:(NSUInteger)index; | ||
68 | - (BOOL) containsObject:(id)object; | ||
69 | - (id) randomObject; | ||
70 | - (id) lastObject; | ||
71 | - (NSArray*) getNSArray; | ||
72 | |||
73 | |||
74 | // Adding Objects | ||
75 | |||
76 | - (void) addObject:(id)object; | ||
77 | - (void) addObjectsFromArray:(CCArray*)otherArray; | ||
78 | - (void) addObjectsFromNSArray:(NSArray*)otherArray; | ||
79 | - (void) insertObject:(id)object atIndex:(NSUInteger)index; | ||
80 | |||
81 | |||
82 | // Removing Objects | ||
83 | |||
84 | - (void) removeLastObject; | ||
85 | - (void) removeObject:(id)object; | ||
86 | - (void) removeObjectAtIndex:(NSUInteger)index; | ||
87 | - (void) removeObjectsInArray:(CCArray*)otherArray; | ||
88 | - (void) removeAllObjects; | ||
89 | - (void) fastRemoveObject:(id)object; | ||
90 | - (void) fastRemoveObjectAtIndex:(NSUInteger)index; | ||
91 | |||
92 | |||
93 | // Rearranging Content | ||
94 | |||
95 | - (void) exchangeObject:(id)object1 withObject:(id)object2; | ||
96 | - (void) exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2; | ||
97 | - (void) reverseObjects; | ||
98 | - (void) reduceMemoryFootprint; | ||
99 | |||
100 | // Sending Messages to Elements | ||
101 | |||
102 | - (void) makeObjectsPerformSelector:(SEL)aSelector; | ||
103 | - (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)object; | ||
104 | |||
105 | |||
106 | @end | ||
diff --git a/libs/cocos2d/Support/CCArray.m b/libs/cocos2d/Support/CCArray.m new file mode 100755 index 0000000..a48a5f3 --- /dev/null +++ b/libs/cocos2d/Support/CCArray.m | |||
@@ -0,0 +1,290 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #import "CCArray.h" | ||
26 | #import "../ccMacros.h" | ||
27 | |||
28 | |||
29 | @implementation CCArray | ||
30 | |||
31 | + (id) array | ||
32 | { | ||
33 | return [[[self alloc] init] autorelease]; | ||
34 | } | ||
35 | |||
36 | + (id) arrayWithCapacity:(NSUInteger)capacity | ||
37 | { | ||
38 | return [[[self alloc] initWithCapacity:capacity] autorelease]; | ||
39 | } | ||
40 | |||
41 | + (id) arrayWithArray:(CCArray*)otherArray | ||
42 | { | ||
43 | return [[(CCArray*)[self alloc] initWithArray:otherArray] autorelease]; | ||
44 | } | ||
45 | |||
46 | + (id) arrayWithNSArray:(NSArray*)otherArray | ||
47 | { | ||
48 | return [[(CCArray*)[self alloc] initWithNSArray:otherArray] autorelease]; | ||
49 | } | ||
50 | |||
51 | - (id) init | ||
52 | { | ||
53 | self = [self initWithCapacity:2]; | ||
54 | return self; | ||
55 | } | ||
56 | |||
57 | - (id) initWithCapacity:(NSUInteger)capacity | ||
58 | { | ||
59 | self = [super init]; | ||
60 | if (self != nil) { | ||
61 | data = ccArrayNew(capacity); | ||
62 | } | ||
63 | return self; | ||
64 | } | ||
65 | |||
66 | - (id) initWithArray:(CCArray*)otherArray | ||
67 | { | ||
68 | self = [self initWithCapacity:otherArray->data->num]; | ||
69 | if (self != nil) { | ||
70 | [self addObjectsFromArray:otherArray]; | ||
71 | } | ||
72 | return self; | ||
73 | } | ||
74 | |||
75 | - (id) initWithNSArray:(NSArray*)otherArray | ||
76 | { | ||
77 | self = [self initWithCapacity:otherArray.count]; | ||
78 | if (self != nil) { | ||
79 | [self addObjectsFromNSArray:otherArray]; | ||
80 | } | ||
81 | return self; | ||
82 | } | ||
83 | |||
84 | - (id) initWithCoder:(NSCoder*)coder | ||
85 | { | ||
86 | self = [self initWithNSArray:[coder decodeObjectForKey:@"nsarray"]]; | ||
87 | return self; | ||
88 | } | ||
89 | |||
90 | |||
91 | #pragma mark Querying an Array | ||
92 | |||
93 | - (NSUInteger) count | ||
94 | { | ||
95 | return data->num; | ||
96 | } | ||
97 | |||
98 | - (NSUInteger) capacity | ||
99 | { | ||
100 | return data->max; | ||
101 | } | ||
102 | |||
103 | - (NSUInteger) indexOfObject:(id)object | ||
104 | { | ||
105 | return ccArrayGetIndexOfObject(data, object); | ||
106 | } | ||
107 | |||
108 | - (id) objectAtIndex:(NSUInteger)index | ||
109 | { | ||
110 | NSAssert2( index < data->num, @"index out of range in objectAtIndex(%d), index %i", data->num, index ); | ||
111 | |||
112 | return data->arr[index]; | ||
113 | } | ||
114 | |||
115 | - (BOOL) containsObject:(id)object | ||
116 | { | ||
117 | return ccArrayContainsObject(data, object); | ||
118 | } | ||
119 | |||
120 | - (id) lastObject | ||
121 | { | ||
122 | if( data->num > 0 ) | ||
123 | return data->arr[data->num-1]; | ||
124 | return nil; | ||
125 | } | ||
126 | |||
127 | - (id) randomObject | ||
128 | { | ||
129 | if(data->num==0) return nil; | ||
130 | return data->arr[(int)(data->num*CCRANDOM_0_1())]; | ||
131 | } | ||
132 | |||
133 | - (NSArray*) getNSArray | ||
134 | { | ||
135 | return [NSArray arrayWithObjects:data->arr count:data->num]; | ||
136 | } | ||
137 | |||
138 | |||
139 | #pragma mark Adding Objects | ||
140 | |||
141 | - (void) addObject:(id)object | ||
142 | { | ||
143 | ccArrayAppendObjectWithResize(data, object); | ||
144 | } | ||
145 | |||
146 | - (void) addObjectsFromArray:(CCArray*)otherArray | ||
147 | { | ||
148 | ccArrayAppendArrayWithResize(data, otherArray->data); | ||
149 | } | ||
150 | |||
151 | - (void) addObjectsFromNSArray:(NSArray*)otherArray | ||
152 | { | ||
153 | ccArrayEnsureExtraCapacity(data, otherArray.count); | ||
154 | for(id object in otherArray) | ||
155 | ccArrayAppendObject(data, object); | ||
156 | } | ||
157 | |||
158 | - (void) insertObject:(id)object atIndex:(NSUInteger)index | ||
159 | { | ||
160 | ccArrayInsertObjectAtIndex(data, object, index); | ||
161 | } | ||
162 | |||
163 | |||
164 | #pragma mark Removing Objects | ||
165 | |||
166 | - (void) removeObject:(id)object | ||
167 | { | ||
168 | ccArrayRemoveObject(data, object); | ||
169 | } | ||
170 | |||
171 | - (void) removeObjectAtIndex:(NSUInteger)index | ||
172 | { | ||
173 | ccArrayRemoveObjectAtIndex(data, index); | ||
174 | } | ||
175 | |||
176 | - (void) fastRemoveObject:(id)object | ||
177 | { | ||
178 | ccArrayFastRemoveObject(data, object); | ||
179 | } | ||
180 | |||
181 | - (void) fastRemoveObjectAtIndex:(NSUInteger)index | ||
182 | { | ||
183 | ccArrayFastRemoveObjectAtIndex(data, index); | ||
184 | } | ||
185 | |||
186 | - (void) removeObjectsInArray:(CCArray*)otherArray | ||
187 | { | ||
188 | ccArrayRemoveArray(data, otherArray->data); | ||
189 | } | ||
190 | |||
191 | - (void) removeLastObject | ||
192 | { | ||
193 | NSAssert( data->num > 0, @"no objects added" ); | ||
194 | |||
195 | ccArrayRemoveObjectAtIndex(data, data->num-1); | ||
196 | } | ||
197 | |||
198 | - (void) removeAllObjects | ||
199 | { | ||
200 | ccArrayRemoveAllObjects(data); | ||
201 | } | ||
202 | |||
203 | |||
204 | #pragma mark Rearranging Content | ||
205 | |||
206 | - (void) exchangeObject:(id)object1 withObject:(id)object2 | ||
207 | { | ||
208 | NSUInteger index1 = ccArrayGetIndexOfObject(data, object1); | ||
209 | if(index1 == NSNotFound) return; | ||
210 | NSUInteger index2 = ccArrayGetIndexOfObject(data, object2); | ||
211 | if(index2 == NSNotFound) return; | ||
212 | |||
213 | ccArraySwapObjectsAtIndexes(data, index1, index2); | ||
214 | } | ||
215 | |||
216 | - (void) exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 | ||
217 | { | ||
218 | ccArraySwapObjectsAtIndexes(data, index1, index2); | ||
219 | } | ||
220 | |||
221 | - (void) reverseObjects | ||
222 | { | ||
223 | if (data->num > 1) | ||
224 | { | ||
225 | //floor it since in case of a oneven number the number of swaps stays the same | ||
226 | int count = (int) floorf(data->num/2.f); | ||
227 | NSUInteger maxIndex = data->num - 1; | ||
228 | |||
229 | for (int i = 0; i < count ; i++) | ||
230 | { | ||
231 | ccArraySwapObjectsAtIndexes(data, i, maxIndex); | ||
232 | maxIndex--; | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | - (void) reduceMemoryFootprint | ||
238 | { | ||
239 | ccArrayShrink(data); | ||
240 | } | ||
241 | |||
242 | #pragma mark Sending Messages to Elements | ||
243 | |||
244 | - (void) makeObjectsPerformSelector:(SEL)aSelector | ||
245 | { | ||
246 | ccArrayMakeObjectsPerformSelector(data, aSelector); | ||
247 | } | ||
248 | |||
249 | - (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)object | ||
250 | { | ||
251 | ccArrayMakeObjectsPerformSelectorWithObject(data, aSelector, object); | ||
252 | } | ||
253 | |||
254 | |||
255 | #pragma mark CCArray - NSFastEnumeration protocol | ||
256 | |||
257 | - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len | ||
258 | { | ||
259 | if(state->state == 1) return 0; | ||
260 | |||
261 | state->mutationsPtr = (unsigned long *)self; | ||
262 | state->itemsPtr = &data->arr[0]; | ||
263 | state->state = 1; | ||
264 | return data->num; | ||
265 | } | ||
266 | |||
267 | |||
268 | #pragma mark CCArray - NSCopying protocol | ||
269 | |||
270 | - (id)copyWithZone:(NSZone *)zone | ||
271 | { | ||
272 | NSArray *nsArray = [self getNSArray]; | ||
273 | CCArray *newArray = [[[self class] allocWithZone:zone] initWithNSArray:nsArray]; | ||
274 | return newArray; | ||
275 | } | ||
276 | |||
277 | - (void) encodeWithCoder:(NSCoder *)coder | ||
278 | { | ||
279 | [coder encodeObject:[self getNSArray] forKey:@"nsarray"]; | ||
280 | } | ||
281 | |||
282 | #pragma mark | ||
283 | |||
284 | - (void) dealloc | ||
285 | { | ||
286 | ccArrayFree(data); | ||
287 | [super dealloc]; | ||
288 | } | ||
289 | |||
290 | @end | ||
diff --git a/libs/cocos2d/Support/CCFileUtils.h b/libs/cocos2d/Support/CCFileUtils.h new file mode 100755 index 0000000..0455202 --- /dev/null +++ b/libs/cocos2d/Support/CCFileUtils.h | |||
@@ -0,0 +1,62 @@ | |||
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 | #import <Foundation/Foundation.h> | ||
29 | |||
30 | |||
31 | /** Helper class to handle file operations */ | ||
32 | @interface CCFileUtils : NSObject | ||
33 | { | ||
34 | } | ||
35 | |||
36 | /** Returns the fullpath of an filename. | ||
37 | |||
38 | If this method is when Retina Display is enabled, then the | ||
39 | Retina Display suffix will be appended to the file (See ccConfig.h). | ||
40 | |||
41 | If the Retina Display image doesn't exist, then it will return the "non-Retina Display" image | ||
42 | |||
43 | */ | ||
44 | +(NSString*) fullPathFromRelativePath:(NSString*) relPath; | ||
45 | @end | ||
46 | |||
47 | /** loads a file into memory. | ||
48 | the caller should release the allocated buffer. | ||
49 | |||
50 | @returns the size of the allocated buffer | ||
51 | @since v0.99.5 | ||
52 | */ | ||
53 | NSInteger ccLoadFileIntoMemory(const char *filename, unsigned char **out); | ||
54 | |||
55 | |||
56 | /** removes the HD suffix from a path | ||
57 | |||
58 | @returns NSString * without the HD suffix | ||
59 | @since v0.99.5 | ||
60 | */ | ||
61 | NSString *ccRemoveHDSuffixFromFile( NSString *path ); | ||
62 | |||
diff --git a/libs/cocos2d/Support/CCFileUtils.m b/libs/cocos2d/Support/CCFileUtils.m new file mode 100755 index 0000000..6d33799 --- /dev/null +++ b/libs/cocos2d/Support/CCFileUtils.m | |||
@@ -0,0 +1,169 @@ | |||
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 | #import <Availability.h> | ||
29 | #import "CCFileUtils.h" | ||
30 | #import "../CCConfiguration.h" | ||
31 | #import "../ccMacros.h" | ||
32 | #import "../ccConfig.h" | ||
33 | |||
34 | static NSFileManager *__localFileManager=nil; | ||
35 | |||
36 | // | ||
37 | NSInteger ccLoadFileIntoMemory(const char *filename, unsigned char **out) | ||
38 | { | ||
39 | NSCAssert( out, @"ccLoadFileIntoMemory: invalid 'out' parameter"); | ||
40 | NSCAssert( &*out, @"ccLoadFileIntoMemory: invalid 'out' parameter"); | ||
41 | |||
42 | size_t size = 0; | ||
43 | FILE *f = fopen(filename, "rb"); | ||
44 | if( !f ) { | ||
45 | *out = NULL; | ||
46 | return -1; | ||
47 | } | ||
48 | |||
49 | fseek(f, 0, SEEK_END); | ||
50 | size = ftell(f); | ||
51 | fseek(f, 0, SEEK_SET); | ||
52 | |||
53 | *out = malloc(size); | ||
54 | size_t read = fread(*out, 1, size, f); | ||
55 | if( read != size ) { | ||
56 | free(*out); | ||
57 | *out = NULL; | ||
58 | return -1; | ||
59 | } | ||
60 | |||
61 | fclose(f); | ||
62 | |||
63 | return size; | ||
64 | } | ||
65 | |||
66 | NSString *ccRemoveHDSuffixFromFile( NSString *path ) | ||
67 | { | ||
68 | #if CC_IS_RETINA_DISPLAY_SUPPORTED | ||
69 | |||
70 | if( CC_CONTENT_SCALE_FACTOR() == 2 ) { | ||
71 | |||
72 | NSString *name = [path lastPathComponent]; | ||
73 | |||
74 | // check if path already has the suffix. | ||
75 | if( [name rangeOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX].location != NSNotFound ) { | ||
76 | |||
77 | CCLOG(@"cocos2d: Filename(%@) contains %@ suffix. Removing it. See cocos2d issue #1040", path, CC_RETINA_DISPLAY_FILENAME_SUFFIX); | ||
78 | |||
79 | NSString *newLastname = [name stringByReplacingOccurrencesOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX withString:@""]; | ||
80 | |||
81 | NSString *pathWithoutLastname = [path stringByDeletingLastPathComponent]; | ||
82 | return [pathWithoutLastname stringByAppendingPathComponent:newLastname]; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | #endif // CC_IS_RETINA_DISPLAY_SUPPORTED | ||
87 | |||
88 | return path; | ||
89 | |||
90 | } | ||
91 | |||
92 | |||
93 | @implementation CCFileUtils | ||
94 | |||
95 | +(void) initialize | ||
96 | { | ||
97 | if( self == [CCFileUtils class] ) | ||
98 | __localFileManager = [[NSFileManager alloc] init]; | ||
99 | } | ||
100 | |||
101 | +(NSString*) getDoubleResolutionImage:(NSString*)path | ||
102 | { | ||
103 | #if CC_IS_RETINA_DISPLAY_SUPPORTED | ||
104 | |||
105 | if( CC_CONTENT_SCALE_FACTOR() == 2 ) | ||
106 | { | ||
107 | |||
108 | NSString *pathWithoutExtension = [path stringByDeletingPathExtension]; | ||
109 | NSString *name = [pathWithoutExtension lastPathComponent]; | ||
110 | |||
111 | // check if path already has the suffix. | ||
112 | if( [name rangeOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX].location != NSNotFound ) { | ||
113 | |||
114 | CCLOG(@"cocos2d: WARNING Filename(%@) already has the suffix %@. Using it.", name, CC_RETINA_DISPLAY_FILENAME_SUFFIX); | ||
115 | return path; | ||
116 | } | ||
117 | |||
118 | |||
119 | NSString *extension = [path pathExtension]; | ||
120 | |||
121 | if( [extension isEqualToString:@"ccz"] || [extension isEqualToString:@"gz"] ) | ||
122 | { | ||
123 | // All ccz / gz files should be in the format filename.xxx.ccz | ||
124 | // so we need to pull off the .xxx part of the extension as well | ||
125 | extension = [NSString stringWithFormat:@"%@.%@", [pathWithoutExtension pathExtension], extension]; | ||
126 | pathWithoutExtension = [pathWithoutExtension stringByDeletingPathExtension]; | ||
127 | } | ||
128 | |||
129 | |||
130 | NSString *retinaName = [pathWithoutExtension stringByAppendingString:CC_RETINA_DISPLAY_FILENAME_SUFFIX]; | ||
131 | retinaName = [retinaName stringByAppendingPathExtension:extension]; | ||
132 | |||
133 | if( [__localFileManager fileExistsAtPath:retinaName] ) | ||
134 | return retinaName; | ||
135 | |||
136 | CCLOG(@"cocos2d: CCFileUtils: Warning HD file not found: %@", [retinaName lastPathComponent] ); | ||
137 | } | ||
138 | |||
139 | #endif // CC_IS_RETINA_DISPLAY_SUPPORTED | ||
140 | |||
141 | return path; | ||
142 | } | ||
143 | |||
144 | +(NSString*) fullPathFromRelativePath:(NSString*) relPath | ||
145 | { | ||
146 | NSAssert(relPath != nil, @"CCFileUtils: Invalid path"); | ||
147 | |||
148 | NSString *fullpath = nil; | ||
149 | |||
150 | // only if it is not an absolute path | ||
151 | if( ! [relPath isAbsolutePath] ) | ||
152 | { | ||
153 | NSString *file = [relPath lastPathComponent]; | ||
154 | NSString *imageDirectory = [relPath stringByDeletingLastPathComponent]; | ||
155 | |||
156 | fullpath = [[NSBundle mainBundle] pathForResource:file | ||
157 | ofType:nil | ||
158 | inDirectory:imageDirectory]; | ||
159 | } | ||
160 | |||
161 | if (fullpath == nil) | ||
162 | fullpath = relPath; | ||
163 | |||
164 | fullpath = [self getDoubleResolutionImage:fullpath]; | ||
165 | |||
166 | return fullpath; | ||
167 | } | ||
168 | |||
169 | @end | ||
diff --git a/libs/cocos2d/Support/CCProfiling.h b/libs/cocos2d/Support/CCProfiling.h new file mode 100755 index 0000000..b241fb9 --- /dev/null +++ b/libs/cocos2d/Support/CCProfiling.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Stuart Carnie | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import <Foundation/Foundation.h> | ||
28 | #import <sys/time.h> | ||
29 | |||
30 | @class CCProfilingTimer; | ||
31 | |||
32 | @interface CCProfiler : NSObject { | ||
33 | NSMutableArray* activeTimers; | ||
34 | } | ||
35 | |||
36 | + (CCProfiler*)sharedProfiler; | ||
37 | + (CCProfilingTimer*)timerWithName:(NSString*)timerName andInstance:(id)instance; | ||
38 | + (void)releaseTimer:(CCProfilingTimer*)timer; | ||
39 | - (void)displayTimers; | ||
40 | |||
41 | @end | ||
42 | |||
43 | |||
44 | @interface CCProfilingTimer : NSObject { | ||
45 | NSString* name; | ||
46 | struct timeval startTime; | ||
47 | double averageTime; | ||
48 | } | ||
49 | |||
50 | @end | ||
51 | |||
52 | extern void CCProfilingBeginTimingBlock(CCProfilingTimer* timer); | ||
53 | extern void CCProfilingEndTimingBlock(CCProfilingTimer* timer); | ||
diff --git a/libs/cocos2d/Support/CCProfiling.m b/libs/cocos2d/Support/CCProfiling.m new file mode 100755 index 0000000..13c8c81 --- /dev/null +++ b/libs/cocos2d/Support/CCProfiling.m | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2010 Stuart Carnie | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import "../ccConfig.h" | ||
27 | |||
28 | #if CC_ENABLE_PROFILERS | ||
29 | |||
30 | #import "CCProfiling.h" | ||
31 | |||
32 | @interface CCProfilingTimer() | ||
33 | - (id)initWithName:(NSString*)timerName andInstance:(id)instance; | ||
34 | @end | ||
35 | |||
36 | @implementation CCProfiler | ||
37 | |||
38 | static CCProfiler* g_sharedProfiler; | ||
39 | |||
40 | + (CCProfiler*)sharedProfiler { | ||
41 | if (!g_sharedProfiler) | ||
42 | g_sharedProfiler = [[CCProfiler alloc] init]; | ||
43 | |||
44 | return g_sharedProfiler; | ||
45 | } | ||
46 | |||
47 | + (CCProfilingTimer*)timerWithName:(NSString*)timerName andInstance:(id)instance { | ||
48 | CCProfiler* p = [CCProfiler sharedProfiler]; | ||
49 | CCProfilingTimer* t = [[CCProfilingTimer alloc] initWithName:timerName andInstance:instance]; | ||
50 | [p->activeTimers addObject:t]; | ||
51 | [t release]; | ||
52 | return t; | ||
53 | } | ||
54 | |||
55 | + (void)releaseTimer:(CCProfilingTimer*)timer { | ||
56 | CCProfiler* p = [CCProfiler sharedProfiler]; | ||
57 | [p->activeTimers removeObject:timer]; | ||
58 | } | ||
59 | |||
60 | - (id)init { | ||
61 | if (!(self = [super init])) return nil; | ||
62 | |||
63 | activeTimers = [[NSMutableArray alloc] init]; | ||
64 | |||
65 | return self; | ||
66 | } | ||
67 | |||
68 | - (void)dealloc { | ||
69 | [activeTimers release]; | ||
70 | [super dealloc]; | ||
71 | } | ||
72 | |||
73 | - (void)displayTimers { | ||
74 | for (id timer in activeTimers) { | ||
75 | printf("%s\n", [[timer description] cStringUsingEncoding:[NSString defaultCStringEncoding]]); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | @end | ||
80 | |||
81 | @implementation CCProfilingTimer | ||
82 | |||
83 | - (id)initWithName:(NSString*)timerName andInstance:(id)instance { | ||
84 | if (!(self = [super init])) return nil; | ||
85 | |||
86 | name = [[NSString stringWithFormat:@"%@ (0x%.8x)", timerName, instance] retain]; | ||
87 | |||
88 | return self; | ||
89 | } | ||
90 | |||
91 | - (void)dealloc { | ||
92 | [name release]; | ||
93 | [super dealloc]; | ||
94 | } | ||
95 | |||
96 | - (NSString*)description { | ||
97 | return [NSString stringWithFormat:@"%@ : avg time, %fms", name, averageTime]; | ||
98 | } | ||
99 | |||
100 | void CCProfilingBeginTimingBlock(CCProfilingTimer* timer) { | ||
101 | gettimeofday(&timer->startTime, NULL); | ||
102 | } | ||
103 | |||
104 | typedef unsigned int uint32; | ||
105 | void CCProfilingEndTimingBlock(CCProfilingTimer* timer) { | ||
106 | struct timeval currentTime; | ||
107 | gettimeofday(¤tTime, NULL); | ||
108 | timersub(¤tTime, &timer->startTime, ¤tTime); | ||
109 | double duration = currentTime.tv_sec * 1000.0 + currentTime.tv_usec / 1000.0; | ||
110 | |||
111 | // return in milliseconds | ||
112 | timer->averageTime = (timer->averageTime + duration) / 2.0f; | ||
113 | } | ||
114 | |||
115 | @end | ||
116 | |||
117 | #endif | ||
diff --git a/libs/cocos2d/Support/CGPointExtension.h b/libs/cocos2d/Support/CGPointExtension.h new file mode 100755 index 0000000..96edeb7 --- /dev/null +++ b/libs/cocos2d/Support/CGPointExtension.h | |||
@@ -0,0 +1,334 @@ | |||
1 | /* cocos2d for iPhone | ||
2 | * http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2007 Scott Lembcke | ||
5 | * | ||
6 | * Copyright (c) 2010 Lam Pham | ||
7 | * | ||
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
9 | * of this software and associated documentation files (the "Software"), to deal | ||
10 | * in the Software without restriction, including without limitation the rights | ||
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
12 | * copies of the Software, and to permit persons to whom the Software is | ||
13 | * furnished to do so, subject to the following conditions: | ||
14 | * | ||
15 | * The above copyright notice and this permission notice shall be included in | ||
16 | * all copies or substantial portions of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
24 | * SOFTWARE. | ||
25 | */ | ||
26 | |||
27 | /* | ||
28 | * Some of the functions were based on Chipmunk's cpVect.h. | ||
29 | */ | ||
30 | |||
31 | /** | ||
32 | @file | ||
33 | CGPoint extensions based on Chipmunk's cpVect file. | ||
34 | These extensions work both with CGPoint and cpVect. | ||
35 | |||
36 | The "ccp" prefix means: "CoCos2d Point" | ||
37 | |||
38 | Examples: | ||
39 | - ccpAdd( ccp(1,1), ccp(2,2) ); // preferred cocos2d way | ||
40 | - ccpAdd( CGPointMake(1,1), CGPointMake(2,2) ); // also ok but more verbose | ||
41 | |||
42 | - cpvadd( cpv(1,1), cpv(2,2) ); // way of the chipmunk | ||
43 | - ccpAdd( cpv(1,1), cpv(2,2) ); // mixing chipmunk and cocos2d (avoid) | ||
44 | - cpvadd( CGPointMake(1,1), CGPointMake(2,2) ); // mixing chipmunk and CG (avoid) | ||
45 | */ | ||
46 | |||
47 | #import <Availability.h> | ||
48 | |||
49 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
50 | #import <CoreGraphics/CGGeometry.h> | ||
51 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
52 | #import <Foundation/Foundation.h> | ||
53 | #endif | ||
54 | |||
55 | #import <math.h> | ||
56 | #import <objc/objc.h> | ||
57 | |||
58 | #ifdef __cplusplus | ||
59 | extern "C" { | ||
60 | #endif | ||
61 | |||
62 | /** Helper macro that creates a CGPoint | ||
63 | @return CGPoint | ||
64 | @since v0.7.2 | ||
65 | */ | ||
66 | #define ccp(__X__,__Y__) CGPointMake(__X__,__Y__) | ||
67 | |||
68 | |||
69 | /** Returns opposite of point. | ||
70 | @return CGPoint | ||
71 | @since v0.7.2 | ||
72 | */ | ||
73 | static inline CGPoint | ||
74 | ccpNeg(const CGPoint v) | ||
75 | { | ||
76 | return ccp(-v.x, -v.y); | ||
77 | } | ||
78 | |||
79 | /** Calculates sum of two points. | ||
80 | @return CGPoint | ||
81 | @since v0.7.2 | ||
82 | */ | ||
83 | static inline CGPoint | ||
84 | ccpAdd(const CGPoint v1, const CGPoint v2) | ||
85 | { | ||
86 | return ccp(v1.x + v2.x, v1.y + v2.y); | ||
87 | } | ||
88 | |||
89 | /** Calculates difference of two points. | ||
90 | @return CGPoint | ||
91 | @since v0.7.2 | ||
92 | */ | ||
93 | static inline CGPoint | ||
94 | ccpSub(const CGPoint v1, const CGPoint v2) | ||
95 | { | ||
96 | return ccp(v1.x - v2.x, v1.y - v2.y); | ||
97 | } | ||
98 | |||
99 | /** Returns point multiplied by given factor. | ||
100 | @return CGPoint | ||
101 | @since v0.7.2 | ||
102 | */ | ||
103 | static inline CGPoint | ||
104 | ccpMult(const CGPoint v, const CGFloat s) | ||
105 | { | ||
106 | return ccp(v.x*s, v.y*s); | ||
107 | } | ||
108 | |||
109 | /** Calculates midpoint between two points. | ||
110 | @return CGPoint | ||
111 | @since v0.7.2 | ||
112 | */ | ||
113 | static inline CGPoint | ||
114 | ccpMidpoint(const CGPoint v1, const CGPoint v2) | ||
115 | { | ||
116 | return ccpMult(ccpAdd(v1, v2), 0.5f); | ||
117 | } | ||
118 | |||
119 | /** Calculates dot product of two points. | ||
120 | @return CGFloat | ||
121 | @since v0.7.2 | ||
122 | */ | ||
123 | static inline CGFloat | ||
124 | ccpDot(const CGPoint v1, const CGPoint v2) | ||
125 | { | ||
126 | return v1.x*v2.x + v1.y*v2.y; | ||
127 | } | ||
128 | |||
129 | /** Calculates cross product of two points. | ||
130 | @return CGFloat | ||
131 | @since v0.7.2 | ||
132 | */ | ||
133 | static inline CGFloat | ||
134 | ccpCross(const CGPoint v1, const CGPoint v2) | ||
135 | { | ||
136 | return v1.x*v2.y - v1.y*v2.x; | ||
137 | } | ||
138 | |||
139 | /** Calculates perpendicular of v, rotated 90 degrees counter-clockwise -- cross(v, perp(v)) >= 0 | ||
140 | @return CGPoint | ||
141 | @since v0.7.2 | ||
142 | */ | ||
143 | static inline CGPoint | ||
144 | ccpPerp(const CGPoint v) | ||
145 | { | ||
146 | return ccp(-v.y, v.x); | ||
147 | } | ||
148 | |||
149 | /** Calculates perpendicular of v, rotated 90 degrees clockwise -- cross(v, rperp(v)) <= 0 | ||
150 | @return CGPoint | ||
151 | @since v0.7.2 | ||
152 | */ | ||
153 | static inline CGPoint | ||
154 | ccpRPerp(const CGPoint v) | ||
155 | { | ||
156 | return ccp(v.y, -v.x); | ||
157 | } | ||
158 | |||
159 | /** Calculates the projection of v1 over v2. | ||
160 | @return CGPoint | ||
161 | @since v0.7.2 | ||
162 | */ | ||
163 | static inline CGPoint | ||
164 | ccpProject(const CGPoint v1, const CGPoint v2) | ||
165 | { | ||
166 | return ccpMult(v2, ccpDot(v1, v2)/ccpDot(v2, v2)); | ||
167 | } | ||
168 | |||
169 | /** Rotates two points. | ||
170 | @return CGPoint | ||
171 | @since v0.7.2 | ||
172 | */ | ||
173 | static inline CGPoint | ||
174 | ccpRotate(const CGPoint v1, const CGPoint v2) | ||
175 | { | ||
176 | return ccp(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x); | ||
177 | } | ||
178 | |||
179 | /** Unrotates two points. | ||
180 | @return CGPoint | ||
181 | @since v0.7.2 | ||
182 | */ | ||
183 | static inline CGPoint | ||
184 | ccpUnrotate(const CGPoint v1, const CGPoint v2) | ||
185 | { | ||
186 | return ccp(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y); | ||
187 | } | ||
188 | |||
189 | /** Calculates the square length of a CGPoint (not calling sqrt() ) | ||
190 | @return CGFloat | ||
191 | @since v0.7.2 | ||
192 | */ | ||
193 | static inline CGFloat | ||
194 | ccpLengthSQ(const CGPoint v) | ||
195 | { | ||
196 | return ccpDot(v, v); | ||
197 | } | ||
198 | |||
199 | /** Calculates distance between point an origin | ||
200 | @return CGFloat | ||
201 | @since v0.7.2 | ||
202 | */ | ||
203 | CGFloat ccpLength(const CGPoint v); | ||
204 | |||
205 | /** Calculates the distance between two points | ||
206 | @return CGFloat | ||
207 | @since v0.7.2 | ||
208 | */ | ||
209 | CGFloat ccpDistance(const CGPoint v1, const CGPoint v2); | ||
210 | |||
211 | /** Returns point multiplied to a length of 1. | ||
212 | @return CGPoint | ||
213 | @since v0.7.2 | ||
214 | */ | ||
215 | CGPoint ccpNormalize(const CGPoint v); | ||
216 | |||
217 | /** Converts radians to a normalized vector. | ||
218 | @return CGPoint | ||
219 | @since v0.7.2 | ||
220 | */ | ||
221 | CGPoint ccpForAngle(const CGFloat a); | ||
222 | |||
223 | /** Converts a vector to radians. | ||
224 | @return CGFloat | ||
225 | @since v0.7.2 | ||
226 | */ | ||
227 | CGFloat ccpToAngle(const CGPoint v); | ||
228 | |||
229 | |||
230 | /** Clamp a value between from and to. | ||
231 | @since v0.99.1 | ||
232 | */ | ||
233 | float clampf(float value, float min_inclusive, float max_inclusive); | ||
234 | |||
235 | /** Clamp a point between from and to. | ||
236 | @since v0.99.1 | ||
237 | */ | ||
238 | CGPoint ccpClamp(CGPoint p, CGPoint from, CGPoint to); | ||
239 | |||
240 | /** Quickly convert CGSize to a CGPoint | ||
241 | @since v0.99.1 | ||
242 | */ | ||
243 | CGPoint ccpFromSize(CGSize s); | ||
244 | |||
245 | /** Run a math operation function on each point component | ||
246 | * absf, fllorf, ceilf, roundf | ||
247 | * any function that has the signature: float func(float); | ||
248 | * For example: let's try to take the floor of x,y | ||
249 | * ccpCompOp(p,floorf); | ||
250 | @since v0.99.1 | ||
251 | */ | ||
252 | CGPoint ccpCompOp(CGPoint p, float (*opFunc)(float)); | ||
253 | |||
254 | /** Linear Interpolation between two points a and b | ||
255 | @returns | ||
256 | alpha == 0 ? a | ||
257 | alpha == 1 ? b | ||
258 | otherwise a value between a..b | ||
259 | @since v0.99.1 | ||
260 | */ | ||
261 | CGPoint ccpLerp(CGPoint a, CGPoint b, float alpha); | ||
262 | |||
263 | |||
264 | /** @returns if points have fuzzy equality which means equal with some degree of variance. | ||
265 | @since v0.99.1 | ||
266 | */ | ||
267 | BOOL ccpFuzzyEqual(CGPoint a, CGPoint b, float variance); | ||
268 | |||
269 | |||
270 | /** Multiplies a nd b components, a.x*b.x, a.y*b.y | ||
271 | @returns a component-wise multiplication | ||
272 | @since v0.99.1 | ||
273 | */ | ||
274 | CGPoint ccpCompMult(CGPoint a, CGPoint b); | ||
275 | |||
276 | /** @returns the signed angle in radians between two vector directions | ||
277 | @since v0.99.1 | ||
278 | */ | ||
279 | float ccpAngleSigned(CGPoint a, CGPoint b); | ||
280 | |||
281 | /** @returns the angle in radians between two vector directions | ||
282 | @since v0.99.1 | ||
283 | */ | ||
284 | float ccpAngle(CGPoint a, CGPoint b); | ||
285 | |||
286 | /** Rotates a point counter clockwise by the angle around a pivot | ||
287 | @param v is the point to rotate | ||
288 | @param pivot is the pivot, naturally | ||
289 | @param angle is the angle of rotation cw in radians | ||
290 | @returns the rotated point | ||
291 | @since v0.99.1 | ||
292 | */ | ||
293 | CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle); | ||
294 | |||
295 | /** A general line-line intersection test | ||
296 | @param p1 | ||
297 | is the startpoint for the first line P1 = (p1 - p2) | ||
298 | @param p2 | ||
299 | is the endpoint for the first line P1 = (p1 - p2) | ||
300 | @param p3 | ||
301 | is the startpoint for the second line P2 = (p3 - p4) | ||
302 | @param p4 | ||
303 | is the endpoint for the second line P2 = (p3 - p4) | ||
304 | @param s | ||
305 | is the range for a hitpoint in P1 (pa = p1 + s*(p2 - p1)) | ||
306 | @param t | ||
307 | is the range for a hitpoint in P3 (pa = p2 + t*(p4 - p3)) | ||
308 | @return bool | ||
309 | indicating successful intersection of a line | ||
310 | note that to truly test intersection for segments we have to make | ||
311 | sure that s & t lie within [0..1] and for rays, make sure s & t > 0 | ||
312 | the hit point is p3 + t * (p4 - p3); | ||
313 | the hit point also is p1 + s * (p2 - p1); | ||
314 | @since v0.99.1 | ||
315 | */ | ||
316 | BOOL ccpLineIntersect(CGPoint p1, CGPoint p2, | ||
317 | CGPoint p3, CGPoint p4, | ||
318 | float *s, float *t); | ||
319 | |||
320 | /* | ||
321 | ccpSegmentIntersect returns YES if Segment A-B intersects with segment C-D | ||
322 | @since v1.0.0 | ||
323 | */ | ||
324 | BOOL ccpSegmentIntersect(CGPoint A, CGPoint B, CGPoint C, CGPoint D); | ||
325 | |||
326 | /* | ||
327 | ccpIntersectPoint returns the intersection point of line A-B, C-D | ||
328 | @since v1.0.0 | ||
329 | */ | ||
330 | CGPoint ccpIntersectPoint(CGPoint A, CGPoint B, CGPoint C, CGPoint D); | ||
331 | |||
332 | #ifdef __cplusplus | ||
333 | } | ||
334 | #endif | ||
diff --git a/libs/cocos2d/Support/CGPointExtension.m b/libs/cocos2d/Support/CGPointExtension.m new file mode 100755 index 0000000..b06859d --- /dev/null +++ b/libs/cocos2d/Support/CGPointExtension.m | |||
@@ -0,0 +1,196 @@ | |||
1 | /* cocos2d for iPhone | ||
2 | * http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2007 Scott Lembcke | ||
5 | * | ||
6 | * Copyright (c) 2010 Lam Pham | ||
7 | * | ||
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
9 | * of this software and associated documentation files (the "Software"), to deal | ||
10 | * in the Software without restriction, including without limitation the rights | ||
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
12 | * copies of the Software, and to permit persons to whom the Software is | ||
13 | * furnished to do so, subject to the following conditions: | ||
14 | * | ||
15 | * The above copyright notice and this permission notice shall be included in | ||
16 | * all copies or substantial portions of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
24 | * SOFTWARE. | ||
25 | */ | ||
26 | |||
27 | #include "stdio.h" | ||
28 | #include "math.h" | ||
29 | |||
30 | #import "../ccMacros.h" // CC_SWAP | ||
31 | #include "CGPointExtension.h" | ||
32 | |||
33 | #define kCGPointEpsilon FLT_EPSILON | ||
34 | |||
35 | CGFloat | ||
36 | ccpLength(const CGPoint v) | ||
37 | { | ||
38 | return sqrtf(ccpLengthSQ(v)); | ||
39 | } | ||
40 | |||
41 | CGFloat | ||
42 | ccpDistance(const CGPoint v1, const CGPoint v2) | ||
43 | { | ||
44 | return ccpLength(ccpSub(v1, v2)); | ||
45 | } | ||
46 | |||
47 | CGPoint | ||
48 | ccpNormalize(const CGPoint v) | ||
49 | { | ||
50 | return ccpMult(v, 1.0f/ccpLength(v)); | ||
51 | } | ||
52 | |||
53 | CGPoint | ||
54 | ccpForAngle(const CGFloat a) | ||
55 | { | ||
56 | return ccp(cosf(a), sinf(a)); | ||
57 | } | ||
58 | |||
59 | CGFloat | ||
60 | ccpToAngle(const CGPoint v) | ||
61 | { | ||
62 | return atan2f(v.y, v.x); | ||
63 | } | ||
64 | |||
65 | CGPoint ccpLerp(CGPoint a, CGPoint b, float alpha) | ||
66 | { | ||
67 | return ccpAdd(ccpMult(a, 1.f - alpha), ccpMult(b, alpha)); | ||
68 | } | ||
69 | |||
70 | float clampf(float value, float min_inclusive, float max_inclusive) | ||
71 | { | ||
72 | if (min_inclusive > max_inclusive) { | ||
73 | CC_SWAP(min_inclusive,max_inclusive); | ||
74 | } | ||
75 | return value < min_inclusive ? min_inclusive : value < max_inclusive? value : max_inclusive; | ||
76 | } | ||
77 | |||
78 | CGPoint ccpClamp(CGPoint p, CGPoint min_inclusive, CGPoint max_inclusive) | ||
79 | { | ||
80 | return ccp(clampf(p.x,min_inclusive.x,max_inclusive.x), clampf(p.y, min_inclusive.y, max_inclusive.y)); | ||
81 | } | ||
82 | |||
83 | CGPoint ccpFromSize(CGSize s) | ||
84 | { | ||
85 | return ccp(s.width, s.height); | ||
86 | } | ||
87 | |||
88 | CGPoint ccpCompOp(CGPoint p, float (*opFunc)(float)) | ||
89 | { | ||
90 | return ccp(opFunc(p.x), opFunc(p.y)); | ||
91 | } | ||
92 | |||
93 | BOOL ccpFuzzyEqual(CGPoint a, CGPoint b, float var) | ||
94 | { | ||
95 | if(a.x - var <= b.x && b.x <= a.x + var) | ||
96 | if(a.y - var <= b.y && b.y <= a.y + var) | ||
97 | return true; | ||
98 | return false; | ||
99 | } | ||
100 | |||
101 | CGPoint ccpCompMult(CGPoint a, CGPoint b) | ||
102 | { | ||
103 | return ccp(a.x * b.x, a.y * b.y); | ||
104 | } | ||
105 | |||
106 | float ccpAngleSigned(CGPoint a, CGPoint b) | ||
107 | { | ||
108 | CGPoint a2 = ccpNormalize(a); | ||
109 | CGPoint b2 = ccpNormalize(b); | ||
110 | float angle = atan2f(a2.x * b2.y - a2.y * b2.x, ccpDot(a2, b2)); | ||
111 | if( fabs(angle) < kCGPointEpsilon ) return 0.f; | ||
112 | return angle; | ||
113 | } | ||
114 | |||
115 | CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle) | ||
116 | { | ||
117 | CGPoint r = ccpSub(v, pivot); | ||
118 | float cosa = cosf(angle), sina = sinf(angle); | ||
119 | float t = r.x; | ||
120 | r.x = t*cosa - r.y*sina + pivot.x; | ||
121 | r.y = t*sina + r.y*cosa + pivot.y; | ||
122 | return r; | ||
123 | } | ||
124 | |||
125 | |||
126 | BOOL ccpSegmentIntersect(CGPoint A, CGPoint B, CGPoint C, CGPoint D) | ||
127 | { | ||
128 | float S, T; | ||
129 | |||
130 | if( ccpLineIntersect(A, B, C, D, &S, &T ) | ||
131 | && (S >= 0.0f && S <= 1.0f && T >= 0.0f && T <= 1.0f) ) | ||
132 | return YES; | ||
133 | |||
134 | return NO; | ||
135 | } | ||
136 | |||
137 | CGPoint ccpIntersectPoint(CGPoint A, CGPoint B, CGPoint C, CGPoint D) | ||
138 | { | ||
139 | float S, T; | ||
140 | |||
141 | if( ccpLineIntersect(A, B, C, D, &S, &T) ) { | ||
142 | // Point of intersection | ||
143 | CGPoint P; | ||
144 | P.x = A.x + S * (B.x - A.x); | ||
145 | P.y = A.y + S * (B.y - A.y); | ||
146 | return P; | ||
147 | } | ||
148 | |||
149 | return CGPointZero; | ||
150 | } | ||
151 | |||
152 | BOOL ccpLineIntersect(CGPoint A, CGPoint B, | ||
153 | CGPoint C, CGPoint D, | ||
154 | float *S, float *T) | ||
155 | { | ||
156 | // FAIL: Line undefined | ||
157 | if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) return NO; | ||
158 | |||
159 | const float BAx = B.x - A.x; | ||
160 | const float BAy = B.y - A.y; | ||
161 | const float DCx = D.x - C.x; | ||
162 | const float DCy = D.y - C.y; | ||
163 | const float ACx = A.x - C.x; | ||
164 | const float ACy = A.y - C.y; | ||
165 | |||
166 | const float denom = DCy*BAx - DCx*BAy; | ||
167 | |||
168 | *S = DCx*ACy - DCy*ACx; | ||
169 | *T = BAx*ACy - BAy*ACx; | ||
170 | |||
171 | if (denom == 0) { | ||
172 | if (*S == 0 || *T == 0) { | ||
173 | // Lines incident | ||
174 | return YES; | ||
175 | } | ||
176 | // Lines parallel and not incident | ||
177 | return NO; | ||
178 | } | ||
179 | |||
180 | *S = *S / denom; | ||
181 | *T = *T / denom; | ||
182 | |||
183 | // Point of intersection | ||
184 | // CGPoint P; | ||
185 | // P.x = A.x + *S * (B.x - A.x); | ||
186 | // P.y = A.y + *S * (B.y - A.y); | ||
187 | |||
188 | return YES; | ||
189 | } | ||
190 | |||
191 | float ccpAngle(CGPoint a, CGPoint b) | ||
192 | { | ||
193 | float angle = acosf(ccpDot(ccpNormalize(a), ccpNormalize(b))); | ||
194 | if( fabs(angle) < kCGPointEpsilon ) return 0.f; | ||
195 | return angle; | ||
196 | } | ||
diff --git a/libs/cocos2d/Support/OpenGL_Internal.h b/libs/cocos2d/Support/OpenGL_Internal.h new file mode 100755 index 0000000..4789683 --- /dev/null +++ b/libs/cocos2d/Support/OpenGL_Internal.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | |||
3 | ===== IMPORTANT ===== | ||
4 | |||
5 | This is sample code demonstrating API, technology or techniques in development. | ||
6 | Although this sample code has been reviewed for technical accuracy, it is not | ||
7 | final. Apple is supplying this information to help you plan for the adoption of | ||
8 | the technologies and programming interfaces described herein. This information | ||
9 | is subject to change, and software implemented based on this sample code should | ||
10 | be tested with final operating system software and final documentation. Newer | ||
11 | versions of this sample code may be provided with future seeds of the API or | ||
12 | technology. For information about updates to this and other developer | ||
13 | documentation, view the New & Updated sidebars in subsequent documentation | ||
14 | seeds. | ||
15 | |||
16 | ===================== | ||
17 | |||
18 | File: OpenGL_Internal.h | ||
19 | Abstract: This file is included for support purposes and isn't necessary for | ||
20 | understanding this sample. | ||
21 | |||
22 | Version: 1.0 | ||
23 | |||
24 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. | ||
25 | ("Apple") in consideration of your agreement to the following terms, and your | ||
26 | use, installation, modification or redistribution of this Apple software | ||
27 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
28 | please do not use, install, modify or redistribute this Apple software. | ||
29 | |||
30 | In consideration of your agreement to abide by the following terms, and subject | ||
31 | to these terms, Apple grants you a personal, non-exclusive license, under | ||
32 | Apple's copyrights in this original Apple software (the "Apple Software"), to | ||
33 | use, reproduce, modify and redistribute the Apple Software, with or without | ||
34 | modifications, in source and/or binary forms; provided that if you redistribute | ||
35 | the Apple Software in its entirety and without modifications, you must retain | ||
36 | this notice and the following text and disclaimers in all such redistributions | ||
37 | of the Apple Software. | ||
38 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used | ||
39 | to endorse or promote products derived from the Apple Software without specific | ||
40 | prior written permission from Apple. Except as expressly stated in this notice, | ||
41 | no other rights or licenses, express or implied, are granted by Apple herein, | ||
42 | including but not limited to any patent rights that may be infringed by your | ||
43 | derivative works or by other works in which the Apple Software may be | ||
44 | incorporated. | ||
45 | |||
46 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
47 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
48 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
49 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
50 | COMBINATION WITH YOUR PRODUCTS. | ||
51 | |||
52 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
53 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
54 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
55 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR | ||
56 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF | ||
57 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF | ||
58 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
59 | |||
60 | Copyright (C) 2008 Apple Inc. All Rights Reserved. | ||
61 | |||
62 | */ | ||
63 | |||
64 | /* Generic error reporting */ | ||
65 | #define REPORT_ERROR(__FORMAT__, ...) printf("%s: %s\n", __FUNCTION__, [[NSString stringWithFormat:__FORMAT__, __VA_ARGS__] UTF8String]) | ||
66 | |||
67 | /* EAGL and GL functions calling wrappers that log on error */ | ||
68 | #define CALL_EAGL_FUNCTION(__FUNC__, ...) ({ EAGLError __error = __FUNC__( __VA_ARGS__ ); if(__error != kEAGLErrorSuccess) printf("%s() called from %s returned error %i\n", #__FUNC__, __FUNCTION__, __error); (__error ? NO : YES); }) | ||
69 | //#define CHECK_GL_ERROR() ({ GLenum __error = glGetError(); if(__error) printf("OpenGL error 0x%04X in %s\n", __error, __FUNCTION__); (__error ? NO : YES); }) | ||
70 | #define CHECK_GL_ERROR() ({ GLenum __error = glGetError(); if(__error) printf("OpenGL error 0x%04X in %s\n", __error, __FUNCTION__); }) | ||
71 | |||
72 | /* Optional delegate methods support */ | ||
73 | #ifndef __DELEGATE_IVAR__ | ||
74 | #define __DELEGATE_IVAR__ _delegate | ||
75 | #endif | ||
76 | #ifndef __DELEGATE_METHODS_IVAR__ | ||
77 | #define __DELEGATE_METHODS_IVAR__ _delegateMethods | ||
78 | #endif | ||
79 | #define TEST_DELEGATE_METHOD_BIT(__BIT__) (self->__DELEGATE_METHODS_IVAR__ & (1 << __BIT__)) | ||
80 | #define SET_DELEGATE_METHOD_BIT(__BIT__, __NAME__) { if([self->__DELEGATE_IVAR__ respondsToSelector:@selector(__NAME__)]) self->__DELEGATE_METHODS_IVAR__ |= (1 << __BIT__); else self->__DELEGATE_METHODS_IVAR__ &= ~(1 << __BIT__); } | ||
diff --git a/libs/cocos2d/Support/TGAlib.h b/libs/cocos2d/Support/TGAlib.h new file mode 100755 index 0000000..247084e --- /dev/null +++ b/libs/cocos2d/Support/TGAlib.h | |||
@@ -0,0 +1,55 @@ | |||
1 | // | ||
2 | // TGA lib for cocos2d-iphone | ||
3 | // | ||
4 | // sources from: http://www.lighthouse3d.com/opengl/terrain/index.php3?tgasource | ||
5 | // | ||
6 | |||
7 | //#ifndef TGA_LIB | ||
8 | //#define TGA_LIB | ||
9 | |||
10 | /** | ||
11 | @file | ||
12 | TGA image support | ||
13 | */ | ||
14 | |||
15 | enum { | ||
16 | TGA_OK, | ||
17 | TGA_ERROR_FILE_OPEN, | ||
18 | TGA_ERROR_READING_FILE, | ||
19 | TGA_ERROR_INDEXED_COLOR, | ||
20 | TGA_ERROR_MEMORY, | ||
21 | TGA_ERROR_COMPRESSED_FILE, | ||
22 | }; | ||
23 | |||
24 | /** TGA format */ | ||
25 | typedef struct sImageTGA { | ||
26 | int status; | ||
27 | unsigned char type, pixelDepth; | ||
28 | |||
29 | /** map width */ | ||
30 | short int width; | ||
31 | |||
32 | /** map height */ | ||
33 | short int height; | ||
34 | |||
35 | /** raw data */ | ||
36 | unsigned char *imageData; | ||
37 | int flipped; | ||
38 | } tImageTGA; | ||
39 | |||
40 | /// load the image header fields. We only keep those that matter! | ||
41 | void tgaLoadHeader(FILE *file, tImageTGA *info); | ||
42 | |||
43 | /// loads the image pixels. You shouldn't call this function directly | ||
44 | void tgaLoadImageData(FILE *file, tImageTGA *info); | ||
45 | |||
46 | /// this is the function to call when we want to load an image | ||
47 | tImageTGA * tgaLoad(const char *filename); | ||
48 | |||
49 | // /converts RGB to greyscale | ||
50 | void tgaRGBtogreyscale(tImageTGA *info); | ||
51 | |||
52 | /// releases the memory used for the image | ||
53 | void tgaDestroy(tImageTGA *info); | ||
54 | |||
55 | //#endif // TGA_LIB | ||
diff --git a/libs/cocos2d/Support/TGAlib.m b/libs/cocos2d/Support/TGAlib.m new file mode 100755 index 0000000..11303b4 --- /dev/null +++ b/libs/cocos2d/Support/TGAlib.m | |||
@@ -0,0 +1,274 @@ | |||
1 | // | ||
2 | // TGA lib for cocos2d-iphone | ||
3 | // | ||
4 | // sources from: http://www.lighthouse3d.com/opengl/terrain/index.php3?tgasource | ||
5 | // | ||
6 | // TGA RLE compression support by Ernesto Corvi | ||
7 | |||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | |||
12 | #import "TGAlib.h" | ||
13 | |||
14 | void tgaLoadRLEImageData(FILE *file, tImageTGA *info); | ||
15 | void tgaFlipImage( tImageTGA *info ); | ||
16 | |||
17 | // load the image header fields. We only keep those that matter! | ||
18 | void tgaLoadHeader(FILE *file, tImageTGA *info) { | ||
19 | unsigned char cGarbage; | ||
20 | short int iGarbage; | ||
21 | |||
22 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
23 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
24 | |||
25 | // type must be 2 or 3 | ||
26 | fread(&info->type, sizeof(unsigned char), 1, file); | ||
27 | |||
28 | fread(&iGarbage, sizeof(short int), 1, file); | ||
29 | fread(&iGarbage, sizeof(short int), 1, file); | ||
30 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
31 | fread(&iGarbage, sizeof(short int), 1, file); | ||
32 | fread(&iGarbage, sizeof(short int), 1, file); | ||
33 | |||
34 | fread(&info->width, sizeof(short int), 1, file); | ||
35 | fread(&info->height, sizeof(short int), 1, file); | ||
36 | fread(&info->pixelDepth, sizeof(unsigned char), 1, file); | ||
37 | |||
38 | fread(&cGarbage, sizeof(unsigned char), 1, file); | ||
39 | |||
40 | info->flipped = 0; | ||
41 | if ( cGarbage & 0x20 ) info->flipped = 1; | ||
42 | } | ||
43 | |||
44 | // loads the image pixels. You shouldn't call this function directly | ||
45 | void tgaLoadImageData(FILE *file, tImageTGA *info) { | ||
46 | |||
47 | int mode,total,i; | ||
48 | unsigned char aux; | ||
49 | |||
50 | // mode equal the number of components for each pixel | ||
51 | mode = info->pixelDepth / 8; | ||
52 | // total is the number of unsigned chars we'll have to read | ||
53 | total = info->height * info->width * mode; | ||
54 | |||
55 | fread(info->imageData,sizeof(unsigned char),total,file); | ||
56 | |||
57 | // mode=3 or 4 implies that the image is RGB(A). However TGA | ||
58 | // stores it as BGR(A) so we'll have to swap R and B. | ||
59 | if (mode >= 3) | ||
60 | for (i=0; i < total; i+= mode) { | ||
61 | aux = info->imageData[i]; | ||
62 | info->imageData[i] = info->imageData[i+2]; | ||
63 | info->imageData[i+2] = aux; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | // loads the RLE encoded image pixels. You shouldn't call this function directly | ||
68 | void tgaLoadRLEImageData(FILE *file, tImageTGA *info) | ||
69 | { | ||
70 | unsigned int mode,total,i, index = 0; | ||
71 | unsigned char aux[4], runlength = 0; | ||
72 | unsigned int skip = 0, flag = 0; | ||
73 | |||
74 | // mode equal the number of components for each pixel | ||
75 | mode = info->pixelDepth / 8; | ||
76 | // total is the number of unsigned chars we'll have to read | ||
77 | total = info->height * info->width; | ||
78 | |||
79 | for( i = 0; i < total; i++ ) | ||
80 | { | ||
81 | // if we have a run length pending, run it | ||
82 | if ( runlength != 0 ) | ||
83 | { | ||
84 | // we do, update the run length count | ||
85 | runlength--; | ||
86 | skip = (flag != 0); | ||
87 | } | ||
88 | else | ||
89 | { | ||
90 | // otherwise, read in the run length token | ||
91 | if ( fread(&runlength,sizeof(unsigned char),1,file) != 1 ) | ||
92 | return; | ||
93 | |||
94 | // see if it's a RLE encoded sequence | ||
95 | flag = runlength & 0x80; | ||
96 | if ( flag ) runlength -= 128; | ||
97 | skip = 0; | ||
98 | } | ||
99 | |||
100 | // do we need to skip reading this pixel? | ||
101 | if ( !skip ) | ||
102 | { | ||
103 | // no, read in the pixel data | ||
104 | if ( fread(aux,sizeof(unsigned char),mode,file) != mode ) | ||
105 | return; | ||
106 | |||
107 | // mode=3 or 4 implies that the image is RGB(A). However TGA | ||
108 | // stores it as BGR(A) so we'll have to swap R and B. | ||
109 | if ( mode >= 3 ) | ||
110 | { | ||
111 | unsigned char tmp; | ||
112 | |||
113 | tmp = aux[0]; | ||
114 | aux[0] = aux[2]; | ||
115 | aux[2] = tmp; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | // add the pixel to our image | ||
120 | memcpy(&info->imageData[index], aux, mode); | ||
121 | index += mode; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | void tgaFlipImage( tImageTGA *info ) | ||
126 | { | ||
127 | // mode equal the number of components for each pixel | ||
128 | int mode = info->pixelDepth / 8; | ||
129 | int rowbytes = info->width*mode; | ||
130 | unsigned char *row = (unsigned char *)malloc(rowbytes); | ||
131 | int y; | ||
132 | |||
133 | if (row == NULL) return; | ||
134 | |||
135 | for( y = 0; y < (info->height/2); y++ ) | ||
136 | { | ||
137 | memcpy(row, &info->imageData[y*rowbytes],rowbytes); | ||
138 | memcpy(&info->imageData[y*rowbytes], &info->imageData[(info->height-(y+1))*rowbytes], rowbytes); | ||
139 | memcpy(&info->imageData[(info->height-(y+1))*rowbytes], row, rowbytes); | ||
140 | } | ||
141 | |||
142 | free(row); | ||
143 | info->flipped = 0; | ||
144 | } | ||
145 | |||
146 | // this is the function to call when we want to load an image | ||
147 | tImageTGA * tgaLoad(const char *filename) { | ||
148 | |||
149 | FILE *file; | ||
150 | tImageTGA *info; | ||
151 | int mode,total; | ||
152 | |||
153 | // allocate memory for the info struct and check! | ||
154 | info = (tImageTGA *)malloc(sizeof(tImageTGA)); | ||
155 | if (info == NULL) | ||
156 | return(NULL); | ||
157 | |||
158 | |||
159 | // open the file for reading (binary mode) | ||
160 | file = fopen(filename, "rb"); | ||
161 | if (file == NULL) { | ||
162 | info->status = TGA_ERROR_FILE_OPEN; | ||
163 | return(info); | ||
164 | } | ||
165 | |||
166 | // load the header | ||
167 | tgaLoadHeader(file,info); | ||
168 | |||
169 | // check for errors when loading the header | ||
170 | if (ferror(file)) { | ||
171 | info->status = TGA_ERROR_READING_FILE; | ||
172 | fclose(file); | ||
173 | return(info); | ||
174 | } | ||
175 | |||
176 | // check if the image is color indexed | ||
177 | if (info->type == 1) { | ||
178 | info->status = TGA_ERROR_INDEXED_COLOR; | ||
179 | fclose(file); | ||
180 | return(info); | ||
181 | } | ||
182 | // check for other types (compressed images) | ||
183 | if ((info->type != 2) && (info->type !=3) && (info->type !=10) ) { | ||
184 | info->status = TGA_ERROR_COMPRESSED_FILE; | ||
185 | fclose(file); | ||
186 | return(info); | ||
187 | } | ||
188 | |||
189 | // mode equals the number of image components | ||
190 | mode = info->pixelDepth / 8; | ||
191 | // total is the number of unsigned chars to read | ||
192 | total = info->height * info->width * mode; | ||
193 | // allocate memory for image pixels | ||
194 | info->imageData = (unsigned char *)malloc(sizeof(unsigned char) * | ||
195 | total); | ||
196 | |||
197 | // check to make sure we have the memory required | ||
198 | if (info->imageData == NULL) { | ||
199 | info->status = TGA_ERROR_MEMORY; | ||
200 | fclose(file); | ||
201 | return(info); | ||
202 | } | ||
203 | // finally load the image pixels | ||
204 | if ( info->type == 10 ) | ||
205 | tgaLoadRLEImageData(file, info); | ||
206 | else | ||
207 | tgaLoadImageData(file,info); | ||
208 | |||
209 | // check for errors when reading the pixels | ||
210 | if (ferror(file)) { | ||
211 | info->status = TGA_ERROR_READING_FILE; | ||
212 | fclose(file); | ||
213 | return(info); | ||
214 | } | ||
215 | fclose(file); | ||
216 | info->status = TGA_OK; | ||
217 | |||
218 | if ( info->flipped ) | ||
219 | { | ||
220 | tgaFlipImage( info ); | ||
221 | if ( info->flipped ) info->status = TGA_ERROR_MEMORY; | ||
222 | } | ||
223 | |||
224 | return(info); | ||
225 | } | ||
226 | |||
227 | // converts RGB to greyscale | ||
228 | void tgaRGBtogreyscale(tImageTGA *info) { | ||
229 | |||
230 | int mode,i,j; | ||
231 | |||
232 | unsigned char *newImageData; | ||
233 | |||
234 | // if the image is already greyscale do nothing | ||
235 | if (info->pixelDepth == 8) | ||
236 | return; | ||
237 | |||
238 | // compute the number of actual components | ||
239 | mode = info->pixelDepth / 8; | ||
240 | |||
241 | // allocate an array for the new image data | ||
242 | newImageData = (unsigned char *)malloc(sizeof(unsigned char) * | ||
243 | info->height * info->width); | ||
244 | if (newImageData == NULL) { | ||
245 | return; | ||
246 | } | ||
247 | |||
248 | // convert pixels: greyscale = o.30 * R + 0.59 * G + 0.11 * B | ||
249 | for (i = 0,j = 0; j < info->width * info->height; i +=mode, j++) | ||
250 | newImageData[j] = | ||
251 | (unsigned char)(0.30 * info->imageData[i] + | ||
252 | 0.59 * info->imageData[i+1] + | ||
253 | 0.11 * info->imageData[i+2]); | ||
254 | |||
255 | |||
256 | //free old image data | ||
257 | free(info->imageData); | ||
258 | |||
259 | // reassign pixelDepth and type according to the new image type | ||
260 | info->pixelDepth = 8; | ||
261 | info->type = 3; | ||
262 | // reassing imageData to the new array. | ||
263 | info->imageData = newImageData; | ||
264 | } | ||
265 | |||
266 | // releases the memory used for the image | ||
267 | void tgaDestroy(tImageTGA *info) { | ||
268 | |||
269 | if (info != NULL) { | ||
270 | if (info->imageData != NULL) | ||
271 | free(info->imageData); | ||
272 | free(info); | ||
273 | } | ||
274 | } | ||
diff --git a/libs/cocos2d/Support/TransformUtils.h b/libs/cocos2d/Support/TransformUtils.h new file mode 100755 index 0000000..49fde35 --- /dev/null +++ b/libs/cocos2d/Support/TransformUtils.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #import <Availability.h> | ||
27 | |||
28 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
29 | #import <UIKit/UIKit.h> | ||
30 | #import <OpenGLES/ES1/gl.h> | ||
31 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
32 | #import <OpenGL/gl.h> | ||
33 | #import <Foundation/Foundation.h> | ||
34 | #endif | ||
35 | |||
36 | void CGAffineToGL(const CGAffineTransform *t, GLfloat *m); | ||
37 | void GLToCGAffine(const GLfloat *m, CGAffineTransform *t); | ||
diff --git a/libs/cocos2d/Support/TransformUtils.m b/libs/cocos2d/Support/TransformUtils.m new file mode 100755 index 0000000..9caecf0 --- /dev/null +++ b/libs/cocos2d/Support/TransformUtils.m | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | * Copyright (c) 2009 Valentin Milea | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #import "TransformUtils.h" | ||
28 | |||
29 | void CGAffineToGL(const CGAffineTransform *t, GLfloat *m) | ||
30 | { | ||
31 | // | m[0] m[4] m[8] m[12] | | m11 m21 m31 m41 | | a c 0 tx | | ||
32 | // | m[1] m[5] m[9] m[13] | | m12 m22 m32 m42 | | b d 0 ty | | ||
33 | // | m[2] m[6] m[10] m[14] | <=> | m13 m23 m33 m43 | <=> | 0 0 1 0 | | ||
34 | // | m[3] m[7] m[11] m[15] | | m14 m24 m34 m44 | | 0 0 0 1 | | ||
35 | |||
36 | m[2] = m[3] = m[6] = m[7] = m[8] = m[9] = m[11] = m[14] = 0.0f; | ||
37 | m[10] = m[15] = 1.0f; | ||
38 | m[0] = t->a; m[4] = t->c; m[12] = t->tx; | ||
39 | m[1] = t->b; m[5] = t->d; m[13] = t->ty; | ||
40 | } | ||
41 | |||
42 | void GLToCGAffine(const GLfloat *m, CGAffineTransform *t) | ||
43 | { | ||
44 | t->a = m[0]; t->c = m[4]; t->tx = m[12]; | ||
45 | t->b = m[1]; t->d = m[5]; t->ty = m[13]; | ||
46 | } | ||
diff --git a/libs/cocos2d/Support/ZipUtils.h b/libs/cocos2d/Support/ZipUtils.h new file mode 100755 index 0000000..363f911 --- /dev/null +++ b/libs/cocos2d/Support/ZipUtils.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* cocos2d for iPhone | ||
2 | * | ||
3 | * http://www.cocos2d-iphone.org | ||
4 | * | ||
5 | * | ||
6 | * inflateMemory_ based on zlib example code | ||
7 | * http://www.zlib.net | ||
8 | * | ||
9 | * Some ideas were taken from: | ||
10 | * http://themanaworld.org/ | ||
11 | * from the mapreader.cpp file | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef __CC_ZIP_UTILS_H | ||
16 | #define __CC_ZIP_UTILS_H | ||
17 | |||
18 | #import <stdint.h> | ||
19 | |||
20 | #ifdef __cplusplus | ||
21 | extern "C" { | ||
22 | #endif | ||
23 | |||
24 | /* XXX: pragma pack ??? */ | ||
25 | /** @struct CCZHeader | ||
26 | */ | ||
27 | struct CCZHeader { | ||
28 | uint8_t sig[4]; // signature. Should be 'CCZ!' 4 bytes | ||
29 | uint16_t compression_type; // should 0 | ||
30 | uint16_t version; // should be 2 (although version type==1 is also supported) | ||
31 | uint32_t reserved; // Reserverd for users. | ||
32 | uint32_t len; // size of the uncompressed file | ||
33 | }; | ||
34 | |||
35 | enum { | ||
36 | CCZ_COMPRESSION_ZLIB, // zlib format. | ||
37 | CCZ_COMPRESSION_BZIP2, // bzip2 format (not supported yet) | ||
38 | CCZ_COMPRESSION_GZIP, // gzip format (not supported yet) | ||
39 | CCZ_COMPRESSION_NONE, // plain (not supported yet) | ||
40 | }; | ||
41 | |||
42 | /** @file | ||
43 | * Zip helper functions | ||
44 | */ | ||
45 | |||
46 | /** | ||
47 | * Inflates either zlib or gzip deflated memory. The inflated memory is | ||
48 | * expected to be freed by the caller. | ||
49 | * | ||
50 | * It will allocate 256k for the destination buffer. If it is not enought it will multiply the previous buffer size per 2, until there is enough memory. | ||
51 | * @returns the length of the deflated buffer | ||
52 | * | ||
53 | @since v0.8.1 | ||
54 | */ | ||
55 | int ccInflateMemory(unsigned char *in, unsigned int inLength, unsigned char **out); | ||
56 | |||
57 | /** | ||
58 | * Inflates either zlib or gzip deflated memory. The inflated memory is | ||
59 | * expected to be freed by the caller. | ||
60 | * | ||
61 | * outLenghtHint is assumed to be the needed room to allocate the inflated buffer. | ||
62 | * | ||
63 | * @returns the length of the deflated buffer | ||
64 | * | ||
65 | @since v1.0.0 | ||
66 | */ | ||
67 | int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int outLenghtHint ); | ||
68 | |||
69 | |||
70 | /** inflates a GZip file into memory | ||
71 | * | ||
72 | * @returns the length of the deflated buffer | ||
73 | * | ||
74 | * @since v0.99.5 | ||
75 | */ | ||
76 | int ccInflateGZipFile(const char *filename, unsigned char **out); | ||
77 | |||
78 | /** inflates a CCZ file into memory | ||
79 | * | ||
80 | * @returns the length of the deflated buffer | ||
81 | * | ||
82 | * @since v0.99.5 | ||
83 | */ | ||
84 | int ccInflateCCZFile(const char *filename, unsigned char **out); | ||
85 | |||
86 | |||
87 | #ifdef __cplusplus | ||
88 | } | ||
89 | #endif | ||
90 | |||
91 | #endif // __CC_ZIP_UTILS_H | ||
diff --git a/libs/cocos2d/Support/ZipUtils.m b/libs/cocos2d/Support/ZipUtils.m new file mode 100755 index 0000000..ccd8bbc --- /dev/null +++ b/libs/cocos2d/Support/ZipUtils.m | |||
@@ -0,0 +1,251 @@ | |||
1 | /* cocos2d for iPhone | ||
2 | * | ||
3 | * http://www.cocos2d-iphone.org | ||
4 | * | ||
5 | * | ||
6 | * Inflates either zlib or gzip deflated memory. The inflated memory is | ||
7 | * expected to be freed by the caller. | ||
8 | * | ||
9 | * inflateMemory_ based on zlib example code | ||
10 | * http://www.zlib.net | ||
11 | * | ||
12 | * Some ideas were taken from: | ||
13 | * http://themanaworld.org/ | ||
14 | * from the mapreader.cpp file | ||
15 | */ | ||
16 | |||
17 | #import <Availability.h> | ||
18 | |||
19 | #import <zlib.h> | ||
20 | #import <stdlib.h> | ||
21 | #import <assert.h> | ||
22 | #import <stdio.h> | ||
23 | |||
24 | #import "ZipUtils.h" | ||
25 | #import "CCFileUtils.h" | ||
26 | #import "../ccMacros.h" | ||
27 | |||
28 | // memory in iPhone is precious | ||
29 | // Should buffer factor be 1.5 instead of 2 ? | ||
30 | #define BUFFER_INC_FACTOR (2) | ||
31 | |||
32 | static int inflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int *outLength, unsigned int outLenghtHint ) | ||
33 | { | ||
34 | /* ret value */ | ||
35 | int err = Z_OK; | ||
36 | |||
37 | int bufferSize = outLenghtHint; | ||
38 | *out = (unsigned char*) malloc(bufferSize); | ||
39 | |||
40 | z_stream d_stream; /* decompression stream */ | ||
41 | d_stream.zalloc = (alloc_func)0; | ||
42 | d_stream.zfree = (free_func)0; | ||
43 | d_stream.opaque = (voidpf)0; | ||
44 | |||
45 | d_stream.next_in = in; | ||
46 | d_stream.avail_in = inLength; | ||
47 | d_stream.next_out = *out; | ||
48 | d_stream.avail_out = bufferSize; | ||
49 | |||
50 | /* window size to hold 256k */ | ||
51 | if( (err = inflateInit2(&d_stream, 15 + 32)) != Z_OK ) | ||
52 | return err; | ||
53 | |||
54 | for (;;) { | ||
55 | err = inflate(&d_stream, Z_NO_FLUSH); | ||
56 | |||
57 | if (err == Z_STREAM_END) | ||
58 | break; | ||
59 | |||
60 | switch (err) { | ||
61 | case Z_NEED_DICT: | ||
62 | err = Z_DATA_ERROR; | ||
63 | case Z_DATA_ERROR: | ||
64 | case Z_MEM_ERROR: | ||
65 | inflateEnd(&d_stream); | ||
66 | return err; | ||
67 | } | ||
68 | |||
69 | // not enough memory ? | ||
70 | if (err != Z_STREAM_END) { | ||
71 | |||
72 | unsigned char *tmp = realloc(*out, bufferSize * BUFFER_INC_FACTOR); | ||
73 | |||
74 | /* not enough memory, ouch */ | ||
75 | if (! tmp ) { | ||
76 | CCLOG(@"cocos2d: ZipUtils: realloc failed"); | ||
77 | inflateEnd(&d_stream); | ||
78 | return Z_MEM_ERROR; | ||
79 | } | ||
80 | /* only assign to *out if tmp is valid. it's not guaranteed that realloc will reuse the memory */ | ||
81 | *out = tmp; | ||
82 | |||
83 | d_stream.next_out = *out + bufferSize; | ||
84 | d_stream.avail_out = bufferSize; | ||
85 | bufferSize *= BUFFER_INC_FACTOR; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | |||
90 | *outLength = bufferSize - d_stream.avail_out; | ||
91 | err = inflateEnd(&d_stream); | ||
92 | return err; | ||
93 | } | ||
94 | |||
95 | int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int outLengthHint ) | ||
96 | { | ||
97 | unsigned int outLength = 0; | ||
98 | int err = inflateMemoryWithHint(in, inLength, out, &outLength, outLengthHint ); | ||
99 | |||
100 | if (err != Z_OK || *out == NULL) { | ||
101 | if (err == Z_MEM_ERROR) | ||
102 | CCLOG(@"cocos2d: ZipUtils: Out of memory while decompressing map data!"); | ||
103 | |||
104 | else if (err == Z_VERSION_ERROR) | ||
105 | CCLOG(@"cocos2d: ZipUtils: Incompatible zlib version!"); | ||
106 | |||
107 | else if (err == Z_DATA_ERROR) | ||
108 | CCLOG(@"cocos2d: ZipUtils: Incorrect zlib compressed data!"); | ||
109 | |||
110 | else | ||
111 | CCLOG(@"cocos2d: ZipUtils: Unknown error while decompressing map data!"); | ||
112 | |||
113 | free(*out); | ||
114 | *out = NULL; | ||
115 | outLength = 0; | ||
116 | } | ||
117 | |||
118 | return outLength; | ||
119 | } | ||
120 | |||
121 | int ccInflateMemory(unsigned char *in, unsigned int inLength, unsigned char **out) | ||
122 | { | ||
123 | // 256k for hint | ||
124 | return ccInflateMemoryWithHint(in, inLength, out, 256 * 1024 ); | ||
125 | } | ||
126 | |||
127 | int ccInflateGZipFile(const char *path, unsigned char **out) | ||
128 | { | ||
129 | int len; | ||
130 | unsigned int offset = 0; | ||
131 | |||
132 | NSCAssert( out, @"ccInflateGZipFile: invalid 'out' parameter"); | ||
133 | NSCAssert( &*out, @"ccInflateGZipFile: invalid 'out' parameter"); | ||
134 | |||
135 | gzFile inFile = gzopen(path, "rb"); | ||
136 | if( inFile == NULL ) { | ||
137 | CCLOG(@"cocos2d: ZipUtils: error open gzip file: %s", path); | ||
138 | return -1; | ||
139 | } | ||
140 | |||
141 | /* 512k initial decompress buffer */ | ||
142 | int bufferSize = 512 * 1024; | ||
143 | unsigned int totalBufferSize = bufferSize; | ||
144 | |||
145 | *out = malloc( bufferSize ); | ||
146 | if( ! out ) { | ||
147 | CCLOG(@"cocos2d: ZipUtils: out of memory"); | ||
148 | return -1; | ||
149 | } | ||
150 | |||
151 | for (;;) { | ||
152 | len = gzread(inFile, *out + offset, bufferSize); | ||
153 | if (len < 0) { | ||
154 | CCLOG(@"cocos2d: ZipUtils: error in gzread"); | ||
155 | free( *out ); | ||
156 | *out = NULL; | ||
157 | return -1; | ||
158 | } | ||
159 | if (len == 0) | ||
160 | break; | ||
161 | |||
162 | offset += len; | ||
163 | |||
164 | // finish reading the file | ||
165 | if( len < bufferSize ) | ||
166 | break; | ||
167 | |||
168 | bufferSize *= BUFFER_INC_FACTOR; | ||
169 | totalBufferSize += bufferSize; | ||
170 | unsigned char *tmp = realloc(*out, totalBufferSize ); | ||
171 | |||
172 | if( ! tmp ) { | ||
173 | CCLOG(@"cocos2d: ZipUtils: out of memory"); | ||
174 | free( *out ); | ||
175 | *out = NULL; | ||
176 | return -1; | ||
177 | } | ||
178 | |||
179 | *out = tmp; | ||
180 | } | ||
181 | |||
182 | if (gzclose(inFile) != Z_OK) | ||
183 | CCLOG(@"cocos2d: ZipUtils: gzclose failed"); | ||
184 | |||
185 | return offset; | ||
186 | } | ||
187 | |||
188 | int ccInflateCCZFile(const char *path, unsigned char **out) | ||
189 | { | ||
190 | NSCAssert( out, @"ccInflateCCZFile: invalid 'out' parameter"); | ||
191 | NSCAssert( &*out, @"ccInflateCCZFile: invalid 'out' parameter"); | ||
192 | |||
193 | // load file into memory | ||
194 | unsigned char *compressed = NULL; | ||
195 | NSInteger fileLen = ccLoadFileIntoMemory( path, &compressed ); | ||
196 | if( fileLen < 0 ) { | ||
197 | CCLOG(@"cocos2d: Error loading CCZ compressed file"); | ||
198 | } | ||
199 | |||
200 | struct CCZHeader *header = (struct CCZHeader*) compressed; | ||
201 | |||
202 | // verify header | ||
203 | if( header->sig[0] != 'C' || header->sig[1] != 'C' || header->sig[2] != 'Z' || header->sig[3] != '!' ) { | ||
204 | CCLOG(@"cocos2d: Invalid CCZ file"); | ||
205 | free(compressed); | ||
206 | return -1; | ||
207 | } | ||
208 | |||
209 | // verify header version | ||
210 | uint16_t version = CFSwapInt16BigToHost( header->version ); | ||
211 | if( version > 2 ) { | ||
212 | CCLOG(@"cocos2d: Unsupported CCZ header format"); | ||
213 | free(compressed); | ||
214 | return -1; | ||
215 | } | ||
216 | |||
217 | // verify compression format | ||
218 | if( CFSwapInt16BigToHost(header->compression_type) != CCZ_COMPRESSION_ZLIB ) { | ||
219 | CCLOG(@"cocos2d: CCZ Unsupported compression method"); | ||
220 | free(compressed); | ||
221 | return -1; | ||
222 | } | ||
223 | |||
224 | uint32_t len = CFSwapInt32BigToHost( header->len ); | ||
225 | |||
226 | *out = malloc( len ); | ||
227 | if(! *out ) | ||
228 | { | ||
229 | CCLOG(@"cocos2d: CCZ: Failed to allocate memory for texture"); | ||
230 | free(compressed); | ||
231 | return -1; | ||
232 | } | ||
233 | |||
234 | |||
235 | uLongf destlen = len; | ||
236 | uLongf source = (uLongf) compressed + sizeof(*header); | ||
237 | int ret = uncompress(*out, &destlen, (Bytef*)source, fileLen - sizeof(*header) ); | ||
238 | |||
239 | free( compressed ); | ||
240 | |||
241 | if( ret != Z_OK ) | ||
242 | { | ||
243 | CCLOG(@"cocos2d: CCZ: Failed to uncompress data"); | ||
244 | free( *out ); | ||
245 | *out = NULL; | ||
246 | return -1; | ||
247 | } | ||
248 | |||
249 | |||
250 | return len; | ||
251 | } | ||
diff --git a/libs/cocos2d/Support/base64.c b/libs/cocos2d/Support/base64.c new file mode 100755 index 0000000..9aa52a6 --- /dev/null +++ b/libs/cocos2d/Support/base64.c | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | public domain BASE64 code | ||
3 | |||
4 | modified for cocos2d-iphone: http://www.cocos2d-iphone.org | ||
5 | */ | ||
6 | |||
7 | #include <stdio.h> | ||
8 | #include <stdlib.h> | ||
9 | |||
10 | #include "base64.h" | ||
11 | |||
12 | unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
13 | |||
14 | int _base64Decode( unsigned char *input, unsigned int input_len, unsigned char *output, unsigned int *output_len ); | ||
15 | |||
16 | int _base64Decode( unsigned char *input, unsigned int input_len, unsigned char *output, unsigned int *output_len ) | ||
17 | { | ||
18 | static char inalphabet[256], decoder[256]; | ||
19 | int i, bits, c, char_count, errors = 0; | ||
20 | unsigned int input_idx = 0; | ||
21 | unsigned int output_idx = 0; | ||
22 | |||
23 | for (i = (sizeof alphabet) - 1; i >= 0 ; i--) { | ||
24 | inalphabet[alphabet[i]] = 1; | ||
25 | decoder[alphabet[i]] = i; | ||
26 | } | ||
27 | |||
28 | char_count = 0; | ||
29 | bits = 0; | ||
30 | for( input_idx=0; input_idx < input_len ; input_idx++ ) { | ||
31 | c = input[ input_idx ]; | ||
32 | if (c == '=') | ||
33 | break; | ||
34 | if (c > 255 || ! inalphabet[c]) | ||
35 | continue; | ||
36 | bits += decoder[c]; | ||
37 | char_count++; | ||
38 | if (char_count == 4) { | ||
39 | output[ output_idx++ ] = (bits >> 16); | ||
40 | output[ output_idx++ ] = ((bits >> 8) & 0xff); | ||
41 | output[ output_idx++ ] = ( bits & 0xff); | ||
42 | bits = 0; | ||
43 | char_count = 0; | ||
44 | } else { | ||
45 | bits <<= 6; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | if( c == '=' ) { | ||
50 | switch (char_count) { | ||
51 | case 1: | ||
52 | fprintf(stderr, "base64Decode: encoding incomplete: at least 2 bits missing"); | ||
53 | errors++; | ||
54 | break; | ||
55 | case 2: | ||
56 | output[ output_idx++ ] = ( bits >> 10 ); | ||
57 | break; | ||
58 | case 3: | ||
59 | output[ output_idx++ ] = ( bits >> 16 ); | ||
60 | output[ output_idx++ ] = (( bits >> 8 ) & 0xff); | ||
61 | break; | ||
62 | } | ||
63 | } else if ( input_idx < input_len ) { | ||
64 | if (char_count) { | ||
65 | fprintf(stderr, "base64 encoding incomplete: at least %d bits truncated", | ||
66 | ((4 - char_count) * 6)); | ||
67 | errors++; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | *output_len = output_idx; | ||
72 | return errors; | ||
73 | } | ||
74 | |||
75 | int base64Decode(unsigned char *in, unsigned int inLength, unsigned char **out) | ||
76 | { | ||
77 | unsigned int outLength = 0; | ||
78 | |||
79 | //should be enough to store 6-bit buffers in 8-bit buffers | ||
80 | *out = malloc( inLength * 3.0f / 4.0f + 1 ); | ||
81 | if( *out ) { | ||
82 | int ret = _base64Decode(in, inLength, *out, &outLength); | ||
83 | |||
84 | if (ret > 0 ) | ||
85 | { | ||
86 | printf("Base64Utils: error decoding"); | ||
87 | free(*out); | ||
88 | *out = NULL; | ||
89 | outLength = 0; | ||
90 | } | ||
91 | } | ||
92 | return outLength; | ||
93 | } | ||
diff --git a/libs/cocos2d/Support/base64.h b/libs/cocos2d/Support/base64.h new file mode 100755 index 0000000..d30878e --- /dev/null +++ b/libs/cocos2d/Support/base64.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | public domain BASE64 code | ||
3 | |||
4 | modified for cocos2d-iphone: http://www.cocos2d-iphone.org | ||
5 | */ | ||
6 | |||
7 | #ifndef __CC_BASE64_DECODE_H | ||
8 | #define __CC_BASE64_DECODE_H | ||
9 | |||
10 | #ifdef __cplusplus | ||
11 | extern "C" { | ||
12 | #endif | ||
13 | |||
14 | |||
15 | /** @file | ||
16 | base64 helper functions | ||
17 | */ | ||
18 | |||
19 | /** | ||
20 | * Decodes a 64base encoded memory. The decoded memory is | ||
21 | * expected to be freed by the caller. | ||
22 | * | ||
23 | * @returns the length of the out buffer | ||
24 | * | ||
25 | @since v0.8.1 | ||
26 | */ | ||
27 | int base64Decode(unsigned char *in, unsigned int inLength, unsigned char **out); | ||
28 | |||
29 | #ifdef __cplusplus | ||
30 | } | ||
31 | #endif | ||
32 | |||
33 | #endif // __CC_BASE64_DECODE_H | ||
diff --git a/libs/cocos2d/Support/ccCArray.h b/libs/cocos2d/Support/ccCArray.h new file mode 100755 index 0000000..20d9633 --- /dev/null +++ b/libs/cocos2d/Support/ccCArray.h | |||
@@ -0,0 +1,447 @@ | |||
1 | /* Copyright (c) 2007 Scott Lembcke | ||
2 | * | ||
3 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | * of this software and associated documentation files (the "Software"), to deal | ||
5 | * in the Software without restriction, including without limitation the rights | ||
6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | * copies of the Software, and to permit persons to whom the Software is | ||
8 | * furnished to do so, subject to the following conditions: | ||
9 | * | ||
10 | * The above copyright notice and this permission notice shall be included in | ||
11 | * all copies or substantial portions of the Software. | ||
12 | * | ||
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
19 | * SOFTWARE. | ||
20 | */ | ||
21 | |||
22 | /** | ||
23 | @file | ||
24 | Based on Chipmunk cpArray. | ||
25 | ccArray is a faster alternative to NSMutableArray, it does pretty much the | ||
26 | same thing (stores NSObjects and retains/releases them appropriately). It's | ||
27 | faster because: | ||
28 | - it uses a plain C interface so it doesn't incur Objective-c messaging overhead | ||
29 | - it assumes you know what you're doing, so it doesn't spend time on safety checks | ||
30 | (index out of bounds, required capacity etc.) | ||
31 | - comparisons are done using pointer equality instead of isEqual | ||
32 | |||
33 | There are 2 kind of functions: | ||
34 | - ccArray functions that manipulates objective-c objects (retain and release are performanced) | ||
35 | - ccCArray functions that manipulates values like if they were standard C structures (no retain/release is performed) | ||
36 | */ | ||
37 | |||
38 | #ifndef CC_ARRAY_H | ||
39 | #define CC_ARRAY_H | ||
40 | |||
41 | #import <Foundation/Foundation.h> | ||
42 | |||
43 | #import <stdlib.h> | ||
44 | #import <string.h> | ||
45 | |||
46 | |||
47 | #pragma mark - | ||
48 | #pragma mark ccArray for Objects | ||
49 | |||
50 | // Easy integration | ||
51 | #define CCARRAYDATA_FOREACH(__array__, __object__) \ | ||
52 | __object__=__array__->arr[0]; for(NSUInteger i=0, num=__array__->num; i<num; i++, __object__=__array__->arr[i]) \ | ||
53 | |||
54 | |||
55 | typedef struct ccArray { | ||
56 | NSUInteger num, max; | ||
57 | id *arr; | ||
58 | } ccArray; | ||
59 | |||
60 | /** Allocates and initializes a new array with specified capacity */ | ||
61 | static inline ccArray* ccArrayNew(NSUInteger capacity) { | ||
62 | if (capacity == 0) | ||
63 | capacity = 1; | ||
64 | |||
65 | ccArray *arr = (ccArray*)malloc( sizeof(ccArray) ); | ||
66 | arr->num = 0; | ||
67 | arr->arr = (id*) malloc( capacity * sizeof(id) ); | ||
68 | arr->max = capacity; | ||
69 | |||
70 | return arr; | ||
71 | } | ||
72 | |||
73 | static inline void ccArrayRemoveAllObjects(ccArray *arr); | ||
74 | |||
75 | /** Frees array after removing all remaining objects. Silently ignores nil arr. */ | ||
76 | static inline void ccArrayFree(ccArray *arr) | ||
77 | { | ||
78 | if( arr == nil ) return; | ||
79 | |||
80 | ccArrayRemoveAllObjects(arr); | ||
81 | |||
82 | free(arr->arr); | ||
83 | free(arr); | ||
84 | } | ||
85 | |||
86 | /** Doubles array capacity */ | ||
87 | static inline void ccArrayDoubleCapacity(ccArray *arr) | ||
88 | { | ||
89 | arr->max *= 2; | ||
90 | id *newArr = (id *)realloc( arr->arr, arr->max * sizeof(id) ); | ||
91 | // will fail when there's not enough memory | ||
92 | NSCAssert(newArr != NULL, @"ccArrayDoubleCapacity failed. Not enough memory"); | ||
93 | arr->arr = newArr; | ||
94 | } | ||
95 | |||
96 | /** Increases array capacity such that max >= num + extra. */ | ||
97 | static inline void ccArrayEnsureExtraCapacity(ccArray *arr, NSUInteger extra) | ||
98 | { | ||
99 | while (arr->max < arr->num + extra) | ||
100 | ccArrayDoubleCapacity(arr); | ||
101 | } | ||
102 | |||
103 | /** shrinks the array so the memory footprint corresponds with the number of items */ | ||
104 | static inline void ccArrayShrink(ccArray *arr) | ||
105 | { | ||
106 | NSUInteger newSize; | ||
107 | |||
108 | //only resize when necessary | ||
109 | if (arr->max > arr->num && !(arr->num==0 && arr->max==1)) | ||
110 | { | ||
111 | if (arr->num!=0) | ||
112 | { | ||
113 | newSize=arr->num; | ||
114 | arr->max=arr->num; | ||
115 | } | ||
116 | else | ||
117 | {//minimum capacity of 1, with 0 elements the array would be free'd by realloc | ||
118 | newSize=1; | ||
119 | arr->max=1; | ||
120 | } | ||
121 | |||
122 | arr->arr = (id*) realloc(arr->arr,newSize * sizeof(id) ); | ||
123 | NSCAssert(arr->arr!=NULL,@"could not reallocate the memory"); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | /** Returns index of first occurence of object, NSNotFound if object not found. */ | ||
128 | static inline NSUInteger ccArrayGetIndexOfObject(ccArray *arr, id object) | ||
129 | { | ||
130 | for( NSUInteger i = 0; i < arr->num; i++) | ||
131 | if( arr->arr[i] == object ) return i; | ||
132 | |||
133 | return NSNotFound; | ||
134 | } | ||
135 | |||
136 | /** Returns a Boolean value that indicates whether object is present in array. */ | ||
137 | static inline BOOL ccArrayContainsObject(ccArray *arr, id object) | ||
138 | { | ||
139 | return ccArrayGetIndexOfObject(arr, object) != NSNotFound; | ||
140 | } | ||
141 | |||
142 | /** Appends an object. Bahaviour undefined if array doesn't have enough capacity. */ | ||
143 | static inline void ccArrayAppendObject(ccArray *arr, id object) | ||
144 | { | ||
145 | arr->arr[arr->num] = [object retain]; | ||
146 | arr->num++; | ||
147 | } | ||
148 | |||
149 | /** Appends an object. Capacity of arr is increased if needed. */ | ||
150 | static inline void ccArrayAppendObjectWithResize(ccArray *arr, id object) | ||
151 | { | ||
152 | ccArrayEnsureExtraCapacity(arr, 1); | ||
153 | ccArrayAppendObject(arr, object); | ||
154 | } | ||
155 | |||
156 | /** Appends objects from plusArr to arr. Behaviour undefined if arr doesn't have | ||
157 | enough capacity. */ | ||
158 | static inline void ccArrayAppendArray(ccArray *arr, ccArray *plusArr) | ||
159 | { | ||
160 | for( NSUInteger i = 0; i < plusArr->num; i++) | ||
161 | ccArrayAppendObject(arr, plusArr->arr[i]); | ||
162 | } | ||
163 | |||
164 | /** Appends objects from plusArr to arr. Capacity of arr is increased if needed. */ | ||
165 | static inline void ccArrayAppendArrayWithResize(ccArray *arr, ccArray *plusArr) | ||
166 | { | ||
167 | ccArrayEnsureExtraCapacity(arr, plusArr->num); | ||
168 | ccArrayAppendArray(arr, plusArr); | ||
169 | } | ||
170 | |||
171 | /** Inserts an object at index */ | ||
172 | static inline void ccArrayInsertObjectAtIndex(ccArray *arr, id object, NSUInteger index) | ||
173 | { | ||
174 | NSCAssert(index<=arr->num, @"Invalid index. Out of bounds"); | ||
175 | |||
176 | ccArrayEnsureExtraCapacity(arr, 1); | ||
177 | |||
178 | NSUInteger remaining = arr->num - index; | ||
179 | if( remaining > 0) | ||
180 | memmove(&arr->arr[index+1], &arr->arr[index], sizeof(id) * remaining ); | ||
181 | |||
182 | arr->arr[index] = [object retain]; | ||
183 | arr->num++; | ||
184 | } | ||
185 | |||
186 | /** Swaps two objects */ | ||
187 | static inline void ccArraySwapObjectsAtIndexes(ccArray *arr, NSUInteger index1, NSUInteger index2) | ||
188 | { | ||
189 | NSCAssert(index1 < arr->num, @"(1) Invalid index. Out of bounds"); | ||
190 | NSCAssert(index2 < arr->num, @"(2) Invalid index. Out of bounds"); | ||
191 | |||
192 | id object1 = arr->arr[index1]; | ||
193 | |||
194 | arr->arr[index1] = arr->arr[index2]; | ||
195 | arr->arr[index2] = object1; | ||
196 | } | ||
197 | |||
198 | /** Removes all objects from arr */ | ||
199 | static inline void ccArrayRemoveAllObjects(ccArray *arr) | ||
200 | { | ||
201 | while( arr->num > 0 ) | ||
202 | [arr->arr[--arr->num] release]; | ||
203 | } | ||
204 | |||
205 | /** Removes object at specified index and pushes back all subsequent objects. | ||
206 | Behaviour undefined if index outside [0, num-1]. */ | ||
207 | static inline void ccArrayRemoveObjectAtIndex(ccArray *arr, NSUInteger index) | ||
208 | { | ||
209 | [arr->arr[index] release]; | ||
210 | arr->num--; | ||
211 | |||
212 | NSUInteger remaining = arr->num - index; | ||
213 | if(remaining>0) | ||
214 | memmove(&arr->arr[index], &arr->arr[index+1], remaining * sizeof(id)); | ||
215 | } | ||
216 | |||
217 | /** Removes object at specified index and fills the gap with the last object, | ||
218 | thereby avoiding the need to push back subsequent objects. | ||
219 | Behaviour undefined if index outside [0, num-1]. */ | ||
220 | static inline void ccArrayFastRemoveObjectAtIndex(ccArray *arr, NSUInteger index) | ||
221 | { | ||
222 | [arr->arr[index] release]; | ||
223 | NSUInteger last = --arr->num; | ||
224 | arr->arr[index] = arr->arr[last]; | ||
225 | } | ||
226 | |||
227 | static inline void ccArrayFastRemoveObject(ccArray *arr, id object) | ||
228 | { | ||
229 | NSUInteger index = ccArrayGetIndexOfObject(arr, object); | ||
230 | if (index != NSNotFound) | ||
231 | ccArrayFastRemoveObjectAtIndex(arr, index); | ||
232 | } | ||
233 | |||
234 | /** Searches for the first occurance of object and removes it. If object is not | ||
235 | found the function has no effect. */ | ||
236 | static inline void ccArrayRemoveObject(ccArray *arr, id object) | ||
237 | { | ||
238 | NSUInteger index = ccArrayGetIndexOfObject(arr, object); | ||
239 | if (index != NSNotFound) | ||
240 | ccArrayRemoveObjectAtIndex(arr, index); | ||
241 | } | ||
242 | |||
243 | /** Removes from arr all objects in minusArr. For each object in minusArr, the | ||
244 | first matching instance in arr will be removed. */ | ||
245 | static inline void ccArrayRemoveArray(ccArray *arr, ccArray *minusArr) | ||
246 | { | ||
247 | for( NSUInteger i = 0; i < minusArr->num; i++) | ||
248 | ccArrayRemoveObject(arr, minusArr->arr[i]); | ||
249 | } | ||
250 | |||
251 | /** Removes from arr all objects in minusArr. For each object in minusArr, all | ||
252 | matching instances in arr will be removed. */ | ||
253 | static inline void ccArrayFullRemoveArray(ccArray *arr, ccArray *minusArr) | ||
254 | { | ||
255 | NSUInteger back = 0; | ||
256 | |||
257 | for( NSUInteger i = 0; i < arr->num; i++) { | ||
258 | if( ccArrayContainsObject(minusArr, arr->arr[i]) ) { | ||
259 | [arr->arr[i] release]; | ||
260 | back++; | ||
261 | } else | ||
262 | arr->arr[i - back] = arr->arr[i]; | ||
263 | } | ||
264 | |||
265 | arr->num -= back; | ||
266 | } | ||
267 | |||
268 | /** Sends to each object in arr the message identified by given selector. */ | ||
269 | static inline void ccArrayMakeObjectsPerformSelector(ccArray *arr, SEL sel) | ||
270 | { | ||
271 | for( NSUInteger i = 0; i < arr->num; i++) | ||
272 | [arr->arr[i] performSelector:sel]; | ||
273 | } | ||
274 | |||
275 | static inline void ccArrayMakeObjectsPerformSelectorWithObject(ccArray *arr, SEL sel, id object) | ||
276 | { | ||
277 | for( NSUInteger i = 0; i < arr->num; i++) | ||
278 | [arr->arr[i] performSelector:sel withObject:object]; | ||
279 | } | ||
280 | |||
281 | |||
282 | #pragma mark - | ||
283 | #pragma mark ccCArray for Values (c structures) | ||
284 | |||
285 | typedef ccArray ccCArray; | ||
286 | |||
287 | static inline void ccCArrayRemoveAllValues(ccCArray *arr); | ||
288 | |||
289 | /** Allocates and initializes a new C array with specified capacity */ | ||
290 | static inline ccCArray* ccCArrayNew(NSUInteger capacity) { | ||
291 | if (capacity == 0) | ||
292 | capacity = 1; | ||
293 | |||
294 | ccCArray *arr = (ccCArray*)malloc( sizeof(ccCArray) ); | ||
295 | arr->num = 0; | ||
296 | arr->arr = (id*) malloc( capacity * sizeof(id) ); | ||
297 | arr->max = capacity; | ||
298 | |||
299 | return arr; | ||
300 | } | ||
301 | |||
302 | /** Frees C array after removing all remaining values. Silently ignores nil arr. */ | ||
303 | static inline void ccCArrayFree(ccCArray *arr) | ||
304 | { | ||
305 | if( arr == nil ) return; | ||
306 | |||
307 | ccCArrayRemoveAllValues(arr); | ||
308 | |||
309 | free(arr->arr); | ||
310 | free(arr); | ||
311 | } | ||
312 | |||
313 | /** Doubles C array capacity */ | ||
314 | static inline void ccCArrayDoubleCapacity(ccCArray *arr) | ||
315 | { | ||
316 | ccArrayDoubleCapacity(arr); | ||
317 | } | ||
318 | |||
319 | /** Increases array capacity such that max >= num + extra. */ | ||
320 | static inline void ccCArrayEnsureExtraCapacity(ccCArray *arr, NSUInteger extra) | ||
321 | { | ||
322 | ccArrayEnsureExtraCapacity(arr,extra); | ||
323 | } | ||
324 | |||
325 | /** Returns index of first occurence of value, NSNotFound if value not found. */ | ||
326 | static inline NSUInteger ccCArrayGetIndexOfValue(ccCArray *arr, void* value) | ||
327 | { | ||
328 | for( NSUInteger i = 0; i < arr->num; i++) | ||
329 | if( arr->arr[i] == value ) return i; | ||
330 | return NSNotFound; | ||
331 | } | ||
332 | |||
333 | /** Returns a Boolean value that indicates whether value is present in the C array. */ | ||
334 | static inline BOOL ccCArrayContainsValue(ccCArray *arr, void* value) | ||
335 | { | ||
336 | return ccCArrayGetIndexOfValue(arr, value) != NSNotFound; | ||
337 | } | ||
338 | |||
339 | /** Inserts a value at a certain position. Behaviour undefined if aray doesn't have enough capacity */ | ||
340 | static inline void ccCArrayInsertValueAtIndex( ccCArray *arr, void *value, NSUInteger index) | ||
341 | { | ||
342 | NSCAssert( index < arr->max, @"ccCArrayInsertValueAtIndex: invalid index"); | ||
343 | |||
344 | NSUInteger remaining = arr->num - index; | ||
345 | |||
346 | // last Value doesn't need to be moved | ||
347 | if( remaining > 0) { | ||
348 | // tex coordinates | ||
349 | memmove( &arr->arr[index+1],&arr->arr[index], sizeof(void*) * remaining ); | ||
350 | } | ||
351 | |||
352 | arr->num++; | ||
353 | arr->arr[index] = (id) value; | ||
354 | } | ||
355 | |||
356 | /** Appends an value. Bahaviour undefined if array doesn't have enough capacity. */ | ||
357 | static inline void ccCArrayAppendValue(ccCArray *arr, void* value) | ||
358 | { | ||
359 | arr->arr[arr->num] = (id) value; | ||
360 | arr->num++; | ||
361 | } | ||
362 | |||
363 | /** Appends an value. Capacity of arr is increased if needed. */ | ||
364 | static inline void ccCArrayAppendValueWithResize(ccCArray *arr, void* value) | ||
365 | { | ||
366 | ccCArrayEnsureExtraCapacity(arr, 1); | ||
367 | ccCArrayAppendValue(arr, value); | ||
368 | } | ||
369 | |||
370 | /** Appends values from plusArr to arr. Behaviour undefined if arr doesn't have | ||
371 | enough capacity. */ | ||
372 | static inline void ccCArrayAppendArray(ccCArray *arr, ccCArray *plusArr) | ||
373 | { | ||
374 | for( NSUInteger i = 0; i < plusArr->num; i++) | ||
375 | ccCArrayAppendValue(arr, plusArr->arr[i]); | ||
376 | } | ||
377 | |||
378 | /** Appends values from plusArr to arr. Capacity of arr is increased if needed. */ | ||
379 | static inline void ccCArrayAppendArrayWithResize(ccCArray *arr, ccCArray *plusArr) | ||
380 | { | ||
381 | ccCArrayEnsureExtraCapacity(arr, plusArr->num); | ||
382 | ccCArrayAppendArray(arr, plusArr); | ||
383 | } | ||
384 | |||
385 | /** Removes all values from arr */ | ||
386 | static inline void ccCArrayRemoveAllValues(ccCArray *arr) | ||
387 | { | ||
388 | arr->num = 0; | ||
389 | } | ||
390 | |||
391 | /** Removes value at specified index and pushes back all subsequent values. | ||
392 | Behaviour undefined if index outside [0, num-1]. | ||
393 | @since v0.99.4 | ||
394 | */ | ||
395 | static inline void ccCArrayRemoveValueAtIndex(ccCArray *arr, NSUInteger index) | ||
396 | { | ||
397 | for( NSUInteger last = --arr->num; index < last; index++) | ||
398 | arr->arr[index] = arr->arr[index + 1]; | ||
399 | } | ||
400 | |||
401 | /** Removes value at specified index and fills the gap with the last value, | ||
402 | thereby avoiding the need to push back subsequent values. | ||
403 | Behaviour undefined if index outside [0, num-1]. | ||
404 | @since v0.99.4 | ||
405 | */ | ||
406 | static inline void ccCArrayFastRemoveValueAtIndex(ccCArray *arr, NSUInteger index) | ||
407 | { | ||
408 | NSUInteger last = --arr->num; | ||
409 | arr->arr[index] = arr->arr[last]; | ||
410 | } | ||
411 | |||
412 | /** Searches for the first occurance of value and removes it. If value is not found the function has no effect. | ||
413 | @since v0.99.4 | ||
414 | */ | ||
415 | static inline void ccCArrayRemoveValue(ccCArray *arr, void* value) | ||
416 | { | ||
417 | NSUInteger index = ccCArrayGetIndexOfValue(arr, value); | ||
418 | if (index != NSNotFound) | ||
419 | ccCArrayRemoveValueAtIndex(arr, index); | ||
420 | } | ||
421 | |||
422 | /** Removes from arr all values in minusArr. For each Value in minusArr, the first matching instance in arr will be removed. | ||
423 | @since v0.99.4 | ||
424 | */ | ||
425 | static inline void ccCArrayRemoveArray(ccCArray *arr, ccCArray *minusArr) | ||
426 | { | ||
427 | for( NSUInteger i = 0; i < minusArr->num; i++) | ||
428 | ccCArrayRemoveValue(arr, minusArr->arr[i]); | ||
429 | } | ||
430 | |||
431 | /** Removes from arr all values in minusArr. For each value in minusArr, all matching instances in arr will be removed. | ||
432 | @since v0.99.4 | ||
433 | */ | ||
434 | static inline void ccCArrayFullRemoveArray(ccCArray *arr, ccCArray *minusArr) | ||
435 | { | ||
436 | NSUInteger back = 0; | ||
437 | |||
438 | for( NSUInteger i = 0; i < arr->num; i++) { | ||
439 | if( ccCArrayContainsValue(minusArr, arr->arr[i]) ) { | ||
440 | back++; | ||
441 | } else | ||
442 | arr->arr[i - back] = arr->arr[i]; | ||
443 | } | ||
444 | |||
445 | arr->num -= back; | ||
446 | } | ||
447 | #endif // CC_ARRAY_H | ||
diff --git a/libs/cocos2d/Support/ccUtils.c b/libs/cocos2d/Support/ccUtils.c new file mode 100755 index 0000000..39786ec --- /dev/null +++ b/libs/cocos2d/Support/ccUtils.c | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | ccNextPOT function is licensed under the same license that is used in CCTexture2D.m. | ||
8 | */ | ||
9 | #include "ccUtils.h" | ||
10 | |||
11 | unsigned long ccNextPOT(unsigned long x) | ||
12 | { | ||
13 | x = x - 1; | ||
14 | x = x | (x >> 1); | ||
15 | x = x | (x >> 2); | ||
16 | x = x | (x >> 4); | ||
17 | x = x | (x >> 8); | ||
18 | x = x | (x >>16); | ||
19 | return x + 1; | ||
20 | } \ No newline at end of file | ||
diff --git a/libs/cocos2d/Support/ccUtils.h b/libs/cocos2d/Support/ccUtils.h new file mode 100755 index 0000000..783fc54 --- /dev/null +++ b/libs/cocos2d/Support/ccUtils.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
3 | * | ||
4 | */ | ||
5 | |||
6 | #ifndef __CC_UTILS_H | ||
7 | #define __CC_UTILS_H | ||
8 | |||
9 | /** @file ccUtils.h | ||
10 | Misc free functions | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | ccNextPOT function is licensed under the same license that is used in CCTexture2D.m. | ||
15 | */ | ||
16 | |||
17 | /** returns the Next Power of Two value. | ||
18 | |||
19 | Examples: | ||
20 | - If "value" is 15, it will return 16. | ||
21 | - If "value" is 16, it will return 16. | ||
22 | - If "value" is 17, it will return 32. | ||
23 | |||
24 | @since v0.99.5 | ||
25 | */ | ||
26 | |||
27 | unsigned long ccNextPOT( unsigned long value ); | ||
28 | |||
29 | #endif // ! __CC_UTILS_H | ||
diff --git a/libs/cocos2d/Support/uthash.h b/libs/cocos2d/Support/uthash.h new file mode 100755 index 0000000..a4bdc18 --- /dev/null +++ b/libs/cocos2d/Support/uthash.h | |||
@@ -0,0 +1,972 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2010, Troy D. Hanson http://uthash.sourceforge.net | ||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are met: | ||
7 | |||
8 | * Redistributions of source code must retain the above copyright | ||
9 | notice, this list of conditions and the following disclaimer. | ||
10 | |||
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||
12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||
14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||
15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
22 | */ | ||
23 | |||
24 | #ifndef UTHASH_H | ||
25 | #define UTHASH_H | ||
26 | |||
27 | #include <string.h> /* memcmp,strlen */ | ||
28 | #include <stddef.h> /* ptrdiff_t */ | ||
29 | |||
30 | /* These macros use decltype or the earlier __typeof GNU extension. | ||
31 | As decltype is only available in newer compilers (VS2010 or gcc 4.3+ | ||
32 | when compiling c++ source) this code uses whatever method is needed | ||
33 | or, for VS2008 where neither is available, uses casting workarounds. */ | ||
34 | #ifdef _MSC_VER /* MS compiler */ | ||
35 | #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ | ||
36 | #define DECLTYPE(x) (decltype(x)) | ||
37 | #else /* VS2008 or older (or VS2010 in C mode) */ | ||
38 | #define NO_DECLTYPE | ||
39 | #define DECLTYPE(x) | ||
40 | #endif | ||
41 | #else /* GNU, Sun and other compilers */ | ||
42 | #define DECLTYPE(x) (__typeof(x)) | ||
43 | #endif | ||
44 | |||
45 | #ifdef NO_DECLTYPE | ||
46 | #define DECLTYPE_ASSIGN(dst,src) \ | ||
47 | do { \ | ||
48 | char **_da_dst = (char**)(&(dst)); \ | ||
49 | *_da_dst = (char*)(src); \ | ||
50 | } while(0) | ||
51 | #else | ||
52 | #define DECLTYPE_ASSIGN(dst,src) \ | ||
53 | do { \ | ||
54 | (dst) = DECLTYPE(dst)(src); \ | ||
55 | } while(0) | ||
56 | #endif | ||
57 | |||
58 | /* a number of the hash function use uint32_t which isn't defined on win32 */ | ||
59 | #ifdef _MSC_VER | ||
60 | typedef unsigned int uint32_t; | ||
61 | #else | ||
62 | #include <inttypes.h> /* uint32_t */ | ||
63 | #endif | ||
64 | |||
65 | #define UTHASH_VERSION 1.9.3 | ||
66 | |||
67 | #define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ | ||
68 | #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ | ||
69 | #define uthash_free(ptr,sz) free(ptr) /* free fcn */ | ||
70 | |||
71 | #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ | ||
72 | #define uthash_expand_fyi(tbl) /* can be defined to log expands */ | ||
73 | |||
74 | /* initial number of buckets */ | ||
75 | #define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ | ||
76 | #define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ | ||
77 | #define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ | ||
78 | |||
79 | /* calculate the element whose hash handle address is hhe */ | ||
80 | #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) | ||
81 | |||
82 | #define HASH_FIND(hh,head,keyptr,keylen,out) \ | ||
83 | do { \ | ||
84 | unsigned _hf_bkt,_hf_hashv; \ | ||
85 | out=NULL; \ | ||
86 | if (head) { \ | ||
87 | HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ | ||
88 | if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ | ||
89 | HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ | ||
90 | keyptr,keylen,out); \ | ||
91 | } \ | ||
92 | } \ | ||
93 | } while (0) | ||
94 | |||
95 | #ifdef HASH_BLOOM | ||
96 | #define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) | ||
97 | #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) | ||
98 | #define HASH_BLOOM_MAKE(tbl) \ | ||
99 | do { \ | ||
100 | (tbl)->bloom_nbits = HASH_BLOOM; \ | ||
101 | (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ | ||
102 | if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ | ||
103 | memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ | ||
104 | (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ | ||
105 | } while (0); | ||
106 | |||
107 | #define HASH_BLOOM_FREE(tbl) \ | ||
108 | do { \ | ||
109 | uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ | ||
110 | } while (0); | ||
111 | |||
112 | #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) | ||
113 | #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) | ||
114 | |||
115 | #define HASH_BLOOM_ADD(tbl,hashv) \ | ||
116 | HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) | ||
117 | |||
118 | #define HASH_BLOOM_TEST(tbl,hashv) \ | ||
119 | HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) | ||
120 | |||
121 | #else | ||
122 | #define HASH_BLOOM_MAKE(tbl) | ||
123 | #define HASH_BLOOM_FREE(tbl) | ||
124 | #define HASH_BLOOM_ADD(tbl,hashv) | ||
125 | #define HASH_BLOOM_TEST(tbl,hashv) (1) | ||
126 | #endif | ||
127 | |||
128 | #define HASH_MAKE_TABLE(hh,head) \ | ||
129 | do { \ | ||
130 | (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ | ||
131 | sizeof(UT_hash_table)); \ | ||
132 | if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ | ||
133 | memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ | ||
134 | (head)->hh.tbl->tail = &((head)->hh); \ | ||
135 | (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ | ||
136 | (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ | ||
137 | (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ | ||
138 | (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ | ||
139 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ | ||
140 | if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ | ||
141 | memset((head)->hh.tbl->buckets, 0, \ | ||
142 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ | ||
143 | HASH_BLOOM_MAKE((head)->hh.tbl); \ | ||
144 | (head)->hh.tbl->signature = HASH_SIGNATURE; \ | ||
145 | } while(0) | ||
146 | |||
147 | #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ | ||
148 | HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) | ||
149 | |||
150 | #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ | ||
151 | do { \ | ||
152 | unsigned _ha_bkt; \ | ||
153 | (add)->hh.next = NULL; \ | ||
154 | (add)->hh.key = (char*)keyptr; \ | ||
155 | (add)->hh.keylen = keylen_in; \ | ||
156 | if (!(head)) { \ | ||
157 | head = (add); \ | ||
158 | (head)->hh.prev = NULL; \ | ||
159 | HASH_MAKE_TABLE(hh,head); \ | ||
160 | } else { \ | ||
161 | (head)->hh.tbl->tail->next = (add); \ | ||
162 | (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ | ||
163 | (head)->hh.tbl->tail = &((add)->hh); \ | ||
164 | } \ | ||
165 | (head)->hh.tbl->num_items++; \ | ||
166 | (add)->hh.tbl = (head)->hh.tbl; \ | ||
167 | HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ | ||
168 | (add)->hh.hashv, _ha_bkt); \ | ||
169 | HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ | ||
170 | HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ | ||
171 | HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ | ||
172 | HASH_FSCK(hh,head); \ | ||
173 | } while(0) | ||
174 | |||
175 | #define HASH_TO_BKT( hashv, num_bkts, bkt ) \ | ||
176 | do { \ | ||
177 | bkt = ((hashv) & ((num_bkts) - 1)); \ | ||
178 | } while(0) | ||
179 | |||
180 | /* delete "delptr" from the hash table. | ||
181 | * "the usual" patch-up process for the app-order doubly-linked-list. | ||
182 | * The use of _hd_hh_del below deserves special explanation. | ||
183 | * These used to be expressed using (delptr) but that led to a bug | ||
184 | * if someone used the same symbol for the head and deletee, like | ||
185 | * HASH_DELETE(hh,users,users); | ||
186 | * We want that to work, but by changing the head (users) below | ||
187 | * we were forfeiting our ability to further refer to the deletee (users) | ||
188 | * in the patch-up process. Solution: use scratch space to | ||
189 | * copy the deletee pointer, then the latter references are via that | ||
190 | * scratch pointer rather than through the repointed (users) symbol. | ||
191 | */ | ||
192 | #define HASH_DELETE(hh,head,delptr) \ | ||
193 | do { \ | ||
194 | unsigned _hd_bkt; \ | ||
195 | struct UT_hash_handle *_hd_hh_del; \ | ||
196 | if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ | ||
197 | uthash_free((head)->hh.tbl->buckets, \ | ||
198 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ | ||
199 | HASH_BLOOM_FREE((head)->hh.tbl); \ | ||
200 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ | ||
201 | head = NULL; \ | ||
202 | } else { \ | ||
203 | _hd_hh_del = &((delptr)->hh); \ | ||
204 | if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ | ||
205 | (head)->hh.tbl->tail = \ | ||
206 | (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ | ||
207 | (head)->hh.tbl->hho); \ | ||
208 | } \ | ||
209 | if ((delptr)->hh.prev) { \ | ||
210 | ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ | ||
211 | (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ | ||
212 | } else { \ | ||
213 | DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ | ||
214 | } \ | ||
215 | if (_hd_hh_del->next) { \ | ||
216 | ((UT_hash_handle*)((char*)_hd_hh_del->next + \ | ||
217 | (head)->hh.tbl->hho))->prev = \ | ||
218 | _hd_hh_del->prev; \ | ||
219 | } \ | ||
220 | HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ | ||
221 | HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ | ||
222 | (head)->hh.tbl->num_items--; \ | ||
223 | } \ | ||
224 | HASH_FSCK(hh,head); \ | ||
225 | } while (0) | ||
226 | |||
227 | |||
228 | /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ | ||
229 | #define HASH_FIND_STR(head,findstr,out) \ | ||
230 | HASH_FIND(hh,head,findstr,strlen(findstr),out) | ||
231 | #define HASH_ADD_STR(head,strfield,add) \ | ||
232 | HASH_ADD(hh,head,strfield,strlen(add->strfield),add) | ||
233 | #define HASH_FIND_INT(head,findint,out) \ | ||
234 | HASH_FIND(hh,head,findint,sizeof(int),out) | ||
235 | #define HASH_ADD_INT(head,intfield,add) \ | ||
236 | HASH_ADD(hh,head,intfield,sizeof(int),add) | ||
237 | #define HASH_FIND_PTR(head,findptr,out) \ | ||
238 | HASH_FIND(hh,head,findptr,sizeof(void *),out) | ||
239 | #define HASH_ADD_PTR(head,ptrfield,add) \ | ||
240 | HASH_ADD(hh,head,ptrfield,sizeof(void *),add) | ||
241 | #define HASH_DEL(head,delptr) \ | ||
242 | HASH_DELETE(hh,head,delptr) | ||
243 | |||
244 | /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. | ||
245 | * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. | ||
246 | */ | ||
247 | #ifdef HASH_DEBUG | ||
248 | #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) | ||
249 | #define HASH_FSCK(hh,head) \ | ||
250 | do { \ | ||
251 | unsigned _bkt_i; \ | ||
252 | unsigned _count, _bkt_count; \ | ||
253 | char *_prev; \ | ||
254 | struct UT_hash_handle *_thh; \ | ||
255 | if (head) { \ | ||
256 | _count = 0; \ | ||
257 | for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ | ||
258 | _bkt_count = 0; \ | ||
259 | _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ | ||
260 | _prev = NULL; \ | ||
261 | while (_thh) { \ | ||
262 | if (_prev != (char*)(_thh->hh_prev)) { \ | ||
263 | HASH_OOPS("invalid hh_prev %p, actual %p\n", \ | ||
264 | _thh->hh_prev, _prev ); \ | ||
265 | } \ | ||
266 | _bkt_count++; \ | ||
267 | _prev = (char*)(_thh); \ | ||
268 | _thh = _thh->hh_next; \ | ||
269 | } \ | ||
270 | _count += _bkt_count; \ | ||
271 | if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ | ||
272 | HASH_OOPS("invalid bucket count %d, actual %d\n", \ | ||
273 | (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ | ||
274 | } \ | ||
275 | } \ | ||
276 | if (_count != (head)->hh.tbl->num_items) { \ | ||
277 | HASH_OOPS("invalid hh item count %d, actual %d\n", \ | ||
278 | (head)->hh.tbl->num_items, _count ); \ | ||
279 | } \ | ||
280 | /* traverse hh in app order; check next/prev integrity, count */ \ | ||
281 | _count = 0; \ | ||
282 | _prev = NULL; \ | ||
283 | _thh = &(head)->hh; \ | ||
284 | while (_thh) { \ | ||
285 | _count++; \ | ||
286 | if (_prev !=(char*)(_thh->prev)) { \ | ||
287 | HASH_OOPS("invalid prev %p, actual %p\n", \ | ||
288 | _thh->prev, _prev ); \ | ||
289 | } \ | ||
290 | _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ | ||
291 | _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ | ||
292 | (head)->hh.tbl->hho) : NULL ); \ | ||
293 | } \ | ||
294 | if (_count != (head)->hh.tbl->num_items) { \ | ||
295 | HASH_OOPS("invalid app item count %d, actual %d\n", \ | ||
296 | (head)->hh.tbl->num_items, _count ); \ | ||
297 | } \ | ||
298 | } \ | ||
299 | } while (0) | ||
300 | #else | ||
301 | #define HASH_FSCK(hh,head) | ||
302 | #endif | ||
303 | |||
304 | /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to | ||
305 | * the descriptor to which this macro is defined for tuning the hash function. | ||
306 | * The app can #include <unistd.h> to get the prototype for write(2). */ | ||
307 | #ifdef HASH_EMIT_KEYS | ||
308 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ | ||
309 | do { \ | ||
310 | unsigned _klen = fieldlen; \ | ||
311 | write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ | ||
312 | write(HASH_EMIT_KEYS, keyptr, fieldlen); \ | ||
313 | } while (0) | ||
314 | #else | ||
315 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) | ||
316 | #endif | ||
317 | |||
318 | /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ | ||
319 | #ifdef HASH_FUNCTION | ||
320 | #define HASH_FCN HASH_FUNCTION | ||
321 | #else | ||
322 | #define HASH_FCN HASH_JEN | ||
323 | #endif | ||
324 | |||
325 | /* The Bernstein hash function, used in Perl prior to v5.6 */ | ||
326 | #define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ | ||
327 | do { \ | ||
328 | unsigned _hb_keylen=keylen; \ | ||
329 | char *_hb_key=(char*)(key); \ | ||
330 | (hashv) = 0; \ | ||
331 | while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ | ||
332 | bkt = (hashv) & (num_bkts-1); \ | ||
333 | } while (0) | ||
334 | |||
335 | |||
336 | /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at | ||
337 | * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ | ||
338 | #define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ | ||
339 | do { \ | ||
340 | unsigned _sx_i; \ | ||
341 | char *_hs_key=(char*)(key); \ | ||
342 | hashv = 0; \ | ||
343 | for(_sx_i=0; _sx_i < keylen; _sx_i++) \ | ||
344 | hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ | ||
345 | bkt = hashv & (num_bkts-1); \ | ||
346 | } while (0) | ||
347 | |||
348 | #define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ | ||
349 | do { \ | ||
350 | unsigned _fn_i; \ | ||
351 | char *_hf_key=(char*)(key); \ | ||
352 | hashv = 2166136261UL; \ | ||
353 | for(_fn_i=0; _fn_i < keylen; _fn_i++) \ | ||
354 | hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ | ||
355 | bkt = hashv & (num_bkts-1); \ | ||
356 | } while(0); | ||
357 | |||
358 | #define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ | ||
359 | do { \ | ||
360 | unsigned _ho_i; \ | ||
361 | char *_ho_key=(char*)(key); \ | ||
362 | hashv = 0; \ | ||
363 | for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ | ||
364 | hashv += _ho_key[_ho_i]; \ | ||
365 | hashv += (hashv << 10); \ | ||
366 | hashv ^= (hashv >> 6); \ | ||
367 | } \ | ||
368 | hashv += (hashv << 3); \ | ||
369 | hashv ^= (hashv >> 11); \ | ||
370 | hashv += (hashv << 15); \ | ||
371 | bkt = hashv & (num_bkts-1); \ | ||
372 | } while(0) | ||
373 | |||
374 | #define HASH_JEN_MIX(a,b,c) \ | ||
375 | do { \ | ||
376 | a -= b; a -= c; a ^= ( c >> 13 ); \ | ||
377 | b -= c; b -= a; b ^= ( a << 8 ); \ | ||
378 | c -= a; c -= b; c ^= ( b >> 13 ); \ | ||
379 | a -= b; a -= c; a ^= ( c >> 12 ); \ | ||
380 | b -= c; b -= a; b ^= ( a << 16 ); \ | ||
381 | c -= a; c -= b; c ^= ( b >> 5 ); \ | ||
382 | a -= b; a -= c; a ^= ( c >> 3 ); \ | ||
383 | b -= c; b -= a; b ^= ( a << 10 ); \ | ||
384 | c -= a; c -= b; c ^= ( b >> 15 ); \ | ||
385 | } while (0) | ||
386 | |||
387 | #define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ | ||
388 | do { \ | ||
389 | unsigned _hj_i,_hj_j,_hj_k; \ | ||
390 | char *_hj_key=(char*)(key); \ | ||
391 | hashv = 0xfeedbeef; \ | ||
392 | _hj_i = _hj_j = 0x9e3779b9; \ | ||
393 | _hj_k = keylen; \ | ||
394 | while (_hj_k >= 12) { \ | ||
395 | _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ | ||
396 | + ( (unsigned)_hj_key[2] << 16 ) \ | ||
397 | + ( (unsigned)_hj_key[3] << 24 ) ); \ | ||
398 | _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ | ||
399 | + ( (unsigned)_hj_key[6] << 16 ) \ | ||
400 | + ( (unsigned)_hj_key[7] << 24 ) ); \ | ||
401 | hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ | ||
402 | + ( (unsigned)_hj_key[10] << 16 ) \ | ||
403 | + ( (unsigned)_hj_key[11] << 24 ) ); \ | ||
404 | \ | ||
405 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ | ||
406 | \ | ||
407 | _hj_key += 12; \ | ||
408 | _hj_k -= 12; \ | ||
409 | } \ | ||
410 | hashv += keylen; \ | ||
411 | switch ( _hj_k ) { \ | ||
412 | case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ | ||
413 | case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ | ||
414 | case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ | ||
415 | case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ | ||
416 | case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ | ||
417 | case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ | ||
418 | case 5: _hj_j += _hj_key[4]; \ | ||
419 | case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ | ||
420 | case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ | ||
421 | case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ | ||
422 | case 1: _hj_i += _hj_key[0]; \ | ||
423 | } \ | ||
424 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ | ||
425 | bkt = hashv & (num_bkts-1); \ | ||
426 | } while(0) | ||
427 | |||
428 | /* The Paul Hsieh hash function */ | ||
429 | #undef get16bits | ||
430 | #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ | ||
431 | || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) | ||
432 | #define get16bits(d) (*((const uint16_t *) (d))) | ||
433 | #endif | ||
434 | |||
435 | #if !defined (get16bits) | ||
436 | #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ | ||
437 | +(uint32_t)(((const uint8_t *)(d))[0]) ) | ||
438 | #endif | ||
439 | #define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ | ||
440 | do { \ | ||
441 | char *_sfh_key=(char*)(key); \ | ||
442 | uint32_t _sfh_tmp, _sfh_len = keylen; \ | ||
443 | \ | ||
444 | int _sfh_rem = _sfh_len & 3; \ | ||
445 | _sfh_len >>= 2; \ | ||
446 | hashv = 0xcafebabe; \ | ||
447 | \ | ||
448 | /* Main loop */ \ | ||
449 | for (;_sfh_len > 0; _sfh_len--) { \ | ||
450 | hashv += get16bits (_sfh_key); \ | ||
451 | _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ | ||
452 | hashv = (hashv << 16) ^ _sfh_tmp; \ | ||
453 | _sfh_key += 2*sizeof (uint16_t); \ | ||
454 | hashv += hashv >> 11; \ | ||
455 | } \ | ||
456 | \ | ||
457 | /* Handle end cases */ \ | ||
458 | switch (_sfh_rem) { \ | ||
459 | case 3: hashv += get16bits (_sfh_key); \ | ||
460 | hashv ^= hashv << 16; \ | ||
461 | hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ | ||
462 | hashv += hashv >> 11; \ | ||
463 | break; \ | ||
464 | case 2: hashv += get16bits (_sfh_key); \ | ||
465 | hashv ^= hashv << 11; \ | ||
466 | hashv += hashv >> 17; \ | ||
467 | break; \ | ||
468 | case 1: hashv += *_sfh_key; \ | ||
469 | hashv ^= hashv << 10; \ | ||
470 | hashv += hashv >> 1; \ | ||
471 | } \ | ||
472 | \ | ||
473 | /* Force "avalanching" of final 127 bits */ \ | ||
474 | hashv ^= hashv << 3; \ | ||
475 | hashv += hashv >> 5; \ | ||
476 | hashv ^= hashv << 4; \ | ||
477 | hashv += hashv >> 17; \ | ||
478 | hashv ^= hashv << 25; \ | ||
479 | hashv += hashv >> 6; \ | ||
480 | bkt = hashv & (num_bkts-1); \ | ||
481 | } while(0); | ||
482 | |||
483 | #ifdef HASH_USING_NO_STRICT_ALIASING | ||
484 | /* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads. | ||
485 | * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. | ||
486 | * So MurmurHash comes in two versions, the faster unaligned one and the slower | ||
487 | * aligned one. We only use the faster one on CPU's where we know it's safe. | ||
488 | * | ||
489 | * Note the preprocessor built-in defines can be emitted using: | ||
490 | * | ||
491 | * gcc -m64 -dM -E - < /dev/null (on gcc) | ||
492 | * cc -## a.c (where a.c is a simple test file) (Sun Studio) | ||
493 | */ | ||
494 | #if (defined(__i386__) || defined(__x86_64__)) | ||
495 | #define HASH_MUR HASH_MUR_UNALIGNED | ||
496 | #else | ||
497 | #define HASH_MUR HASH_MUR_ALIGNED | ||
498 | #endif | ||
499 | |||
500 | /* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */ | ||
501 | #define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt) \ | ||
502 | do { \ | ||
503 | const unsigned int _mur_m = 0x5bd1e995; \ | ||
504 | const int _mur_r = 24; \ | ||
505 | hashv = 0xcafebabe ^ keylen; \ | ||
506 | char *_mur_key = (char *)(key); \ | ||
507 | uint32_t _mur_tmp, _mur_len = keylen; \ | ||
508 | \ | ||
509 | for (;_mur_len >= 4; _mur_len-=4) { \ | ||
510 | _mur_tmp = *(uint32_t *)_mur_key; \ | ||
511 | _mur_tmp *= _mur_m; \ | ||
512 | _mur_tmp ^= _mur_tmp >> _mur_r; \ | ||
513 | _mur_tmp *= _mur_m; \ | ||
514 | hashv *= _mur_m; \ | ||
515 | hashv ^= _mur_tmp; \ | ||
516 | _mur_key += 4; \ | ||
517 | } \ | ||
518 | \ | ||
519 | switch(_mur_len) \ | ||
520 | { \ | ||
521 | case 3: hashv ^= _mur_key[2] << 16; \ | ||
522 | case 2: hashv ^= _mur_key[1] << 8; \ | ||
523 | case 1: hashv ^= _mur_key[0]; \ | ||
524 | hashv *= _mur_m; \ | ||
525 | }; \ | ||
526 | \ | ||
527 | hashv ^= hashv >> 13; \ | ||
528 | hashv *= _mur_m; \ | ||
529 | hashv ^= hashv >> 15; \ | ||
530 | \ | ||
531 | bkt = hashv & (num_bkts-1); \ | ||
532 | } while(0) | ||
533 | |||
534 | /* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */ | ||
535 | #define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt) \ | ||
536 | do { \ | ||
537 | const unsigned int _mur_m = 0x5bd1e995; \ | ||
538 | const int _mur_r = 24; \ | ||
539 | hashv = 0xcafebabe ^ (keylen); \ | ||
540 | char *_mur_key = (char *)(key); \ | ||
541 | uint32_t _mur_len = keylen; \ | ||
542 | int _mur_align = (int)_mur_key & 3; \ | ||
543 | \ | ||
544 | if (_mur_align && (_mur_len >= 4)) { \ | ||
545 | unsigned _mur_t = 0, _mur_d = 0; \ | ||
546 | switch(_mur_align) { \ | ||
547 | case 1: _mur_t |= _mur_key[2] << 16; \ | ||
548 | case 2: _mur_t |= _mur_key[1] << 8; \ | ||
549 | case 3: _mur_t |= _mur_key[0]; \ | ||
550 | } \ | ||
551 | _mur_t <<= (8 * _mur_align); \ | ||
552 | _mur_key += 4-_mur_align; \ | ||
553 | _mur_len -= 4-_mur_align; \ | ||
554 | int _mur_sl = 8 * (4-_mur_align); \ | ||
555 | int _mur_sr = 8 * _mur_align; \ | ||
556 | \ | ||
557 | for (;_mur_len >= 4; _mur_len-=4) { \ | ||
558 | _mur_d = *(unsigned *)_mur_key; \ | ||
559 | _mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ | ||
560 | unsigned _mur_k = _mur_t; \ | ||
561 | _mur_k *= _mur_m; \ | ||
562 | _mur_k ^= _mur_k >> _mur_r; \ | ||
563 | _mur_k *= _mur_m; \ | ||
564 | hashv *= _mur_m; \ | ||
565 | hashv ^= _mur_k; \ | ||
566 | _mur_t = _mur_d; \ | ||
567 | _mur_key += 4; \ | ||
568 | } \ | ||
569 | _mur_d = 0; \ | ||
570 | if(_mur_len >= _mur_align) { \ | ||
571 | switch(_mur_align) { \ | ||
572 | case 3: _mur_d |= _mur_key[2] << 16; \ | ||
573 | case 2: _mur_d |= _mur_key[1] << 8; \ | ||
574 | case 1: _mur_d |= _mur_key[0]; \ | ||
575 | } \ | ||
576 | unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ | ||
577 | _mur_k *= _mur_m; \ | ||
578 | _mur_k ^= _mur_k >> _mur_r; \ | ||
579 | _mur_k *= _mur_m; \ | ||
580 | hashv *= _mur_m; \ | ||
581 | hashv ^= _mur_k; \ | ||
582 | _mur_k += _mur_align; \ | ||
583 | _mur_len -= _mur_align; \ | ||
584 | \ | ||
585 | switch(_mur_len) \ | ||
586 | { \ | ||
587 | case 3: hashv ^= _mur_key[2] << 16; \ | ||
588 | case 2: hashv ^= _mur_key[1] << 8; \ | ||
589 | case 1: hashv ^= _mur_key[0]; \ | ||
590 | hashv *= _mur_m; \ | ||
591 | } \ | ||
592 | } else { \ | ||
593 | switch(_mur_len) \ | ||
594 | { \ | ||
595 | case 3: _mur_d ^= _mur_key[2] << 16; \ | ||
596 | case 2: _mur_d ^= _mur_key[1] << 8; \ | ||
597 | case 1: _mur_d ^= _mur_key[0]; \ | ||
598 | case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \ | ||
599 | hashv *= _mur_m; \ | ||
600 | } \ | ||
601 | } \ | ||
602 | \ | ||
603 | hashv ^= hashv >> 13; \ | ||
604 | hashv *= _mur_m; \ | ||
605 | hashv ^= hashv >> 15; \ | ||
606 | } else { \ | ||
607 | for (;_mur_len >= 4; _mur_len-=4) { \ | ||
608 | unsigned _mur_k = *(unsigned*)_mur_key; \ | ||
609 | _mur_k *= _mur_m; \ | ||
610 | _mur_k ^= _mur_k >> _mur_r; \ | ||
611 | _mur_k *= _mur_m; \ | ||
612 | hashv *= _mur_m; \ | ||
613 | hashv ^= _mur_k; \ | ||
614 | _mur_key += 4; \ | ||
615 | } \ | ||
616 | switch(_mur_len) \ | ||
617 | { \ | ||
618 | case 3: hashv ^= _mur_key[2] << 16; \ | ||
619 | case 2: hashv ^= _mur_key[1] << 8; \ | ||
620 | case 1: hashv ^= _mur_key[0]; \ | ||
621 | hashv *= _mur_m; \ | ||
622 | } \ | ||
623 | \ | ||
624 | hashv ^= hashv >> 13; \ | ||
625 | hashv *= _mur_m; \ | ||
626 | hashv ^= hashv >> 15; \ | ||
627 | } \ | ||
628 | bkt = hashv & (num_bkts-1); \ | ||
629 | } while(0) | ||
630 | #endif /* HASH_USING_NO_STRICT_ALIASING */ | ||
631 | |||
632 | /* key comparison function; return 0 if keys equal */ | ||
633 | #define HASH_KEYCMP(a,b,len) memcmp(a,b,len) | ||
634 | |||
635 | /* iterate over items in a known bucket to find desired item */ | ||
636 | #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ | ||
637 | do { \ | ||
638 | if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ | ||
639 | else out=NULL; \ | ||
640 | while (out) { \ | ||
641 | if (out->hh.keylen == keylen_in) { \ | ||
642 | if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ | ||
643 | } \ | ||
644 | if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ | ||
645 | else out = NULL; \ | ||
646 | } \ | ||
647 | } while(0) | ||
648 | |||
649 | /* add an item to a bucket */ | ||
650 | #define HASH_ADD_TO_BKT(head,addhh) \ | ||
651 | do { \ | ||
652 | head.count++; \ | ||
653 | (addhh)->hh_next = head.hh_head; \ | ||
654 | (addhh)->hh_prev = NULL; \ | ||
655 | if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ | ||
656 | (head).hh_head=addhh; \ | ||
657 | if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ | ||
658 | && (addhh)->tbl->noexpand != 1) { \ | ||
659 | HASH_EXPAND_BUCKETS((addhh)->tbl); \ | ||
660 | } \ | ||
661 | } while(0) | ||
662 | |||
663 | /* remove an item from a given bucket */ | ||
664 | #define HASH_DEL_IN_BKT(hh,head,hh_del) \ | ||
665 | (head).count--; \ | ||
666 | if ((head).hh_head == hh_del) { \ | ||
667 | (head).hh_head = hh_del->hh_next; \ | ||
668 | } \ | ||
669 | if (hh_del->hh_prev) { \ | ||
670 | hh_del->hh_prev->hh_next = hh_del->hh_next; \ | ||
671 | } \ | ||
672 | if (hh_del->hh_next) { \ | ||
673 | hh_del->hh_next->hh_prev = hh_del->hh_prev; \ | ||
674 | } | ||
675 | |||
676 | /* Bucket expansion has the effect of doubling the number of buckets | ||
677 | * and redistributing the items into the new buckets. Ideally the | ||
678 | * items will distribute more or less evenly into the new buckets | ||
679 | * (the extent to which this is true is a measure of the quality of | ||
680 | * the hash function as it applies to the key domain). | ||
681 | * | ||
682 | * With the items distributed into more buckets, the chain length | ||
683 | * (item count) in each bucket is reduced. Thus by expanding buckets | ||
684 | * the hash keeps a bound on the chain length. This bounded chain | ||
685 | * length is the essence of how a hash provides constant time lookup. | ||
686 | * | ||
687 | * The calculation of tbl->ideal_chain_maxlen below deserves some | ||
688 | * explanation. First, keep in mind that we're calculating the ideal | ||
689 | * maximum chain length based on the *new* (doubled) bucket count. | ||
690 | * In fractions this is just n/b (n=number of items,b=new num buckets). | ||
691 | * Since the ideal chain length is an integer, we want to calculate | ||
692 | * ceil(n/b). We don't depend on floating point arithmetic in this | ||
693 | * hash, so to calculate ceil(n/b) with integers we could write | ||
694 | * | ||
695 | * ceil(n/b) = (n/b) + ((n%b)?1:0) | ||
696 | * | ||
697 | * and in fact a previous version of this hash did just that. | ||
698 | * But now we have improved things a bit by recognizing that b is | ||
699 | * always a power of two. We keep its base 2 log handy (call it lb), | ||
700 | * so now we can write this with a bit shift and logical AND: | ||
701 | * | ||
702 | * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) | ||
703 | * | ||
704 | */ | ||
705 | #define HASH_EXPAND_BUCKETS(tbl) \ | ||
706 | do { \ | ||
707 | unsigned _he_bkt; \ | ||
708 | unsigned _he_bkt_i; \ | ||
709 | struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ | ||
710 | UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ | ||
711 | _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ | ||
712 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ | ||
713 | if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ | ||
714 | memset(_he_new_buckets, 0, \ | ||
715 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ | ||
716 | tbl->ideal_chain_maxlen = \ | ||
717 | (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ | ||
718 | ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ | ||
719 | tbl->nonideal_items = 0; \ | ||
720 | for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ | ||
721 | { \ | ||
722 | _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ | ||
723 | while (_he_thh) { \ | ||
724 | _he_hh_nxt = _he_thh->hh_next; \ | ||
725 | HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ | ||
726 | _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ | ||
727 | if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ | ||
728 | tbl->nonideal_items++; \ | ||
729 | _he_newbkt->expand_mult = _he_newbkt->count / \ | ||
730 | tbl->ideal_chain_maxlen; \ | ||
731 | } \ | ||
732 | _he_thh->hh_prev = NULL; \ | ||
733 | _he_thh->hh_next = _he_newbkt->hh_head; \ | ||
734 | if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ | ||
735 | _he_thh; \ | ||
736 | _he_newbkt->hh_head = _he_thh; \ | ||
737 | _he_thh = _he_hh_nxt; \ | ||
738 | } \ | ||
739 | } \ | ||
740 | uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ | ||
741 | tbl->num_buckets *= 2; \ | ||
742 | tbl->log2_num_buckets++; \ | ||
743 | tbl->buckets = _he_new_buckets; \ | ||
744 | tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ | ||
745 | (tbl->ineff_expands+1) : 0; \ | ||
746 | if (tbl->ineff_expands > 1) { \ | ||
747 | tbl->noexpand=1; \ | ||
748 | uthash_noexpand_fyi(tbl); \ | ||
749 | } \ | ||
750 | uthash_expand_fyi(tbl); \ | ||
751 | } while(0) | ||
752 | |||
753 | |||
754 | /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ | ||
755 | /* Note that HASH_SORT assumes the hash handle name to be hh. | ||
756 | * HASH_SRT was added to allow the hash handle name to be passed in. */ | ||
757 | #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) | ||
758 | #define HASH_SRT(hh,head,cmpfcn) \ | ||
759 | do { \ | ||
760 | unsigned _hs_i; \ | ||
761 | unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ | ||
762 | struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ | ||
763 | if (head) { \ | ||
764 | _hs_insize = 1; \ | ||
765 | _hs_looping = 1; \ | ||
766 | _hs_list = &((head)->hh); \ | ||
767 | while (_hs_looping) { \ | ||
768 | _hs_p = _hs_list; \ | ||
769 | _hs_list = NULL; \ | ||
770 | _hs_tail = NULL; \ | ||
771 | _hs_nmerges = 0; \ | ||
772 | while (_hs_p) { \ | ||
773 | _hs_nmerges++; \ | ||
774 | _hs_q = _hs_p; \ | ||
775 | _hs_psize = 0; \ | ||
776 | for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ | ||
777 | _hs_psize++; \ | ||
778 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ | ||
779 | ((void*)((char*)(_hs_q->next) + \ | ||
780 | (head)->hh.tbl->hho)) : NULL); \ | ||
781 | if (! (_hs_q) ) break; \ | ||
782 | } \ | ||
783 | _hs_qsize = _hs_insize; \ | ||
784 | while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ | ||
785 | if (_hs_psize == 0) { \ | ||
786 | _hs_e = _hs_q; \ | ||
787 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ | ||
788 | ((void*)((char*)(_hs_q->next) + \ | ||
789 | (head)->hh.tbl->hho)) : NULL); \ | ||
790 | _hs_qsize--; \ | ||
791 | } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ | ||
792 | _hs_e = _hs_p; \ | ||
793 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ | ||
794 | ((void*)((char*)(_hs_p->next) + \ | ||
795 | (head)->hh.tbl->hho)) : NULL); \ | ||
796 | _hs_psize--; \ | ||
797 | } else if (( \ | ||
798 | cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ | ||
799 | DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ | ||
800 | ) <= 0) { \ | ||
801 | _hs_e = _hs_p; \ | ||
802 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ | ||
803 | ((void*)((char*)(_hs_p->next) + \ | ||
804 | (head)->hh.tbl->hho)) : NULL); \ | ||
805 | _hs_psize--; \ | ||
806 | } else { \ | ||
807 | _hs_e = _hs_q; \ | ||
808 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ | ||
809 | ((void*)((char*)(_hs_q->next) + \ | ||
810 | (head)->hh.tbl->hho)) : NULL); \ | ||
811 | _hs_qsize--; \ | ||
812 | } \ | ||
813 | if ( _hs_tail ) { \ | ||
814 | _hs_tail->next = ((_hs_e) ? \ | ||
815 | ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ | ||
816 | } else { \ | ||
817 | _hs_list = _hs_e; \ | ||
818 | } \ | ||
819 | _hs_e->prev = ((_hs_tail) ? \ | ||
820 | ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ | ||
821 | _hs_tail = _hs_e; \ | ||
822 | } \ | ||
823 | _hs_p = _hs_q; \ | ||
824 | } \ | ||
825 | _hs_tail->next = NULL; \ | ||
826 | if ( _hs_nmerges <= 1 ) { \ | ||
827 | _hs_looping=0; \ | ||
828 | (head)->hh.tbl->tail = _hs_tail; \ | ||
829 | DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ | ||
830 | } \ | ||
831 | _hs_insize *= 2; \ | ||
832 | } \ | ||
833 | HASH_FSCK(hh,head); \ | ||
834 | } \ | ||
835 | } while (0) | ||
836 | |||
837 | /* This function selects items from one hash into another hash. | ||
838 | * The end result is that the selected items have dual presence | ||
839 | * in both hashes. There is no copy of the items made; rather | ||
840 | * they are added into the new hash through a secondary hash | ||
841 | * hash handle that must be present in the structure. */ | ||
842 | #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ | ||
843 | do { \ | ||
844 | unsigned _src_bkt, _dst_bkt; \ | ||
845 | void *_last_elt=NULL, *_elt; \ | ||
846 | UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ | ||
847 | ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ | ||
848 | if (src) { \ | ||
849 | for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ | ||
850 | for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ | ||
851 | _src_hh; \ | ||
852 | _src_hh = _src_hh->hh_next) { \ | ||
853 | _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ | ||
854 | if (cond(_elt)) { \ | ||
855 | _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ | ||
856 | _dst_hh->key = _src_hh->key; \ | ||
857 | _dst_hh->keylen = _src_hh->keylen; \ | ||
858 | _dst_hh->hashv = _src_hh->hashv; \ | ||
859 | _dst_hh->prev = _last_elt; \ | ||
860 | _dst_hh->next = NULL; \ | ||
861 | if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ | ||
862 | if (!dst) { \ | ||
863 | DECLTYPE_ASSIGN(dst,_elt); \ | ||
864 | HASH_MAKE_TABLE(hh_dst,dst); \ | ||
865 | } else { \ | ||
866 | _dst_hh->tbl = (dst)->hh_dst.tbl; \ | ||
867 | } \ | ||
868 | HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ | ||
869 | HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ | ||
870 | (dst)->hh_dst.tbl->num_items++; \ | ||
871 | _last_elt = _elt; \ | ||
872 | _last_elt_hh = _dst_hh; \ | ||
873 | } \ | ||
874 | } \ | ||
875 | } \ | ||
876 | } \ | ||
877 | HASH_FSCK(hh_dst,dst); \ | ||
878 | } while (0) | ||
879 | |||
880 | #define HASH_CLEAR(hh,head) \ | ||
881 | do { \ | ||
882 | if (head) { \ | ||
883 | uthash_free((head)->hh.tbl->buckets, \ | ||
884 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ | ||
885 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ | ||
886 | (head)=NULL; \ | ||
887 | } \ | ||
888 | } while(0) | ||
889 | |||
890 | #ifdef NO_DECLTYPE | ||
891 | #define HASH_ITER(hh,head,el,tmp) \ | ||
892 | for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ | ||
893 | el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) | ||
894 | #else | ||
895 | #define HASH_ITER(hh,head,el,tmp) \ | ||
896 | for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ | ||
897 | el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) | ||
898 | #endif | ||
899 | |||
900 | /* obtain a count of items in the hash */ | ||
901 | #define HASH_COUNT(head) HASH_CNT(hh,head) | ||
902 | #define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) | ||
903 | |||
904 | typedef struct UT_hash_bucket { | ||
905 | struct UT_hash_handle *hh_head; | ||
906 | unsigned count; | ||
907 | |||
908 | /* expand_mult is normally set to 0. In this situation, the max chain length | ||
909 | * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If | ||
910 | * the bucket's chain exceeds this length, bucket expansion is triggered). | ||
911 | * However, setting expand_mult to a non-zero value delays bucket expansion | ||
912 | * (that would be triggered by additions to this particular bucket) | ||
913 | * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. | ||
914 | * (The multiplier is simply expand_mult+1). The whole idea of this | ||
915 | * multiplier is to reduce bucket expansions, since they are expensive, in | ||
916 | * situations where we know that a particular bucket tends to be overused. | ||
917 | * It is better to let its chain length grow to a longer yet-still-bounded | ||
918 | * value, than to do an O(n) bucket expansion too often. | ||
919 | */ | ||
920 | unsigned expand_mult; | ||
921 | |||
922 | } UT_hash_bucket; | ||
923 | |||
924 | /* random signature used only to find hash tables in external analysis */ | ||
925 | #define HASH_SIGNATURE 0xa0111fe1 | ||
926 | #define HASH_BLOOM_SIGNATURE 0xb12220f2 | ||
927 | |||
928 | typedef struct UT_hash_table { | ||
929 | UT_hash_bucket *buckets; | ||
930 | unsigned num_buckets, log2_num_buckets; | ||
931 | unsigned num_items; | ||
932 | struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ | ||
933 | ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ | ||
934 | |||
935 | /* in an ideal situation (all buckets used equally), no bucket would have | ||
936 | * more than ceil(#items/#buckets) items. that's the ideal chain length. */ | ||
937 | unsigned ideal_chain_maxlen; | ||
938 | |||
939 | /* nonideal_items is the number of items in the hash whose chain position | ||
940 | * exceeds the ideal chain maxlen. these items pay the penalty for an uneven | ||
941 | * hash distribution; reaching them in a chain traversal takes >ideal steps */ | ||
942 | unsigned nonideal_items; | ||
943 | |||
944 | /* ineffective expands occur when a bucket doubling was performed, but | ||
945 | * afterward, more than half the items in the hash had nonideal chain | ||
946 | * positions. If this happens on two consecutive expansions we inhibit any | ||
947 | * further expansion, as it's not helping; this happens when the hash | ||
948 | * function isn't a good fit for the key domain. When expansion is inhibited | ||
949 | * the hash will still work, albeit no longer in constant time. */ | ||
950 | unsigned ineff_expands, noexpand; | ||
951 | |||
952 | uint32_t signature; /* used only to find hash tables in external analysis */ | ||
953 | #ifdef HASH_BLOOM | ||
954 | uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ | ||
955 | uint8_t *bloom_bv; | ||
956 | char bloom_nbits; | ||
957 | #endif | ||
958 | |||
959 | } UT_hash_table; | ||
960 | |||
961 | typedef struct UT_hash_handle { | ||
962 | struct UT_hash_table *tbl; | ||
963 | void *prev; /* prev element in app order */ | ||
964 | void *next; /* next element in app order */ | ||
965 | struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ | ||
966 | struct UT_hash_handle *hh_next; /* next hh in bucket order */ | ||
967 | void *key; /* ptr to enclosing struct's key */ | ||
968 | unsigned keylen; /* enclosing struct's key len */ | ||
969 | unsigned hashv; /* result of hash-fcn(key) */ | ||
970 | } UT_hash_handle; | ||
971 | |||
972 | #endif /* UTHASH_H */ | ||
diff --git a/libs/cocos2d/Support/utlist.h b/libs/cocos2d/Support/utlist.h new file mode 100755 index 0000000..34c725b --- /dev/null +++ b/libs/cocos2d/Support/utlist.h | |||
@@ -0,0 +1,490 @@ | |||
1 | /* | ||
2 | Copyright (c) 2007-2010, Troy D. Hanson http://uthash.sourceforge.net | ||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are met: | ||
7 | |||
8 | * Redistributions of source code must retain the above copyright | ||
9 | notice, this list of conditions and the following disclaimer. | ||
10 | |||
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||
12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||
14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||
15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
22 | */ | ||
23 | |||
24 | #ifndef UTLIST_H | ||
25 | #define UTLIST_H | ||
26 | |||
27 | #define UTLIST_VERSION 1.9.1 | ||
28 | |||
29 | /* | ||
30 | * This file contains macros to manipulate singly and doubly-linked lists. | ||
31 | * | ||
32 | * 1. LL_ macros: singly-linked lists. | ||
33 | * 2. DL_ macros: doubly-linked lists. | ||
34 | * 3. CDL_ macros: circular doubly-linked lists. | ||
35 | * | ||
36 | * To use singly-linked lists, your structure must have a "next" pointer. | ||
37 | * To use doubly-linked lists, your structure must "prev" and "next" pointers. | ||
38 | * Either way, the pointer to the head of the list must be initialized to NULL. | ||
39 | * | ||
40 | * ----------------.EXAMPLE ------------------------- | ||
41 | * struct item { | ||
42 | * int id; | ||
43 | * struct item *prev, *next; | ||
44 | * } | ||
45 | * | ||
46 | * struct item *list = NULL: | ||
47 | * | ||
48 | * int main() { | ||
49 | * struct item *item; | ||
50 | * ... allocate and populate item ... | ||
51 | * DL_APPEND(list, item); | ||
52 | * } | ||
53 | * -------------------------------------------------- | ||
54 | * | ||
55 | * For doubly-linked lists, the append and delete macros are O(1) | ||
56 | * For singly-linked lists, append and delete are O(n) but prepend is O(1) | ||
57 | * The sort macro is O(n log(n)) for all types of single/double/circular lists. | ||
58 | */ | ||
59 | |||
60 | /* These macros use decltype or the earlier __typeof GNU extension. | ||
61 | As decltype is only available in newer compilers (VS2010 or gcc 4.3+ | ||
62 | when compiling c++ code), this code uses whatever method is needed | ||
63 | or, for VS2008 where neither is available, uses casting workarounds. */ | ||
64 | #ifdef _MSC_VER /* MS compiler */ | ||
65 | #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ | ||
66 | #define LDECLTYPE(x) decltype(x) | ||
67 | #else /* VS2008 or older (or VS2010 in C mode) */ | ||
68 | #define NO_DECLTYPE | ||
69 | #define LDECLTYPE(x) char* | ||
70 | #endif | ||
71 | #else /* GNU, Sun and other compilers */ | ||
72 | #define LDECLTYPE(x) __typeof(x) | ||
73 | #endif | ||
74 | |||
75 | /* for VS2008 we use some workarounds to get around the lack of decltype, | ||
76 | * namely, we always reassign our tmp variable to the list head if we need | ||
77 | * to dereference its prev/next pointers, and save/restore the real head.*/ | ||
78 | #ifdef NO_DECLTYPE | ||
79 | #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } | ||
80 | #define _NEXT(elt,list) ((char*)((list)->next)) | ||
81 | #define _NEXTASGN(elt,list,to) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } | ||
82 | #define _PREV(elt,list) ((char*)((list)->prev)) | ||
83 | #define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } | ||
84 | #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } | ||
85 | #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } | ||
86 | #else | ||
87 | #define _SV(elt,list) | ||
88 | #define _NEXT(elt,list) ((elt)->next) | ||
89 | #define _NEXTASGN(elt,list,to) ((elt)->next)=(to) | ||
90 | #define _PREV(elt,list) ((elt)->prev) | ||
91 | #define _PREVASGN(elt,list,to) ((elt)->prev)=(to) | ||
92 | #define _RS(list) | ||
93 | #define _CASTASGN(a,b) (a)=(b) | ||
94 | #endif | ||
95 | |||
96 | /****************************************************************************** | ||
97 | * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * | ||
98 | * Unwieldy variable names used here to avoid shadowing passed-in variables. * | ||
99 | *****************************************************************************/ | ||
100 | #define LL_SORT(list, cmp) \ | ||
101 | do { \ | ||
102 | LDECLTYPE(list) _ls_p; \ | ||
103 | LDECLTYPE(list) _ls_q; \ | ||
104 | LDECLTYPE(list) _ls_e; \ | ||
105 | LDECLTYPE(list) _ls_tail; \ | ||
106 | LDECLTYPE(list) _ls_oldhead; \ | ||
107 | LDECLTYPE(list) _tmp; \ | ||
108 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ | ||
109 | if (list) { \ | ||
110 | _ls_insize = 1; \ | ||
111 | _ls_looping = 1; \ | ||
112 | while (_ls_looping) { \ | ||
113 | _CASTASGN(_ls_p,list); \ | ||
114 | _CASTASGN(_ls_oldhead,list); \ | ||
115 | list = NULL; \ | ||
116 | _ls_tail = NULL; \ | ||
117 | _ls_nmerges = 0; \ | ||
118 | while (_ls_p) { \ | ||
119 | _ls_nmerges++; \ | ||
120 | _ls_q = _ls_p; \ | ||
121 | _ls_psize = 0; \ | ||
122 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ | ||
123 | _ls_psize++; \ | ||
124 | _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \ | ||
125 | if (!_ls_q) break; \ | ||
126 | } \ | ||
127 | _ls_qsize = _ls_insize; \ | ||
128 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ | ||
129 | if (_ls_psize == 0) { \ | ||
130 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
131 | } else if (_ls_qsize == 0 || !_ls_q) { \ | ||
132 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
133 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ | ||
134 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
135 | } else { \ | ||
136 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
137 | } \ | ||
138 | if (_ls_tail) { \ | ||
139 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ | ||
140 | } else { \ | ||
141 | _CASTASGN(list,_ls_e); \ | ||
142 | } \ | ||
143 | _ls_tail = _ls_e; \ | ||
144 | } \ | ||
145 | _ls_p = _ls_q; \ | ||
146 | } \ | ||
147 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \ | ||
148 | if (_ls_nmerges <= 1) { \ | ||
149 | _ls_looping=0; \ | ||
150 | } \ | ||
151 | _ls_insize *= 2; \ | ||
152 | } \ | ||
153 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ | ||
154 | } while (0) | ||
155 | |||
156 | #define DL_SORT(list, cmp) \ | ||
157 | do { \ | ||
158 | LDECLTYPE(list) _ls_p; \ | ||
159 | LDECLTYPE(list) _ls_q; \ | ||
160 | LDECLTYPE(list) _ls_e; \ | ||
161 | LDECLTYPE(list) _ls_tail; \ | ||
162 | LDECLTYPE(list) _ls_oldhead; \ | ||
163 | LDECLTYPE(list) _tmp; \ | ||
164 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ | ||
165 | if (list) { \ | ||
166 | _ls_insize = 1; \ | ||
167 | _ls_looping = 1; \ | ||
168 | while (_ls_looping) { \ | ||
169 | _CASTASGN(_ls_p,list); \ | ||
170 | _CASTASGN(_ls_oldhead,list); \ | ||
171 | list = NULL; \ | ||
172 | _ls_tail = NULL; \ | ||
173 | _ls_nmerges = 0; \ | ||
174 | while (_ls_p) { \ | ||
175 | _ls_nmerges++; \ | ||
176 | _ls_q = _ls_p; \ | ||
177 | _ls_psize = 0; \ | ||
178 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ | ||
179 | _ls_psize++; \ | ||
180 | _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \ | ||
181 | if (!_ls_q) break; \ | ||
182 | } \ | ||
183 | _ls_qsize = _ls_insize; \ | ||
184 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ | ||
185 | if (_ls_psize == 0) { \ | ||
186 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
187 | } else if (_ls_qsize == 0 || !_ls_q) { \ | ||
188 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
189 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ | ||
190 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
191 | } else { \ | ||
192 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
193 | } \ | ||
194 | if (_ls_tail) { \ | ||
195 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ | ||
196 | } else { \ | ||
197 | _CASTASGN(list,_ls_e); \ | ||
198 | } \ | ||
199 | _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \ | ||
200 | _ls_tail = _ls_e; \ | ||
201 | } \ | ||
202 | _ls_p = _ls_q; \ | ||
203 | } \ | ||
204 | _CASTASGN(list->prev, _ls_tail); \ | ||
205 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \ | ||
206 | if (_ls_nmerges <= 1) { \ | ||
207 | _ls_looping=0; \ | ||
208 | } \ | ||
209 | _ls_insize *= 2; \ | ||
210 | } \ | ||
211 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ | ||
212 | } while (0) | ||
213 | |||
214 | #define CDL_SORT(list, cmp) \ | ||
215 | do { \ | ||
216 | LDECLTYPE(list) _ls_p; \ | ||
217 | LDECLTYPE(list) _ls_q; \ | ||
218 | LDECLTYPE(list) _ls_e; \ | ||
219 | LDECLTYPE(list) _ls_tail; \ | ||
220 | LDECLTYPE(list) _ls_oldhead; \ | ||
221 | LDECLTYPE(list) _tmp; \ | ||
222 | LDECLTYPE(list) _tmp2; \ | ||
223 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ | ||
224 | if (list) { \ | ||
225 | _ls_insize = 1; \ | ||
226 | _ls_looping = 1; \ | ||
227 | while (_ls_looping) { \ | ||
228 | _CASTASGN(_ls_p,list); \ | ||
229 | _CASTASGN(_ls_oldhead,list); \ | ||
230 | list = NULL; \ | ||
231 | _ls_tail = NULL; \ | ||
232 | _ls_nmerges = 0; \ | ||
233 | while (_ls_p) { \ | ||
234 | _ls_nmerges++; \ | ||
235 | _ls_q = _ls_p; \ | ||
236 | _ls_psize = 0; \ | ||
237 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ | ||
238 | _ls_psize++; \ | ||
239 | _SV(_ls_q,list); \ | ||
240 | if (_NEXT(_ls_q,list) == _ls_oldhead) { \ | ||
241 | _ls_q = NULL; \ | ||
242 | } else { \ | ||
243 | _ls_q = _NEXT(_ls_q,list); \ | ||
244 | } \ | ||
245 | _RS(list); \ | ||
246 | if (!_ls_q) break; \ | ||
247 | } \ | ||
248 | _ls_qsize = _ls_insize; \ | ||
249 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ | ||
250 | if (_ls_psize == 0) { \ | ||
251 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
252 | if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ | ||
253 | } else if (_ls_qsize == 0 || !_ls_q) { \ | ||
254 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
255 | if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ | ||
256 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ | ||
257 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||
258 | if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ | ||
259 | } else { \ | ||
260 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||
261 | if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ | ||
262 | } \ | ||
263 | if (_ls_tail) { \ | ||
264 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ | ||
265 | } else { \ | ||
266 | _CASTASGN(list,_ls_e); \ | ||
267 | } \ | ||
268 | _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \ | ||
269 | _ls_tail = _ls_e; \ | ||
270 | } \ | ||
271 | _ls_p = _ls_q; \ | ||
272 | } \ | ||
273 | _CASTASGN(list->prev,_ls_tail); \ | ||
274 | _CASTASGN(_tmp2,list); \ | ||
275 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp2); _RS(list); \ | ||
276 | if (_ls_nmerges <= 1) { \ | ||
277 | _ls_looping=0; \ | ||
278 | } \ | ||
279 | _ls_insize *= 2; \ | ||
280 | } \ | ||
281 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ | ||
282 | } while (0) | ||
283 | |||
284 | /****************************************************************************** | ||
285 | * singly linked list macros (non-circular) * | ||
286 | *****************************************************************************/ | ||
287 | #define LL_PREPEND(head,add) \ | ||
288 | do { \ | ||
289 | (add)->next = head; \ | ||
290 | head = add; \ | ||
291 | } while (0) | ||
292 | |||
293 | #define LL_APPEND(head,add) \ | ||
294 | do { \ | ||
295 | LDECLTYPE(head) _tmp; \ | ||
296 | (add)->next=NULL; \ | ||
297 | if (head) { \ | ||
298 | _tmp = head; \ | ||
299 | while (_tmp->next) { _tmp = _tmp->next; } \ | ||
300 | _tmp->next=(add); \ | ||
301 | } else { \ | ||
302 | (head)=(add); \ | ||
303 | } \ | ||
304 | } while (0) | ||
305 | |||
306 | #define LL_DELETE(head,del) \ | ||
307 | do { \ | ||
308 | LDECLTYPE(head) _tmp; \ | ||
309 | if ((head) == (del)) { \ | ||
310 | (head)=(head)->next; \ | ||
311 | } else { \ | ||
312 | _tmp = head; \ | ||
313 | while (_tmp->next && (_tmp->next != (del))) { \ | ||
314 | _tmp = _tmp->next; \ | ||
315 | } \ | ||
316 | if (_tmp->next) { \ | ||
317 | _tmp->next = ((del)->next); \ | ||
318 | } \ | ||
319 | } \ | ||
320 | } while (0) | ||
321 | |||
322 | /* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ | ||
323 | #define LL_APPEND_VS2008(head,add) \ | ||
324 | do { \ | ||
325 | if (head) { \ | ||
326 | (add)->next = head; /* use add->next as a temp variable */ \ | ||
327 | while ((add)->next->next) { (add)->next = (add)->next->next; } \ | ||
328 | (add)->next->next=(add); \ | ||
329 | } else { \ | ||
330 | (head)=(add); \ | ||
331 | } \ | ||
332 | (add)->next=NULL; \ | ||
333 | } while (0) | ||
334 | |||
335 | #define LL_DELETE_VS2008(head,del) \ | ||
336 | do { \ | ||
337 | if ((head) == (del)) { \ | ||
338 | (head)=(head)->next; \ | ||
339 | } else { \ | ||
340 | char *_tmp = (char*)(head); \ | ||
341 | while (head->next && (head->next != (del))) { \ | ||
342 | head = head->next; \ | ||
343 | } \ | ||
344 | if (head->next) { \ | ||
345 | head->next = ((del)->next); \ | ||
346 | } \ | ||
347 | { \ | ||
348 | char **_head_alias = (char**)&(head); \ | ||
349 | *_head_alias = _tmp; \ | ||
350 | } \ | ||
351 | } \ | ||
352 | } while (0) | ||
353 | #ifdef NO_DECLTYPE | ||
354 | #undef LL_APPEND | ||
355 | #define LL_APPEND LL_APPEND_VS2008 | ||
356 | #undef LL_DELETE | ||
357 | #define LL_DELETE LL_DELETE_VS2008 | ||
358 | #endif | ||
359 | /* end VS2008 replacements */ | ||
360 | |||
361 | #define LL_FOREACH(head,el) \ | ||
362 | for(el=head;el;el=el->next) | ||
363 | |||
364 | #define LL_FOREACH_SAFE(head,el,tmp) \ | ||
365 | for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) | ||
366 | |||
367 | #define LL_SEARCH_SCALAR(head,out,field,val) \ | ||
368 | do { \ | ||
369 | LL_FOREACH(head,out) { \ | ||
370 | if ((out)->field == (val)) break; \ | ||
371 | } \ | ||
372 | } while(0) | ||
373 | |||
374 | #define LL_SEARCH(head,out,elt,cmp) \ | ||
375 | do { \ | ||
376 | LL_FOREACH(head,out) { \ | ||
377 | if ((cmp(out,elt))==0) break; \ | ||
378 | } \ | ||
379 | } while(0) | ||
380 | |||
381 | /****************************************************************************** | ||
382 | * doubly linked list macros (non-circular) * | ||
383 | *****************************************************************************/ | ||
384 | #define DL_PREPEND(head,add) \ | ||
385 | do { \ | ||
386 | (add)->next = head; \ | ||
387 | if (head) { \ | ||
388 | (add)->prev = (head)->prev; \ | ||
389 | (head)->prev = (add); \ | ||
390 | } else { \ | ||
391 | (add)->prev = (add); \ | ||
392 | } \ | ||
393 | (head) = (add); \ | ||
394 | } while (0) | ||
395 | |||
396 | #define DL_APPEND(head,add) \ | ||
397 | do { \ | ||
398 | if (head) { \ | ||
399 | (add)->prev = (head)->prev; \ | ||
400 | (head)->prev->next = (add); \ | ||
401 | (head)->prev = (add); \ | ||
402 | (add)->next = NULL; \ | ||
403 | } else { \ | ||
404 | (head)=(add); \ | ||
405 | (head)->prev = (head); \ | ||
406 | (head)->next = NULL; \ | ||
407 | } \ | ||
408 | } while (0); | ||
409 | |||
410 | #define DL_DELETE(head,del) \ | ||
411 | do { \ | ||
412 | if ((del)->prev == (del)) { \ | ||
413 | (head)=NULL; \ | ||
414 | } else if ((del)==(head)) { \ | ||
415 | (del)->next->prev = (del)->prev; \ | ||
416 | (head) = (del)->next; \ | ||
417 | } else { \ | ||
418 | (del)->prev->next = (del)->next; \ | ||
419 | if ((del)->next) { \ | ||
420 | (del)->next->prev = (del)->prev; \ | ||
421 | } else { \ | ||
422 | (head)->prev = (del)->prev; \ | ||
423 | } \ | ||
424 | } \ | ||
425 | } while (0); | ||
426 | |||
427 | |||
428 | #define DL_FOREACH(head,el) \ | ||
429 | for(el=head;el;el=el->next) | ||
430 | |||
431 | /* this version is safe for deleting the elements during iteration */ | ||
432 | #define DL_FOREACH_SAFE(head,el,tmp) \ | ||
433 | for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) | ||
434 | |||
435 | /* these are identical to their singly-linked list counterparts */ | ||
436 | #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR | ||
437 | #define DL_SEARCH LL_SEARCH | ||
438 | |||
439 | /****************************************************************************** | ||
440 | * circular doubly linked list macros * | ||
441 | *****************************************************************************/ | ||
442 | #define CDL_PREPEND(head,add) \ | ||
443 | do { \ | ||
444 | if (head) { \ | ||
445 | (add)->prev = (head)->prev; \ | ||
446 | (add)->next = (head); \ | ||
447 | (head)->prev = (add); \ | ||
448 | (add)->prev->next = (add); \ | ||
449 | } else { \ | ||
450 | (add)->prev = (add); \ | ||
451 | (add)->next = (add); \ | ||
452 | } \ | ||
453 | (head)=(add); \ | ||
454 | } while (0) | ||
455 | |||
456 | #define CDL_DELETE(head,del) \ | ||
457 | do { \ | ||
458 | if ( ((head)==(del)) && ((head)->next == (head))) { \ | ||
459 | (head) = 0L; \ | ||
460 | } else { \ | ||
461 | (del)->next->prev = (del)->prev; \ | ||
462 | (del)->prev->next = (del)->next; \ | ||
463 | if ((del) == (head)) (head)=(del)->next; \ | ||
464 | } \ | ||
465 | } while (0); | ||
466 | |||
467 | #define CDL_FOREACH(head,el) \ | ||
468 | for(el=head;el;el=(el->next==head ? 0L : el->next)) | ||
469 | |||
470 | #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ | ||
471 | for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ | ||
472 | (el) && ((tmp2)=(el)->next, 1); \ | ||
473 | ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) | ||
474 | |||
475 | #define CDL_SEARCH_SCALAR(head,out,field,val) \ | ||
476 | do { \ | ||
477 | CDL_FOREACH(head,out) { \ | ||
478 | if ((out)->field == (val)) break; \ | ||
479 | } \ | ||
480 | } while(0) | ||
481 | |||
482 | #define CDL_SEARCH(head,out,elt,cmp) \ | ||
483 | do { \ | ||
484 | CDL_FOREACH(head,out) { \ | ||
485 | if ((cmp(out,elt))==0) break; \ | ||
486 | } \ | ||
487 | } while(0) | ||
488 | |||
489 | #endif /* UTLIST_H */ | ||
490 | |||
diff --git a/libs/cocos2d/ccConfig.h b/libs/cocos2d/ccConfig.h new file mode 100755 index 0000000..55b4cd8 --- /dev/null +++ b/libs/cocos2d/ccConfig.h | |||
@@ -0,0 +1,334 @@ | |||
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 | #import <Availability.h> | ||
28 | |||
29 | /** | ||
30 | @file | ||
31 | cocos2d (cc) configuration file | ||
32 | */ | ||
33 | |||
34 | /** @def CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
35 | If enabled, the texture coordinates will be calculated by using this formula: | ||
36 | - texCoord.left = (rect.origin.x*2+1) / (texture.wide*2); | ||
37 | - texCoord.right = texCoord.left + (rect.size.width*2-2)/(texture.wide*2); | ||
38 | |||
39 | The same for bottom and top. | ||
40 | |||
41 | This formula prevents artifacts by using 99% of the texture. | ||
42 | The "correct" way to prevent artifacts is by using the spritesheet-artifact-fixer.py or a similar tool. | ||
43 | |||
44 | Affected nodes: | ||
45 | - CCSprite / CCSpriteBatchNode and subclasses: CCLabelBMFont, CCTMXTiledMap | ||
46 | - CCLabelAtlas | ||
47 | - CCQuadParticleSystem | ||
48 | - CCTileMap | ||
49 | |||
50 | To enabled set it to 1. Disabled by default. | ||
51 | |||
52 | @since v0.99.5 | ||
53 | */ | ||
54 | #ifndef CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
55 | #define CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 0 | ||
56 | #endif | ||
57 | |||
58 | |||
59 | /** @def CC_FONT_LABEL_SUPPORT | ||
60 | If enabled, FontLabel will be used to render .ttf files. | ||
61 | If the .ttf file is not found, then it will use the standard UIFont class | ||
62 | If disabled, the standard UIFont class will be used. | ||
63 | |||
64 | To disable set it to 0. Enabled by default. | ||
65 | |||
66 | Only valid for cocos2d-ios. Not supported on cocos2d-mac | ||
67 | */ | ||
68 | #ifndef CC_FONT_LABEL_SUPPORT | ||
69 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
70 | #define CC_FONT_LABEL_SUPPORT 1 | ||
71 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
72 | #define CC_FONT_LABEL_SUPPORT 0 | ||
73 | #endif | ||
74 | #endif | ||
75 | |||
76 | /** @def CC_DIRECTOR_FAST_FPS | ||
77 | If enabled, then the FPS will be drawn using CCLabelAtlas (fast rendering). | ||
78 | You will need to add the fps_images.png to your project. | ||
79 | If disabled, the FPS will be rendered using CCLabel (slow rendering) | ||
80 | |||
81 | To enable set it to a value different than 0. Enabled by default. | ||
82 | */ | ||
83 | #ifndef CC_DIRECTOR_FAST_FPS | ||
84 | #define CC_DIRECTOR_FAST_FPS 1 | ||
85 | #endif | ||
86 | |||
87 | /** @def CC_DIRECTOR_FPS_INTERVAL | ||
88 | Senconds between FPS updates. | ||
89 | 0.5 seconds, means that the FPS number will be updated every 0.5 seconds. | ||
90 | Having a bigger number means a more reliable FPS | ||
91 | |||
92 | Default value: 0.1f | ||
93 | */ | ||
94 | #ifndef CC_DIRECTOR_FPS_INTERVAL | ||
95 | #define CC_DIRECTOR_FPS_INTERVAL (0.1f) | ||
96 | #endif | ||
97 | |||
98 | /** @def CC_DIRECTOR_DISPATCH_FAST_EVENTS | ||
99 | If enabled, and only when it is used with CCFastDirector, the main loop will wait 0.04 seconds to | ||
100 | dispatch all the events, even if there are not events to dispatch. | ||
101 | If your game uses lot's of events (eg: touches) it might be a good idea to enable this feature. | ||
102 | Otherwise, it is safe to leave it disabled. | ||
103 | |||
104 | To enable set it to 1. Disabled by default. | ||
105 | |||
106 | @warning This feature is experimental | ||
107 | */ | ||
108 | #ifndef CC_DIRECTOR_DISPATCH_FAST_EVENTS | ||
109 | #define CC_DIRECTOR_DISPATCH_FAST_EVENTS 0 | ||
110 | #endif | ||
111 | |||
112 | /** @def CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
113 | If enabled, cocos2d-mac will run on the Display Link thread. If disabled cocos2d-mac will run in its own thread. | ||
114 | |||
115 | If enabled, the images will be drawn at the "correct" time, but the events might not be very responsive. | ||
116 | If disabled, some frames might be skipped, but the events will be dispatched as they arrived. | ||
117 | |||
118 | To enable set it to a 1, to disable it set to 0. Enabled by default. | ||
119 | |||
120 | Only valid for cocos2d-mac. Not supported on cocos2d-ios. | ||
121 | |||
122 | */ | ||
123 | #ifndef CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD | ||
124 | #define CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD 1 | ||
125 | #endif | ||
126 | |||
127 | /** @def CC_COCOSNODE_RENDER_SUBPIXEL | ||
128 | If enabled, the CCNode objects (CCSprite, CCLabel,etc) will be able to render in subpixels. | ||
129 | If disabled, integer pixels will be used. | ||
130 | |||
131 | To enable set it to 1. Enabled by default. | ||
132 | */ | ||
133 | #ifndef CC_COCOSNODE_RENDER_SUBPIXEL | ||
134 | #define CC_COCOSNODE_RENDER_SUBPIXEL 1 | ||
135 | #endif | ||
136 | |||
137 | /** @def CC_SPRITEBATCHNODE_RENDER_SUBPIXEL | ||
138 | If enabled, the CCSprite objects rendered with CCSpriteBatchNode will be able to render in subpixels. | ||
139 | If disabled, integer pixels will be used. | ||
140 | |||
141 | To enable set it to 1. Enabled by default. | ||
142 | */ | ||
143 | #ifndef CC_SPRITEBATCHNODE_RENDER_SUBPIXEL | ||
144 | #define CC_SPRITEBATCHNODE_RENDER_SUBPIXEL 1 | ||
145 | #endif | ||
146 | |||
147 | /** @def CC_USES_VBO | ||
148 | If enabled, batch nodes (texture atlas and particle system) will use VBO instead of vertex list (VBO is recommended by Apple) | ||
149 | |||
150 | To enable set it to 1. | ||
151 | Enabled by default on iPhone with ARMv7 processors, iPhone Simulator and Mac | ||
152 | Disabled by default on iPhone with ARMv6 processors. | ||
153 | |||
154 | @since v0.99.5 | ||
155 | */ | ||
156 | #ifndef CC_USES_VBO | ||
157 | #if defined(__ARM_NEON__) || TARGET_IPHONE_SIMULATOR || defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
158 | #define CC_USES_VBO 1 | ||
159 | #else | ||
160 | #define CC_USES_VBO 0 | ||
161 | #endif | ||
162 | #endif | ||
163 | |||
164 | /** @def CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
165 | If enabled, CCNode will transform the nodes using a cached Affine matrix. | ||
166 | If disabled, the node will be transformed using glTranslate,glRotate,glScale. | ||
167 | Using the affine matrix only requires 2 GL calls. | ||
168 | Using the translate/rotate/scale requires 5 GL calls. | ||
169 | But computing the Affine matrix is relative expensive. | ||
170 | But according to performance tests, Affine matrix performs better. | ||
171 | This parameter doesn't affect CCSpriteBatchNode nodes. | ||
172 | |||
173 | To enable set it to a value different than 0. Enabled by default. | ||
174 | |||
175 | */ | ||
176 | #ifndef CC_NODE_TRANSFORM_USING_AFFINE_MATRIX | ||
177 | #define CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 1 | ||
178 | #endif | ||
179 | |||
180 | /** @def CC_OPTIMIZE_BLEND_FUNC_FOR_PREMULTIPLIED_ALPHA | ||
181 | If most of your imamges have pre-multiplied alpha, set it to 1 (if you are going to use .PNG/.JPG file images). | ||
182 | Only set to 0 if ALL your images by-pass Apple UIImage loading system (eg: if you use libpng or PVR images) | ||
183 | |||
184 | To enable set it to a value different than 0. Enabled by default. | ||
185 | |||
186 | @since v0.99.5 | ||
187 | */ | ||
188 | #ifndef CC_OPTIMIZE_BLEND_FUNC_FOR_PREMULTIPLIED_ALPHA | ||
189 | #define CC_OPTIMIZE_BLEND_FUNC_FOR_PREMULTIPLIED_ALPHA 1 | ||
190 | #endif | ||
191 | |||
192 | /** @def CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP | ||
193 | Use GL_TRIANGLE_STRIP instead of GL_TRIANGLES when rendering the texture atlas. | ||
194 | It seems it is the recommend way, but it is much slower, so, enable it at your own risk | ||
195 | |||
196 | To enable set it to a value different than 0. Disabled by default. | ||
197 | |||
198 | */ | ||
199 | #ifndef CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP | ||
200 | #define CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP 0 | ||
201 | #endif | ||
202 | |||
203 | /** @def CC_TEXTURE_NPOT_SUPPORT | ||
204 | If enabled, NPOT textures will be used where available. Only 3rd gen (and newer) devices support NPOT textures. | ||
205 | NPOT textures have the following limitations: | ||
206 | - They can't have mipmaps | ||
207 | - They only accept GL_CLAMP_TO_EDGE in GL_TEXTURE_WRAP_{S,T} | ||
208 | |||
209 | To enable set it to a value different than 0. Disabled by default. | ||
210 | |||
211 | This value governs only the PNG, GIF, BMP, images. | ||
212 | This value DOES NOT govern the PVR (PVR.GZ, PVR.CCZ) files. If NPOT PVR is loaded, then it will create an NPOT texture ignoring this value. | ||
213 | |||
214 | @deprecated This value will be removed in 1.1 and NPOT textures will be loaded by default if the device supports it. | ||
215 | |||
216 | @since v0.99.2 | ||
217 | */ | ||
218 | #ifndef CC_TEXTURE_NPOT_SUPPORT | ||
219 | #define CC_TEXTURE_NPOT_SUPPORT 0 | ||
220 | #endif | ||
221 | |||
222 | /** @def CC_RETINA_DISPLAY_SUPPORT | ||
223 | If enabled, cocos2d supports retina display. | ||
224 | For performance reasons, it's recommended disable it in games without retina display support, like iPad only games. | ||
225 | |||
226 | To enable set it to 1. Use 0 to disable it. Enabled by default. | ||
227 | |||
228 | @since v0.99.5 | ||
229 | */ | ||
230 | #ifndef CC_RETINA_DISPLAY_SUPPORT | ||
231 | #define CC_RETINA_DISPLAY_SUPPORT 1 | ||
232 | #endif | ||
233 | |||
234 | /** @def CC_RETINA_DISPLAY_FILENAME_SUFFIX | ||
235 | It's the suffix that will be appended to the files in order to load "retina display" images. | ||
236 | |||
237 | On an iPhone4 with Retina Display support enabled, the file @"sprite-hd.png" will be loaded instead of @"sprite.png". | ||
238 | If the file doesn't exist it will use the non-retina display image. | ||
239 | |||
240 | Platforms: Only used on Retina Display devices like iPhone 4. | ||
241 | |||
242 | @since v0.99.5 | ||
243 | */ | ||
244 | #ifndef CC_RETINA_DISPLAY_FILENAME_SUFFIX | ||
245 | #define CC_RETINA_DISPLAY_FILENAME_SUFFIX @"-hd" | ||
246 | #endif | ||
247 | |||
248 | /** @def CC_USE_LA88_LABELS_ON_NEON_ARCH | ||
249 | If enabled, it will use LA88 (16-bit textures) on Neon devices for CCLabelTTF objects. | ||
250 | If it is disabled, or if it is used on another architecture it will use A8 (8-bit textures). | ||
251 | On Neon devices, LA88 textures are 6% faster than A8 textures, but then will consume 2x memory. | ||
252 | |||
253 | This feature is disabled by default. | ||
254 | |||
255 | Platforms: Only used on ARM Neon architectures like iPhone 3GS or newer and iPad. | ||
256 | |||
257 | @since v0.99.5 | ||
258 | */ | ||
259 | #ifndef CC_USE_LA88_LABELS_ON_NEON_ARCH | ||
260 | #define CC_USE_LA88_LABELS_ON_NEON_ARCH 0 | ||
261 | #endif | ||
262 | |||
263 | /** @def CC_SPRITE_DEBUG_DRAW | ||
264 | If enabled, all subclasses of CCSprite will draw a bounding box | ||
265 | Useful for debugging purposes only. It is recommened to leave it disabled. | ||
266 | |||
267 | To enable set it to a value different than 0. Disabled by default: | ||
268 | 0 -- disabled | ||
269 | 1 -- draw bounding box | ||
270 | 2 -- draw texture box | ||
271 | */ | ||
272 | #ifndef CC_SPRITE_DEBUG_DRAW | ||
273 | #define CC_SPRITE_DEBUG_DRAW 0 | ||
274 | #endif | ||
275 | |||
276 | /** @def CC_SPRITEBATCHNODE_DEBUG_DRAW | ||
277 | If enabled, all subclasses of CCSprite that are rendered using an CCSpriteBatchNode draw a bounding box. | ||
278 | Useful for debugging purposes only. It is recommened to leave it disabled. | ||
279 | |||
280 | To enable set it to a value different than 0. Disabled by default. | ||
281 | */ | ||
282 | #ifndef CC_SPRITEBATCHNODE_DEBUG_DRAW | ||
283 | #define CC_SPRITEBATCHNODE_DEBUG_DRAW 0 | ||
284 | #endif | ||
285 | |||
286 | /** @def CC_LABELBMFONT_DEBUG_DRAW | ||
287 | If enabled, all subclasses of CCLabelBMFont will draw a bounding box | ||
288 | Useful for debugging purposes only. It is recommened to leave it disabled. | ||
289 | |||
290 | To enable set it to a value different than 0. Disabled by default. | ||
291 | */ | ||
292 | #ifndef CC_LABELBMFONT_DEBUG_DRAW | ||
293 | #define CC_LABELBMFONT_DEBUG_DRAW 0 | ||
294 | #endif | ||
295 | |||
296 | /** @def CC_LABELBMFONT_DEBUG_DRAW | ||
297 | If enabled, all subclasses of CCLabeltAtlas will draw a bounding box | ||
298 | Useful for debugging purposes only. It is recommened to leave it disabled. | ||
299 | |||
300 | To enable set it to a value different than 0. Disabled by default. | ||
301 | */ | ||
302 | #ifndef CC_LABELATLAS_DEBUG_DRAW | ||
303 | #define CC_LABELATLAS_DEBUG_DRAW 0 | ||
304 | #endif | ||
305 | |||
306 | /** @def CC_ENABLE_PROFILERS | ||
307 | If enabled, will activate various profilers withing cocos2d. This statistical data will be output to the console | ||
308 | once per second showing average time (in milliseconds) required to execute the specific routine(s). | ||
309 | Useful for debugging purposes only. It is recommened to leave it disabled. | ||
310 | |||
311 | To enable set it to a value different than 0. Disabled by default. | ||
312 | */ | ||
313 | #ifndef CC_ENABLE_PROFILERS | ||
314 | #define CC_ENABLE_PROFILERS 0 | ||
315 | #endif | ||
316 | |||
317 | // | ||
318 | // DON'T edit this macro. | ||
319 | // | ||
320 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
321 | |||
322 | #if CC_RETINA_DISPLAY_SUPPORT | ||
323 | #define CC_IS_RETINA_DISPLAY_SUPPORTED 1 | ||
324 | #else | ||
325 | #define CC_IS_RETINA_DISPLAY_SUPPORTED 0 | ||
326 | #endif | ||
327 | |||
328 | #elif __MAC_OS_X_VERSION_MAX_ALLOWED | ||
329 | |||
330 | #define CC_IS_RETINA_DISPLAY_SUPPORTED 0 | ||
331 | |||
332 | #endif | ||
333 | |||
334 | |||
diff --git a/libs/cocos2d/ccMacros.h b/libs/cocos2d/ccMacros.h new file mode 100755 index 0000000..4e08725 --- /dev/null +++ b/libs/cocos2d/ccMacros.h | |||
@@ -0,0 +1,253 @@ | |||
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 | #import <math.h> | ||
28 | #import "ccConfig.h" | ||
29 | |||
30 | #import <Foundation/Foundation.h> | ||
31 | #import <Availability.h> | ||
32 | |||
33 | /** | ||
34 | @file | ||
35 | cocos2d helper macros | ||
36 | */ | ||
37 | |||
38 | /* | ||
39 | * if COCOS2D_DEBUG is not defined, or if it is 0 then | ||
40 | * all CCLOGXXX macros will be disabled | ||
41 | * | ||
42 | * if COCOS2D_DEBUG==1 then: | ||
43 | * CCLOG() will be enabled | ||
44 | * CCLOGERROR() will be enabled | ||
45 | * CCLOGINFO() will be disabled | ||
46 | * | ||
47 | * if COCOS2D_DEBUG==2 or higher then: | ||
48 | * CCLOG() will be enabled | ||
49 | * CCLOGERROR() will be enabled | ||
50 | * CCLOGINFO() will be enabled | ||
51 | */ | ||
52 | #if !defined(COCOS2D_DEBUG) || COCOS2D_DEBUG == 0 | ||
53 | #define CCLOG(...) do {} while (0) | ||
54 | #define CCLOGINFO(...) do {} while (0) | ||
55 | #define CCLOGERROR(...) do {} while (0) | ||
56 | |||
57 | #elif COCOS2D_DEBUG == 1 | ||
58 | #define CCLOG(...) NSLog(__VA_ARGS__) | ||
59 | #define CCLOGERROR(...) NSLog(__VA_ARGS__) | ||
60 | #define CCLOGINFO(...) do {} while (0) | ||
61 | |||
62 | #elif COCOS2D_DEBUG > 1 | ||
63 | #define CCLOG(...) NSLog(__VA_ARGS__) | ||
64 | #define CCLOGERROR(...) NSLog(__VA_ARGS__) | ||
65 | #define CCLOGINFO(...) NSLog(__VA_ARGS__) | ||
66 | #endif // COCOS2D_DEBUG | ||
67 | |||
68 | /** @def CC_SWAP | ||
69 | simple macro that swaps 2 variables | ||
70 | */ | ||
71 | #define CC_SWAP( x, y ) \ | ||
72 | ({ __typeof__(x) temp = (x); \ | ||
73 | x = y; y = temp; \ | ||
74 | }) | ||
75 | |||
76 | |||
77 | /** @def CCRANDOM_MINUS1_1 | ||
78 | returns a random float between -1 and 1 | ||
79 | */ | ||
80 | #define CCRANDOM_MINUS1_1() ((random() / (float)0x3fffffff )-1.0f) | ||
81 | |||
82 | /** @def CCRANDOM_0_1 | ||
83 | returns a random float between 0 and 1 | ||
84 | */ | ||
85 | #define CCRANDOM_0_1() ((random() / (float)0x7fffffff )) | ||
86 | |||
87 | /** @def CC_DEGREES_TO_RADIANS | ||
88 | converts degrees to radians | ||
89 | */ | ||
90 | #define CC_DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__) * 0.01745329252f) // PI / 180 | ||
91 | |||
92 | /** @def CC_RADIANS_TO_DEGREES | ||
93 | converts radians to degrees | ||
94 | */ | ||
95 | #define CC_RADIANS_TO_DEGREES(__ANGLE__) ((__ANGLE__) * 57.29577951f) // PI * 180 | ||
96 | |||
97 | /** @def CC_BLEND_SRC | ||
98 | default gl blend src function. Compatible with premultiplied alpha images. | ||
99 | */ | ||
100 | #if CC_OPTIMIZE_BLEND_FUNC_FOR_PREMULTIPLIED_ALPHA | ||
101 | #define CC_BLEND_SRC GL_ONE | ||
102 | #define CC_BLEND_DST GL_ONE_MINUS_SRC_ALPHA | ||
103 | #else | ||
104 | #define CC_BLEND_SRC GL_SRC_ALPHA | ||
105 | #define CC_BLEND_DST GL_ONE_MINUS_SRC_ALPHA | ||
106 | #endif // ! CC_OPTIMIZE_BLEND_FUNC_FOR_PREMULTIPLIED_ALPHA | ||
107 | |||
108 | /** @def CC_ENABLE_DEFAULT_GL_STATES | ||
109 | GL states that are enabled: | ||
110 | - GL_TEXTURE_2D | ||
111 | - GL_VERTEX_ARRAY | ||
112 | - GL_TEXTURE_COORD_ARRAY | ||
113 | - GL_COLOR_ARRAY | ||
114 | */ | ||
115 | #define CC_ENABLE_DEFAULT_GL_STATES() { \ | ||
116 | glEnableClientState(GL_VERTEX_ARRAY); \ | ||
117 | glEnableClientState(GL_COLOR_ARRAY); \ | ||
118 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); \ | ||
119 | glEnable(GL_TEXTURE_2D); \ | ||
120 | } | ||
121 | |||
122 | /** @def CC_DISABLE_DEFAULT_GL_STATES | ||
123 | Disable default GL states: | ||
124 | - GL_TEXTURE_2D | ||
125 | - GL_VERTEX_ARRAY | ||
126 | - GL_TEXTURE_COORD_ARRAY | ||
127 | - GL_COLOR_ARRAY | ||
128 | */ | ||
129 | #define CC_DISABLE_DEFAULT_GL_STATES() { \ | ||
130 | glDisable(GL_TEXTURE_2D); \ | ||
131 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); \ | ||
132 | glDisableClientState(GL_COLOR_ARRAY); \ | ||
133 | glDisableClientState(GL_VERTEX_ARRAY); \ | ||
134 | } | ||
135 | |||
136 | /** @def CC_DIRECTOR_INIT | ||
137 | - Initializes an EAGLView with 0-bit depth format, and RGB565 render buffer. | ||
138 | - The EAGLView view will have multiple touches disabled. | ||
139 | - It will create a UIWindow and it will assign it the 'window' variable. 'window' must be declared before calling this marcro. | ||
140 | - It will parent the EAGLView to the created window | ||
141 | - If the firmware >= 3.1 it will create a Display Link Director. Else it will create an NSTimer director. | ||
142 | - It will try to run at 60 FPS. | ||
143 | - The FPS won't be displayed. | ||
144 | - The orientation will be portrait. | ||
145 | - It will connect the director with the EAGLView. | ||
146 | |||
147 | IMPORTANT: If you want to use another type of render buffer (eg: RGBA8) | ||
148 | or if you want to use a 16-bit or 24-bit depth buffer, you should NOT | ||
149 | use this macro. Instead, you should create the EAGLView manually. | ||
150 | |||
151 | @since v0.99.4 | ||
152 | */ | ||
153 | |||
154 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
155 | |||
156 | #define CC_DIRECTOR_INIT() \ | ||
157 | do { \ | ||
158 | window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; \ | ||
159 | if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] ) \ | ||
160 | [CCDirector setDirectorType:kCCDirectorTypeNSTimer]; \ | ||
161 | CCDirector *__director = [CCDirector sharedDirector]; \ | ||
162 | [__director setDeviceOrientation:kCCDeviceOrientationPortrait]; \ | ||
163 | [__director setDisplayFPS:NO]; \ | ||
164 | [__director setAnimationInterval:1.0/60]; \ | ||
165 | EAGLView *__glView = [EAGLView viewWithFrame:[window bounds] \ | ||
166 | pixelFormat:kEAGLColorFormatRGB565 \ | ||
167 | depthFormat:0 /* GL_DEPTH_COMPONENT24_OES */ \ | ||
168 | preserveBackbuffer:NO \ | ||
169 | sharegroup:nil \ | ||
170 | multiSampling:NO \ | ||
171 | numberOfSamples:0 \ | ||
172 | ]; \ | ||
173 | [__director setOpenGLView:__glView]; \ | ||
174 | [window addSubview:__glView]; \ | ||
175 | [window makeKeyAndVisible]; \ | ||
176 | } while(0) | ||
177 | |||
178 | |||
179 | #elif __MAC_OS_X_VERSION_MAX_ALLOWED | ||
180 | |||
181 | #import "Platforms/Mac/MacWindow.h" | ||
182 | |||
183 | #define CC_DIRECTOR_INIT(__WINSIZE__) \ | ||
184 | do { \ | ||
185 | NSRect frameRect = NSMakeRect(0, 0, (__WINSIZE__).width, (__WINSIZE__).height); \ | ||
186 | self.window = [[MacWindow alloc] initWithFrame:frameRect fullscreen:NO]; \ | ||
187 | self.glView = [[MacGLView alloc] initWithFrame:frameRect shareContext:nil]; \ | ||
188 | [self.window setContentView:self.glView]; \ | ||
189 | CCDirector *__director = [CCDirector sharedDirector]; \ | ||
190 | [__director setDisplayFPS:NO]; \ | ||
191 | [__director setOpenGLView:self.glView]; \ | ||
192 | [(CCDirectorMac*)__director setOriginalWinSize:__WINSIZE__]; \ | ||
193 | [self.window makeMainWindow]; \ | ||
194 | [self.window makeKeyAndOrderFront:self]; \ | ||
195 | } while(0) | ||
196 | |||
197 | #endif | ||
198 | |||
199 | |||
200 | /** @def CC_DIRECTOR_END | ||
201 | Stops and removes the director from memory. | ||
202 | Removes the EAGLView from its parent | ||
203 | |||
204 | @since v0.99.4 | ||
205 | */ | ||
206 | #define CC_DIRECTOR_END() \ | ||
207 | do { \ | ||
208 | CCDirector *__director = [CCDirector sharedDirector]; \ | ||
209 | CC_GLVIEW *__view = [__director openGLView]; \ | ||
210 | [__view removeFromSuperview]; \ | ||
211 | [__director end]; \ | ||
212 | } while(0) | ||
213 | |||
214 | |||
215 | #if CC_IS_RETINA_DISPLAY_SUPPORTED | ||
216 | |||
217 | /****************************/ | ||
218 | /** RETINA DISPLAY ENABLED **/ | ||
219 | /****************************/ | ||
220 | |||
221 | /** @def CC_CONTENT_SCALE_FACTOR | ||
222 | On Mac it returns 1; | ||
223 | On iPhone it returns 2 if RetinaDisplay is On. Otherwise it returns 1 | ||
224 | */ | ||
225 | #import "Platforms/iOS/CCDirectorIOS.h" | ||
226 | #define CC_CONTENT_SCALE_FACTOR() __ccContentScaleFactor | ||
227 | |||
228 | |||
229 | /** @def CC_RECT_PIXELS_TO_POINTS | ||
230 | Converts a rect in pixels to points | ||
231 | */ | ||
232 | #define CC_RECT_PIXELS_TO_POINTS(__pixels__) \ | ||
233 | CGRectMake( (__pixels__).origin.x / CC_CONTENT_SCALE_FACTOR(), (__pixels__).origin.y / CC_CONTENT_SCALE_FACTOR(), \ | ||
234 | (__pixels__).size.width / CC_CONTENT_SCALE_FACTOR(), (__pixels__).size.height / CC_CONTENT_SCALE_FACTOR() ) | ||
235 | |||
236 | /** @def CC_RECT_POINTS_TO_PIXELS | ||
237 | Converts a rect in points to pixels | ||
238 | */ | ||
239 | #define CC_RECT_POINTS_TO_PIXELS(__points__) \ | ||
240 | CGRectMake( (__points__).origin.x * CC_CONTENT_SCALE_FACTOR(), (__points__).origin.y * CC_CONTENT_SCALE_FACTOR(), \ | ||
241 | (__points__).size.width * CC_CONTENT_SCALE_FACTOR(), (__points__).size.height * CC_CONTENT_SCALE_FACTOR() ) | ||
242 | |||
243 | #else // retina disabled | ||
244 | |||
245 | /*****************************/ | ||
246 | /** RETINA DISPLAY DISABLED **/ | ||
247 | /*****************************/ | ||
248 | |||
249 | #define CC_CONTENT_SCALE_FACTOR() 1 | ||
250 | #define CC_RECT_PIXELS_TO_POINTS(__pixels__) __pixels__ | ||
251 | #define CC_RECT_POINTS_TO_PIXELS(__points__) __points__ | ||
252 | |||
253 | #endif // CC_IS_RETINA_DISPLAY_SUPPORTED | ||
diff --git a/libs/cocos2d/ccTypes.h b/libs/cocos2d/ccTypes.h new file mode 100755 index 0000000..46917b3 --- /dev/null +++ b/libs/cocos2d/ccTypes.h | |||
@@ -0,0 +1,287 @@ | |||
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 | @file | ||
29 | cocos2d (cc) types | ||
30 | */ | ||
31 | |||
32 | #import <Availability.h> | ||
33 | #import <Foundation/Foundation.h> | ||
34 | |||
35 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
36 | #import <CoreGraphics/CGGeometry.h> // CGPoint | ||
37 | #endif | ||
38 | |||
39 | #import "Platforms/CCGL.h" | ||
40 | |||
41 | /** RGB color composed of bytes 3 bytes | ||
42 | @since v0.8 | ||
43 | */ | ||
44 | typedef struct _ccColor3B | ||
45 | { | ||
46 | GLubyte r; | ||
47 | GLubyte g; | ||
48 | GLubyte b; | ||
49 | } ccColor3B; | ||
50 | |||
51 | //! helper macro that creates an ccColor3B type | ||
52 | static inline ccColor3B | ||
53 | ccc3(const GLubyte r, const GLubyte g, const GLubyte b) | ||
54 | { | ||
55 | ccColor3B c = {r, g, b}; | ||
56 | return c; | ||
57 | } | ||
58 | //ccColor3B predefined colors | ||
59 | //! White color (255,255,255) | ||
60 | static const ccColor3B ccWHITE = {255,255,255}; | ||
61 | //! Yellow color (255,255,0) | ||
62 | static const ccColor3B ccYELLOW = {255,255,0}; | ||
63 | //! Blue color (0,0,255) | ||
64 | static const ccColor3B ccBLUE = {0,0,255}; | ||
65 | //! Green Color (0,255,0) | ||
66 | static const ccColor3B ccGREEN = {0,255,0}; | ||
67 | //! Red Color (255,0,0,) | ||
68 | static const ccColor3B ccRED = {255,0,0}; | ||
69 | //! Magenta Color (255,0,255) | ||
70 | static const ccColor3B ccMAGENTA = {255,0,255}; | ||
71 | //! Black Color (0,0,0) | ||
72 | static const ccColor3B ccBLACK = {0,0,0}; | ||
73 | //! Orange Color (255,127,0) | ||
74 | static const ccColor3B ccORANGE = {255,127,0}; | ||
75 | //! Gray Color (166,166,166) | ||
76 | static const ccColor3B ccGRAY = {166,166,166}; | ||
77 | |||
78 | /** RGBA color composed of 4 bytes | ||
79 | @since v0.8 | ||
80 | */ | ||
81 | typedef struct _ccColor4B | ||
82 | { | ||
83 | GLubyte r; | ||
84 | GLubyte g; | ||
85 | GLubyte b; | ||
86 | GLubyte a; | ||
87 | } ccColor4B; | ||
88 | //! helper macro that creates an ccColor4B type | ||
89 | static inline ccColor4B | ||
90 | ccc4(const GLubyte r, const GLubyte g, const GLubyte b, const GLubyte o) | ||
91 | { | ||
92 | ccColor4B c = {r, g, b, o}; | ||
93 | return c; | ||
94 | } | ||
95 | |||
96 | |||
97 | /** RGBA color composed of 4 floats | ||
98 | @since v0.8 | ||
99 | */ | ||
100 | typedef struct _ccColor4F { | ||
101 | GLfloat r; | ||
102 | GLfloat g; | ||
103 | GLfloat b; | ||
104 | GLfloat a; | ||
105 | } ccColor4F; | ||
106 | |||
107 | /** Returns a ccColor4F from a ccColor3B. Alpha will be 1. | ||
108 | @since v0.99.1 | ||
109 | */ | ||
110 | static inline ccColor4F ccc4FFromccc3B(ccColor3B c) | ||
111 | { | ||
112 | return (ccColor4F){c.r/255.f, c.g/255.f, c.b/255.f, 1.f}; | ||
113 | } | ||
114 | |||
115 | /** Returns a ccColor4F from a ccColor4B. | ||
116 | @since v0.99.1 | ||
117 | */ | ||
118 | static inline ccColor4F ccc4FFromccc4B(ccColor4B c) | ||
119 | { | ||
120 | return (ccColor4F){c.r/255.f, c.g/255.f, c.b/255.f, c.a/255.f}; | ||
121 | } | ||
122 | |||
123 | /** returns YES if both ccColor4F are equal. Otherwise it returns NO. | ||
124 | @since v0.99.1 | ||
125 | */ | ||
126 | static inline BOOL ccc4FEqual(ccColor4F a, ccColor4F b) | ||
127 | { | ||
128 | return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; | ||
129 | } | ||
130 | |||
131 | /** A vertex composed of 2 GLfloats: x, y | ||
132 | @since v0.8 | ||
133 | */ | ||
134 | typedef struct _ccVertex2F | ||
135 | { | ||
136 | GLfloat x; | ||
137 | GLfloat y; | ||
138 | } ccVertex2F; | ||
139 | |||
140 | /** A vertex composed of 2 floats: x, y | ||
141 | @since v0.8 | ||
142 | */ | ||
143 | typedef struct _ccVertex3F | ||
144 | { | ||
145 | GLfloat x; | ||
146 | GLfloat y; | ||
147 | GLfloat z; | ||
148 | } ccVertex3F; | ||
149 | |||
150 | /** A texcoord composed of 2 floats: u, y | ||
151 | @since v0.8 | ||
152 | */ | ||
153 | typedef struct _ccTex2F { | ||
154 | GLfloat u; | ||
155 | GLfloat v; | ||
156 | } ccTex2F; | ||
157 | |||
158 | |||
159 | //! Point Sprite component | ||
160 | typedef struct _ccPointSprite | ||
161 | { | ||
162 | ccVertex2F pos; // 8 bytes | ||
163 | ccColor4B color; // 4 bytes | ||
164 | GLfloat size; // 4 bytes | ||
165 | } ccPointSprite; | ||
166 | |||
167 | //! A 2D Quad. 4 * 2 floats | ||
168 | typedef struct _ccQuad2 { | ||
169 | ccVertex2F tl; | ||
170 | ccVertex2F tr; | ||
171 | ccVertex2F bl; | ||
172 | ccVertex2F br; | ||
173 | } ccQuad2; | ||
174 | |||
175 | |||
176 | //! A 3D Quad. 4 * 3 floats | ||
177 | typedef struct _ccQuad3 { | ||
178 | ccVertex3F bl; | ||
179 | ccVertex3F br; | ||
180 | ccVertex3F tl; | ||
181 | ccVertex3F tr; | ||
182 | } ccQuad3; | ||
183 | |||
184 | //! A 2D grid size | ||
185 | typedef struct _ccGridSize | ||
186 | { | ||
187 | NSInteger x; | ||
188 | NSInteger y; | ||
189 | } ccGridSize; | ||
190 | |||
191 | //! helper function to create a ccGridSize | ||
192 | static inline ccGridSize | ||
193 | ccg(const NSInteger x, const NSInteger y) | ||
194 | { | ||
195 | ccGridSize v = {x, y}; | ||
196 | return v; | ||
197 | } | ||
198 | |||
199 | //! a Point with a vertex point, a tex coord point and a color 4B | ||
200 | typedef struct _ccV2F_C4B_T2F | ||
201 | { | ||
202 | //! vertices (2F) | ||
203 | ccVertex2F vertices; | ||
204 | //! colors (4B) | ||
205 | ccColor4B colors; | ||
206 | //! tex coords (2F) | ||
207 | ccTex2F texCoords; | ||
208 | } ccV2F_C4B_T2F; | ||
209 | |||
210 | //! a Point with a vertex point, a tex coord point and a color 4F | ||
211 | typedef struct _ccV2F_C4F_T2F | ||
212 | { | ||
213 | //! vertices (2F) | ||
214 | ccVertex2F vertices; | ||
215 | //! colors (4F) | ||
216 | ccColor4F colors; | ||
217 | //! tex coords (2F) | ||
218 | ccTex2F texCoords; | ||
219 | } ccV2F_C4F_T2F; | ||
220 | |||
221 | //! a Point with a vertex point, a tex coord point and a color 4B | ||
222 | typedef struct _ccV3F_C4B_T2F | ||
223 | { | ||
224 | //! vertices (3F) | ||
225 | ccVertex3F vertices; // 12 bytes | ||
226 | // char __padding__[4]; | ||
227 | |||
228 | //! colors (4B) | ||
229 | ccColor4B colors; // 4 bytes | ||
230 | // char __padding2__[4]; | ||
231 | |||
232 | // tex coords (2F) | ||
233 | ccTex2F texCoords; // 8 byts | ||
234 | } ccV3F_C4B_T2F; | ||
235 | |||
236 | //! 4 ccVertex2FTex2FColor4B Quad | ||
237 | typedef struct _ccV2F_C4B_T2F_Quad | ||
238 | { | ||
239 | //! bottom left | ||
240 | ccV2F_C4B_T2F bl; | ||
241 | //! bottom right | ||
242 | ccV2F_C4B_T2F br; | ||
243 | //! top left | ||
244 | ccV2F_C4B_T2F tl; | ||
245 | //! top right | ||
246 | ccV2F_C4B_T2F tr; | ||
247 | } ccV2F_C4B_T2F_Quad; | ||
248 | |||
249 | //! 4 ccVertex3FTex2FColor4B | ||
250 | typedef struct _ccV3F_C4B_T2F_Quad | ||
251 | { | ||
252 | //! top left | ||
253 | ccV3F_C4B_T2F tl; | ||
254 | //! bottom left | ||
255 | ccV3F_C4B_T2F bl; | ||
256 | //! top right | ||
257 | ccV3F_C4B_T2F tr; | ||
258 | //! bottom right | ||
259 | ccV3F_C4B_T2F br; | ||
260 | } ccV3F_C4B_T2F_Quad; | ||
261 | |||
262 | //! 4 ccVertex2FTex2FColor4F Quad | ||
263 | typedef struct _ccV2F_C4F_T2F_Quad | ||
264 | { | ||
265 | //! bottom left | ||
266 | ccV2F_C4F_T2F bl; | ||
267 | //! bottom right | ||
268 | ccV2F_C4F_T2F br; | ||
269 | //! top left | ||
270 | ccV2F_C4F_T2F tl; | ||
271 | //! top right | ||
272 | ccV2F_C4F_T2F tr; | ||
273 | } ccV2F_C4F_T2F_Quad; | ||
274 | |||
275 | //! Blend Function used for textures | ||
276 | typedef struct _ccBlendFunc | ||
277 | { | ||
278 | //! source blend function | ||
279 | GLenum src; | ||
280 | //! destination blend function | ||
281 | GLenum dst; | ||
282 | } ccBlendFunc; | ||
283 | |||
284 | //! delta time type | ||
285 | //! if you want more resolution redefine it as a double | ||
286 | typedef float ccTime; | ||
287 | //typedef double ccTime; | ||
diff --git a/libs/cocos2d/cocos2d.h b/libs/cocos2d/cocos2d.h new file mode 100755 index 0000000..fed2a9b --- /dev/null +++ b/libs/cocos2d/cocos2d.h | |||
@@ -0,0 +1,161 @@ | |||
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 | /** @mainpage cocos2d for iPhone API reference | ||
27 | * | ||
28 | * @image html Icon.png | ||
29 | * | ||
30 | * @section intro Introduction | ||
31 | * This is cocos2d API reference | ||
32 | * | ||
33 | * The programming guide is hosted here: http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:index | ||
34 | * | ||
35 | * <hr> | ||
36 | * | ||
37 | * @todo A native english speaker should check the grammar. We need your help! | ||
38 | * | ||
39 | */ | ||
40 | |||
41 | // 0x00 HI ME LO | ||
42 | // 00 01 00 00 | ||
43 | #define COCOS2D_VERSION 0x00010000 | ||
44 | |||
45 | #import <Availability.h> | ||
46 | |||
47 | // | ||
48 | // all cocos2d include files | ||
49 | // | ||
50 | #import "ccConfig.h" // should be included first | ||
51 | |||
52 | #import "CCActionManager.h" | ||
53 | #import "CCAction.h" | ||
54 | #import "CCActionInstant.h" | ||
55 | #import "CCActionInterval.h" | ||
56 | #import "CCActionEase.h" | ||
57 | #import "CCActionCamera.h" | ||
58 | #import "CCActionTween.h" | ||
59 | #import "CCActionEase.h" | ||
60 | #import "CCActionTiledGrid.h" | ||
61 | #import "CCActionGrid3D.h" | ||
62 | #import "CCActionGrid.h" | ||
63 | #import "CCActionProgressTimer.h" | ||
64 | #import "CCActionPageTurn3D.h" | ||
65 | |||
66 | #import "CCAnimation.h" | ||
67 | #import "CCAnimationCache.h" | ||
68 | #import "CCSprite.h" | ||
69 | #import "CCSpriteFrame.h" | ||
70 | #import "CCSpriteBatchNode.h" | ||
71 | #import "CCSpriteFrameCache.h" | ||
72 | |||
73 | #import "CCLabelTTF.h" | ||
74 | #import "CCLabelBMFont.h" | ||
75 | #import "CCLabelAtlas.h" | ||
76 | |||
77 | #import "CCParticleSystem.h" | ||
78 | #import "CCParticleSystemPoint.h" | ||
79 | #import "CCParticleSystemQuad.h" | ||
80 | #import "CCParticleExamples.h" | ||
81 | |||
82 | #import "CCTexture2D.h" | ||
83 | #import "CCTexturePVR.h" | ||
84 | #import "CCTextureCache.h" | ||
85 | #import "CCTextureAtlas.h" | ||
86 | |||
87 | #import "CCTransition.h" | ||
88 | #import "CCTransitionPageTurn.h" | ||
89 | #import "CCTransitionRadial.h" | ||
90 | |||
91 | #import "CCTMXTiledMap.h" | ||
92 | #import "CCTMXLayer.h" | ||
93 | #import "CCTMXObjectGroup.h" | ||
94 | #import "CCTMXXMLParser.h" | ||
95 | #import "CCTileMapAtlas.h" | ||
96 | |||
97 | #import "CCLayer.h" | ||
98 | #import "CCMenu.h" | ||
99 | #import "CCMenuItem.h" | ||
100 | #import "CCDrawingPrimitives.h" | ||
101 | #import "CCScene.h" | ||
102 | #import "CCScheduler.h" | ||
103 | #import "CCBlockSupport.h" | ||
104 | #import "CCCamera.h" | ||
105 | #import "CCProtocols.h" | ||
106 | #import "CCNode.h" | ||
107 | #import "CCDirector.h" | ||
108 | #import "CCAtlasNode.h" | ||
109 | #import "CCGrabber.h" | ||
110 | #import "CCGrid.h" | ||
111 | #import "CCParallaxNode.h" | ||
112 | #import "CCRenderTexture.h" | ||
113 | #import "CCMotionStreak.h" | ||
114 | #import "CCConfiguration.h" | ||
115 | |||
116 | // | ||
117 | // cocos2d macros | ||
118 | // | ||
119 | #import "ccTypes.h" | ||
120 | #import "ccMacros.h" | ||
121 | |||
122 | |||
123 | // Platform common | ||
124 | #import "Platforms/CCGL.h" | ||
125 | #import "Platforms/CCNS.h" | ||
126 | |||
127 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
128 | #import "Platforms/iOS/CCTouchDispatcher.h" | ||
129 | #import "Platforms/iOS/CCTouchDelegateProtocol.h" | ||
130 | #import "Platforms/iOS/CCTouchHandler.h" | ||
131 | #import "Platforms/iOS/EAGLView.h" | ||
132 | #import "Platforms/iOS/CCDirectorIOS.h" | ||
133 | |||
134 | #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) | ||
135 | #import "Platforms/Mac/MacGLView.h" | ||
136 | #import "Platforms/Mac/CCDirectorMac.h" | ||
137 | #endif | ||
138 | |||
139 | // | ||
140 | // cocos2d helper files | ||
141 | // | ||
142 | #import "Support/OpenGL_Internal.h" | ||
143 | #import "Support/CCFileUtils.h" | ||
144 | #import "Support/CGPointExtension.h" | ||
145 | #import "Support/ccCArray.h" | ||
146 | #import "Support/CCArray.h" | ||
147 | #import "Support/ccUtils.h" | ||
148 | |||
149 | #if CC_ENABLE_PROFILERS | ||
150 | #import "Support/CCProfiling.h" | ||
151 | #endif // CC_ENABLE_PROFILERS | ||
152 | |||
153 | |||
154 | // free functions | ||
155 | NSString * cocos2dVersion(void); | ||
156 | |||
157 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
158 | #ifndef __IPHONE_4_0 | ||
159 | #error "If you are targeting iPad, you should set BASE SDK = 4.0 (or 4.1, or 4.2), and set the 'iOS deploy target' = 3.2" | ||
160 | #endif | ||
161 | #endif | ||
diff --git a/libs/cocos2d/cocos2d.m b/libs/cocos2d/cocos2d.m new file mode 100755 index 0000000..8df3b6f --- /dev/null +++ b/libs/cocos2d/cocos2d.m | |||
@@ -0,0 +1,34 @@ | |||
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 | #import <Foundation/Foundation.h> | ||
28 | #import "cocos2d.h" | ||
29 | static NSString *version = @"cocos2d v1.0.0"; | ||
30 | |||
31 | NSString *cocos2dVersion() | ||
32 | { | ||
33 | return version; | ||
34 | } | ||
diff --git a/libs/cocoslive/CLScoreServerPost.h b/libs/cocoslive/CLScoreServerPost.h new file mode 100755 index 0000000..e782b90 --- /dev/null +++ b/libs/cocoslive/CLScoreServerPost.h | |||
@@ -0,0 +1,142 @@ | |||
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 | |||
29 | #import <UIKit/UIKit.h> | ||
30 | |||
31 | // for MD5 signing | ||
32 | #import <CommonCrypto/CommonDigest.h> | ||
33 | |||
34 | // cocoslive definitions | ||
35 | #import "cocoslive.h" | ||
36 | |||
37 | // Score Server protocol version | ||
38 | #define SCORE_SERVER_PROTOCOL_VERSION @"1.1" | ||
39 | |||
40 | // Server URL | ||
41 | #ifdef USE_LOCAL_SERVER | ||
42 | #define SCORE_SERVER_SEND_URL @"http://localhost:8080/api/post-score" | ||
43 | #define SCORE_SERVER_UPDATE_URL @"http://localhost:8080/api/update-score" | ||
44 | #else | ||
45 | #define SCORE_SERVER_SEND_URL @"http://fourislandscores.appspot.com/api/post-score" | ||
46 | #define SCORE_SERVER_UPDATE_URL @"http://fourislandscores.appspot.com/api/update-score" | ||
47 | #endif | ||
48 | |||
49 | /// Type of errors from the Post Score request | ||
50 | typedef enum { | ||
51 | /// post request successful | ||
52 | kPostStatusOK = 0, | ||
53 | /// post request failed to establish a connection. wi-fi isn't enabled. | ||
54 | /// Don't retry when this option is preset | ||
55 | kPostStatusConnectionFailed = 1, | ||
56 | /// post request failed to post the score. Server might be busy. | ||
57 | /// Retry is suggested | ||
58 | kPostStatusPostFailed = 2, | ||
59 | } tPostStatus; | ||
60 | |||
61 | enum { | ||
62 | //! Invalid Ranking. Valid rankins are from 1 to ... | ||
63 | kServerPostInvalidRanking = 0, | ||
64 | }; | ||
65 | |||
66 | /** | ||
67 | * Handles the Score Post to the cocos live server | ||
68 | */ | ||
69 | @interface CLScoreServerPost : NSObject { | ||
70 | /// game key. secret shared with the server. | ||
71 | /// used to sign the values to prevent spoofing. | ||
72 | NSString *gameKey; | ||
73 | |||
74 | /// game name, used as a login name. | ||
75 | NSString *gameName; | ||
76 | |||
77 | /// delegate instance of fetch score | ||
78 | id delegate; | ||
79 | |||
80 | /// ranking | ||
81 | NSUInteger ranking_; | ||
82 | |||
83 | /// score was updated | ||
84 | BOOL scoreDidUpdate_; | ||
85 | |||
86 | /// data received | ||
87 | NSMutableData *receivedData; | ||
88 | |||
89 | /// values to send in the POST | ||
90 | NSMutableArray *bodyValues; | ||
91 | |||
92 | /// status of the request | ||
93 | tPostStatus postStatus_; | ||
94 | |||
95 | /// mdt context | ||
96 | CC_MD5_CTX md5Ctx; | ||
97 | |||
98 | /// the connection | ||
99 | NSURLConnection *connection_; | ||
100 | } | ||
101 | |||
102 | /** status from the score post */ | ||
103 | @property (nonatomic,readonly) tPostStatus postStatus; | ||
104 | |||
105 | /** connection to the server */ | ||
106 | @property (nonatomic, retain) NSURLConnection *connection; | ||
107 | |||
108 | /** ranking of your score | ||
109 | @since v0.7.3 | ||
110 | */ | ||
111 | @property (nonatomic,readonly) NSUInteger ranking; | ||
112 | |||
113 | /** whether or not the score was updated | ||
114 | @since v0.7.3 | ||
115 | */ | ||
116 | @property (nonatomic,readonly) BOOL scoreDidUpdate; | ||
117 | |||
118 | /** creates a cocos server with a game name and a game key */ | ||
119 | +(id) serverWithGameName:(NSString*) name gameKey:(NSString*) key delegate:(id)delegate; | ||
120 | |||
121 | /** initializes a cocos server with a game name and a game key */ | ||
122 | -(id) initWithGameName:(NSString*) name gameKey:(NSString*) key delegate:(id)delegate; | ||
123 | |||
124 | /** send the scores to the server. A new entre will be created on the server */ | ||
125 | -(BOOL) sendScore: (NSDictionary*) dict; | ||
126 | |||
127 | /** | ||
128 | * Sends a score dictionary to the server for updating an existing entry by playername and device id, or creating a new one. | ||
129 | * The passed dictionary must contain a cc_playername key, otherwise it will raise and exception. | ||
130 | * @since v0.7.1 | ||
131 | */ | ||
132 | -(BOOL) updateScore: (NSDictionary*) dict; | ||
133 | |||
134 | @end | ||
135 | |||
136 | /** CocosLivePost protocol */ | ||
137 | @protocol CLPostDelegate <NSObject> | ||
138 | /** callback method that will be called if the post is successful */ | ||
139 | -(void) scorePostOk:(id) sender; | ||
140 | /** callback method that will be called if the post fails */ | ||
141 | -(void) scorePostFail:(id) sender; | ||
142 | @end | ||
diff --git a/libs/cocoslive/CLScoreServerPost.m b/libs/cocoslive/CLScoreServerPost.m new file mode 100755 index 0000000..43ee7b2 --- /dev/null +++ b/libs/cocoslive/CLScoreServerPost.m | |||
@@ -0,0 +1,335 @@ | |||
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 | #import "CLScoreServerPost.h" | ||
29 | #import "ccMacros.h" | ||
30 | |||
31 | // free function used to sort | ||
32 | NSInteger alphabeticSort(id string1, id string2, void *reverse); | ||
33 | |||
34 | NSInteger alphabeticSort(id string1, id string2, void *reverse) | ||
35 | { | ||
36 | if ((NSInteger *)reverse == NO) | ||
37 | return [string2 localizedCaseInsensitiveCompare:string1]; | ||
38 | return [string1 localizedCaseInsensitiveCompare:string2]; | ||
39 | } | ||
40 | |||
41 | |||
42 | @interface CLScoreServerPost (Private) | ||
43 | -(void) addValue:(NSString*)value key:(NSString*)key; | ||
44 | -(void) calculateHashAndAddValue:(id)value key:(NSString*)key; | ||
45 | -(NSString*) getHashForData; | ||
46 | -(NSData*) getBodyValues; | ||
47 | -(NSString*) encodeData:(NSString*)data; | ||
48 | -(NSMutableURLRequest *) scoreServerRequestWithURLString:(NSString *)url; | ||
49 | -(BOOL) submitScore:(NSDictionary*)dict forUpdate:(BOOL)isUpdate; | ||
50 | @end | ||
51 | |||
52 | |||
53 | @implementation CLScoreServerPost | ||
54 | |||
55 | @synthesize postStatus = postStatus_; | ||
56 | @synthesize ranking = ranking_; | ||
57 | @synthesize scoreDidUpdate = scoreDidUpdate_; | ||
58 | @synthesize connection = connection_; | ||
59 | |||
60 | +(id) serverWithGameName:(NSString*) name gameKey:(NSString*) key delegate:(id) delegate | ||
61 | { | ||
62 | return [[[self alloc] initWithGameName:name gameKey:key delegate:delegate] autorelease]; | ||
63 | } | ||
64 | |||
65 | -(id) initWithGameName:(NSString*) name gameKey:(NSString*) key delegate:(id)aDelegate | ||
66 | { | ||
67 | self = [super init]; | ||
68 | if( self ) { | ||
69 | gameKey = [key retain]; | ||
70 | gameName = [name retain]; | ||
71 | bodyValues = [[NSMutableArray arrayWithCapacity:5] retain]; | ||
72 | delegate = [aDelegate retain]; | ||
73 | receivedData = [[NSMutableData data] retain]; | ||
74 | |||
75 | ranking_ = kServerPostInvalidRanking; | ||
76 | } | ||
77 | |||
78 | return self; | ||
79 | } | ||
80 | |||
81 | -(void) dealloc | ||
82 | { | ||
83 | CCLOGINFO(@"deallocing %@", self); | ||
84 | [delegate release]; | ||
85 | [gameKey release]; | ||
86 | [gameName release]; | ||
87 | [bodyValues release]; | ||
88 | [receivedData release]; | ||
89 | [connection_ release]; | ||
90 | [super dealloc]; | ||
91 | } | ||
92 | |||
93 | |||
94 | #pragma mark ScoreServer send scores | ||
95 | -(BOOL) sendScore: (NSDictionary*) dict | ||
96 | { | ||
97 | return [self submitScore:dict forUpdate:NO]; | ||
98 | } | ||
99 | |||
100 | -(BOOL) updateScore: (NSDictionary*) dict | ||
101 | { | ||
102 | if (![dict objectForKey:@"cc_playername"]) { | ||
103 | // fail. cc_playername + cc_device_id are needed to update an score | ||
104 | [NSException raise:@"cocosLive:updateScore" format:@"cc_playername not found"]; | ||
105 | } | ||
106 | return [self submitScore:dict forUpdate:YES]; | ||
107 | } | ||
108 | |||
109 | -(BOOL) submitScore: (NSDictionary*)dict forUpdate:(BOOL)isUpdate | ||
110 | { | ||
111 | [receivedData setLength:0]; | ||
112 | [bodyValues removeAllObjects]; | ||
113 | |||
114 | // reset status | ||
115 | postStatus_ = kPostStatusOK; | ||
116 | |||
117 | // create the request | ||
118 | NSMutableURLRequest *post = [self scoreServerRequestWithURLString:(isUpdate ? SCORE_SERVER_UPDATE_URL : SCORE_SERVER_SEND_URL)]; | ||
119 | |||
120 | CC_MD5_Init( &md5Ctx); | ||
121 | |||
122 | // hash SHALL be calculated in certain order | ||
123 | NSArray *keys = [dict allKeys]; | ||
124 | int reverseSort = NO; | ||
125 | NSArray *sortedKeys = [keys sortedArrayUsingFunction:alphabeticSort context:&reverseSort]; | ||
126 | for( id key in sortedKeys ) | ||
127 | [self calculateHashAndAddValue:[dict objectForKey:key] key:key]; | ||
128 | |||
129 | // device id is hashed to prevent spoofing this same score from different devices | ||
130 | // one way to prevent a replay attack is to send cc_id & cc_time and use it as primary keys | ||
131 | |||
132 | [self addValue:[[UIDevice currentDevice] uniqueIdentifier] key:@"cc_device_id"]; | ||
133 | [self addValue:gameName key:@"cc_gamename"]; | ||
134 | [self addValue:[self getHashForData] key:@"cc_hash"]; | ||
135 | [self addValue:SCORE_SERVER_PROTOCOL_VERSION key:@"cc_prot_ver"]; | ||
136 | |||
137 | [post setHTTPBody: [self getBodyValues] ]; | ||
138 | |||
139 | // create the connection with the request | ||
140 | // and start loading the data | ||
141 | self.connection=[NSURLConnection connectionWithRequest:post delegate:self]; | ||
142 | |||
143 | if ( ! connection_) | ||
144 | return NO; | ||
145 | |||
146 | return YES; | ||
147 | } | ||
148 | |||
149 | -(NSMutableURLRequest *) scoreServerRequestWithURLString:(NSString *)url { | ||
150 | NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString: url] | ||
151 | cachePolicy:NSURLRequestUseProtocolCachePolicy | ||
152 | timeoutInterval:10.0]; | ||
153 | |||
154 | [request setHTTPMethod: @"POST"]; | ||
155 | [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; | ||
156 | return request; | ||
157 | } | ||
158 | |||
159 | -(void) calculateHashAndAddValue:(id) value key:(NSString*) key | ||
160 | { | ||
161 | NSString *val; | ||
162 | // value shall be a string or nsnumber | ||
163 | if( [value respondsToSelector:@selector(stringValue)] ) | ||
164 | val = [value stringValue]; | ||
165 | else if( [value isKindOfClass:[NSString class]] ) | ||
166 | val = value; | ||
167 | else | ||
168 | [NSException raise:@"Invalid format for value" format:@"Invalid format for value. addValue"]; | ||
169 | |||
170 | [self addValue:val key:key]; | ||
171 | |||
172 | const char * data = [val UTF8String]; | ||
173 | CC_MD5_Update( &md5Ctx, data, strlen(data) ); | ||
174 | } | ||
175 | |||
176 | -(void) addValue:(NSString*)value key:(NSString*) key | ||
177 | { | ||
178 | |||
179 | NSString *encodedValue = [self encodeData:value]; | ||
180 | NSString *encodedKey = [self encodeData:key]; | ||
181 | |||
182 | [bodyValues addObject: [NSString stringWithFormat:@"%@=%@", encodedKey, encodedValue] ]; | ||
183 | } | ||
184 | |||
185 | -(NSData*) getBodyValues { | ||
186 | NSMutableData *data = [[NSMutableData alloc] init]; | ||
187 | |||
188 | BOOL first=YES; | ||
189 | for( NSString *s in bodyValues ) { | ||
190 | if( !first) | ||
191 | [data appendBytes:"&" length:1]; | ||
192 | |||
193 | [data appendBytes:[s UTF8String] length:[s length]]; | ||
194 | first = NO; | ||
195 | } | ||
196 | |||
197 | return [data autorelease]; | ||
198 | } | ||
199 | |||
200 | -(NSString*) getHashForData | ||
201 | { | ||
202 | NSString *ret; | ||
203 | unsigned char pTempKey[16]; | ||
204 | |||
205 | // update the hash with the secret key | ||
206 | const char *data = [gameKey UTF8String]; | ||
207 | CC_MD5_Update(&md5Ctx, data, strlen(data)); | ||
208 | |||
209 | // then get the hash | ||
210 | CC_MD5_Final( pTempKey, &md5Ctx); | ||
211 | |||
212 | // NSData *nsdata = [NSData dataWithBytes:pTempKey length:16]; | ||
213 | ret = [NSString stringWithString:@""]; | ||
214 | for( int i=0;i<16;i++) { | ||
215 | ret = [NSString stringWithFormat:@"%@%02x", ret, pTempKey[i] ]; | ||
216 | } | ||
217 | |||
218 | return ret; | ||
219 | } | ||
220 | |||
221 | -(NSString*) encodeData:(NSString*) data | ||
222 | { | ||
223 | NSString *newData; | ||
224 | |||
225 | newData = [data stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; | ||
226 | |||
227 | // '&' and '=' should be encoded manually | ||
228 | newData = [newData stringByReplacingOccurrencesOfString:@"&" withString:@"%26"]; | ||
229 | newData = [newData stringByReplacingOccurrencesOfString:@"=" withString:@"%3D"]; | ||
230 | |||
231 | return newData; | ||
232 | } | ||
233 | |||
234 | #pragma mark NSURLConnection Delegate | ||
235 | |||
236 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response | ||
237 | { | ||
238 | // this method is called when the server has determined that it | ||
239 | // has enough information to create the NSURLResponse | ||
240 | |||
241 | // it can be called multiple times, for example in the case of a | ||
242 | // redirect, so each time we reset the data. | ||
243 | // receivedData is declared as a method instance elsewhere | ||
244 | [receivedData setLength:0]; | ||
245 | } | ||
246 | |||
247 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data | ||
248 | { | ||
249 | // append the new data to the receivedData | ||
250 | // receivedData is declared as a method instance elsewhere | ||
251 | [receivedData appendData:data]; | ||
252 | |||
253 | // NSString *dataString = [NSString stringWithCString:[data bytes] length: [data length]]; | ||
254 | // CCLOG( @"data: %@", dataString); | ||
255 | } | ||
256 | |||
257 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error | ||
258 | { | ||
259 | CCLOG(@"Connection failed"); | ||
260 | |||
261 | // wifi problems ? | ||
262 | postStatus_ = kPostStatusConnectionFailed; | ||
263 | |||
264 | // release the connection | ||
265 | self.connection = nil; | ||
266 | |||
267 | if( [delegate respondsToSelector:@selector(scorePostFail:) ] ) | ||
268 | [delegate scorePostFail:self]; | ||
269 | } | ||
270 | |||
271 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection | ||
272 | { | ||
273 | // release the connection | ||
274 | self.connection = nil; | ||
275 | |||
276 | // NSString *dataString = [NSString stringWithCString:[receivedData bytes] length: [receivedData length]]; | ||
277 | NSString *dataString = [NSString stringWithCString:[receivedData bytes] encoding: NSASCIIStringEncoding]; | ||
278 | |||
279 | if( [dataString hasPrefix:@"OK:"] ) { | ||
280 | // parse ranking and other possible answers | ||
281 | NSArray *values = [dataString componentsSeparatedByString:@":"]; | ||
282 | NSArray *answer = [ [values objectAtIndex:1] componentsSeparatedByString:@","]; | ||
283 | NSEnumerator *nse = [answer objectEnumerator]; | ||
284 | |||
285 | // Create a holder for each line we are going to work with | ||
286 | NSString *line; | ||
287 | |||
288 | // Loop through all the lines in the lines array processing each one | ||
289 | while( (line = [nse nextObject]) ) { | ||
290 | NSArray *keyvalue = [line componentsSeparatedByString:@"="]; | ||
291 | // NSLog(@"%@",keyvalue); | ||
292 | if( [[keyvalue objectAtIndex:0] isEqual:@"ranking"] ) { | ||
293 | ranking_ = [[keyvalue objectAtIndex:1] intValue]; | ||
294 | } else if( [[keyvalue objectAtIndex:0] isEqual:@"score_updated"] ) { | ||
295 | scoreDidUpdate_ = [[keyvalue objectAtIndex:1] boolValue]; | ||
296 | } | ||
297 | |||
298 | } | ||
299 | if( [delegate respondsToSelector:@selector(scorePostOk:) ] ) | ||
300 | [delegate scorePostOk:self]; | ||
301 | |||
302 | } else if( [dataString hasPrefix: @"OK"] ) { | ||
303 | |||
304 | // Ok | ||
305 | postStatus_ = kPostStatusOK; | ||
306 | |||
307 | if( [delegate respondsToSelector:@selector(scorePostOk:) ] ) | ||
308 | [delegate scorePostOk:self]; | ||
309 | |||
310 | |||
311 | } else { | ||
312 | |||
313 | NSLog(@"cocoslive: Post Score failed. Reason: %@", dataString); | ||
314 | |||
315 | // Error parsing answer | ||
316 | postStatus_ = kPostStatusPostFailed; | ||
317 | |||
318 | if( [delegate respondsToSelector:@selector(scorePostFail:) ] ) | ||
319 | [delegate scorePostFail:self]; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | -(NSURLRequest *)connection:(NSURLConnection *)connection | ||
324 | willSendRequest:(NSURLRequest *)request | ||
325 | redirectResponse:(NSURLResponse *)redirectResponse | ||
326 | { | ||
327 | NSURLRequest *newRequest=request; | ||
328 | if (redirectResponse) { | ||
329 | newRequest=nil; | ||
330 | } | ||
331 | |||
332 | return newRequest; | ||
333 | } | ||
334 | |||
335 | @end | ||
diff --git a/libs/cocoslive/CLScoreServerRequest.h b/libs/cocoslive/CLScoreServerRequest.h new file mode 100755 index 0000000..2002d4c --- /dev/null +++ b/libs/cocoslive/CLScoreServerRequest.h | |||
@@ -0,0 +1,122 @@ | |||
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 | |||
29 | #import <UIKit/UIKit.h> | ||
30 | |||
31 | // cocoslive definitions | ||
32 | #import "cocoslive.h" | ||
33 | |||
34 | // Server URL | ||
35 | #if USE_LOCAL_SERVER | ||
36 | #define SCORE_SERVER_REQUEST_URL @"http://localhost:8080/api/get-scores" | ||
37 | #define SCORE_SERVER_GETRANK_URL @"http://localhost:8080/api/get-rank-for-score" | ||
38 | #else | ||
39 | #define SCORE_SERVER_REQUEST_URL @"http://fourislandscores.appspot.com/api/get-scores" | ||
40 | #define SCORE_SERVER_GETRANK_URL @"http://fourislandscores.appspot.com/api/get-rank-for-score" | ||
41 | #endif | ||
42 | |||
43 | /** Type of predefined Query */ | ||
44 | typedef enum { | ||
45 | kQueryIgnore = 0, | ||
46 | kQueryDay = 1, | ||
47 | kQueryWeek = 2, | ||
48 | kQueryMonth = 3, | ||
49 | kQueryAllTime = 4, | ||
50 | } tQueryType; | ||
51 | |||
52 | /** Flags that can be added to the query */ | ||
53 | typedef enum { | ||
54 | kQueryFlagIgnore = 0, | ||
55 | kQueryFlagByCountry = 1 << 0, | ||
56 | kQueryFlagByDevice = 1 << 1, | ||
57 | } tQueryFlags; | ||
58 | |||
59 | /** | ||
60 | * Handles the Request Scores to the cocos live server | ||
61 | */ | ||
62 | @interface CLScoreServerRequest : NSObject { | ||
63 | |||
64 | /// game name, used as a login name. | ||
65 | NSString *gameName; | ||
66 | |||
67 | /// delegate instance of fetch score | ||
68 | id delegate; | ||
69 | |||
70 | // data received | ||
71 | NSMutableData *receivedData; | ||
72 | |||
73 | // To determine which delegate method will be called in connectionDidFinishLoading: of NSURLConnection Delegate | ||
74 | BOOL reqRankOnly; | ||
75 | |||
76 | /// the connection | ||
77 | NSURLConnection *connection_; | ||
78 | } | ||
79 | |||
80 | /** connection to the server */ | ||
81 | @property (nonatomic, retain) NSURLConnection *connection; | ||
82 | |||
83 | |||
84 | /** creates a ScoreServerRequest server with a game name*/ | ||
85 | +(id) serverWithGameName:(NSString*) name delegate:(id)delegate; | ||
86 | |||
87 | /** initializes a ScoreServerRequest with a game name*/ | ||
88 | -(id) initWithGameName:(NSString*) name delegate:(id)delegate; | ||
89 | |||
90 | /** request scores from server using a predefined query. This is an asyncronous request. | ||
91 | * limit: how many scores are being requested. Maximun is 100 | ||
92 | * flags: can be kQueryFlagByCountry (fetches only scores from country) | ||
93 | * category: an NSString. For example: 'easy', 'medium', 'type1'... When requesting scores, they can be filtered by this field. | ||
94 | */ | ||
95 | -(BOOL) requestScores: (tQueryType) type limit:(int)limit offset:(int)offset flags:(tQueryFlags)flags category:(NSString*)category; | ||
96 | |||
97 | /** request scores from server using a predefined query. This is an asyncronous request. | ||
98 | * limit: how many scores are being requested. Maximun is 100 | ||
99 | * flags: can be kQueryFlagByCountry (fetches only scores from country) | ||
100 | */ | ||
101 | -(BOOL) requestScores: (tQueryType) type limit:(int)limit offset:(int)offset flags:(tQueryFlags)flags; | ||
102 | |||
103 | /** parse the received JSON scores and convert it to objective-c objects */ | ||
104 | -(NSArray*) parseScores; | ||
105 | |||
106 | /** request rank for a given score using a predefined query. This is an asyncronous request. | ||
107 | * score: int for a score | ||
108 | * category: an NSString. For example: 'easy', 'medium', 'type1'... When requesting ranks, they can be filtered by this field. | ||
109 | */ | ||
110 | -(BOOL) requestRankForScore:(int)score andCategory:(NSString*)category; | ||
111 | |||
112 | /** It's actually not parsing anything, just returning int for a rank. Kept name PARSE for convinience with parseScores */ | ||
113 | -(int) parseRank; | ||
114 | |||
115 | @end | ||
116 | |||
117 | /** CocosLive Request protocol */ | ||
118 | @protocol CLRequestDelegate <NSObject> | ||
119 | -(void) scoreRequestOk:(id) sender; | ||
120 | -(void) scoreRequestRankOk:(id) sender; | ||
121 | -(void) scoreRequestFail:(id) sender; | ||
122 | @end | ||
diff --git a/libs/cocoslive/CLScoreServerRequest.m b/libs/cocoslive/CLScoreServerRequest.m new file mode 100755 index 0000000..e16b895 --- /dev/null +++ b/libs/cocoslive/CLScoreServerRequest.m | |||
@@ -0,0 +1,257 @@ | |||
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 | // 3rd party imports | ||
29 | #import "CJSONDeserializer.h" | ||
30 | |||
31 | // local imports | ||
32 | #import "CLScoreServerPost.h" | ||
33 | #import "CLScoreServerRequest.h" | ||
34 | #import "ccMacros.h" | ||
35 | |||
36 | @implementation CLScoreServerRequest | ||
37 | |||
38 | @synthesize connection=connection_; | ||
39 | |||
40 | +(id) serverWithGameName:(NSString*) name delegate:(id)delegate | ||
41 | { | ||
42 | return [[[self alloc] initWithGameName:name delegate:delegate] autorelease]; | ||
43 | } | ||
44 | |||
45 | -(id) initWithGameName:(NSString*) name delegate:(id)aDelegate | ||
46 | { | ||
47 | self = [super init]; | ||
48 | if( self ) { | ||
49 | gameName = [[name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] retain]; | ||
50 | delegate = [aDelegate retain]; | ||
51 | receivedData = [[NSMutableData data] retain]; | ||
52 | } | ||
53 | return self; | ||
54 | } | ||
55 | |||
56 | -(void) dealloc | ||
57 | { | ||
58 | CCLOGINFO(@"deallocing %@", self); | ||
59 | |||
60 | [delegate release]; | ||
61 | [gameName release]; | ||
62 | [receivedData release]; | ||
63 | [connection_ release]; | ||
64 | [super dealloc]; | ||
65 | } | ||
66 | |||
67 | -(BOOL) requestScores:(tQueryType)type | ||
68 | limit:(int)limit | ||
69 | offset:(int)offset | ||
70 | flags:(tQueryFlags)flags | ||
71 | category:(NSString*)category | ||
72 | { | ||
73 | // create the request | ||
74 | [receivedData setLength:0]; | ||
75 | |||
76 | // it's not a call for rank | ||
77 | reqRankOnly = NO; | ||
78 | |||
79 | NSString *device = @""; | ||
80 | if( flags & kQueryFlagByDevice ) | ||
81 | device = [[UIDevice currentDevice] uniqueIdentifier]; | ||
82 | |||
83 | // arguments: | ||
84 | // query: type of query | ||
85 | // limit: how many scores are being requested. Default is 25. Maximun is 100 | ||
86 | // offset: offset of the scores | ||
87 | // flags: bring only country scores, world scores, etc. | ||
88 | // category: string user defined string used to filter | ||
89 | NSString *url= [NSString stringWithFormat:@"%@?gamename=%@&querytype=%d&offset=%d&limit=%d&flags=%d&category=%@&device=%@", | ||
90 | SCORE_SERVER_REQUEST_URL, | ||
91 | gameName, | ||
92 | type, | ||
93 | offset, | ||
94 | limit, | ||
95 | flags, | ||
96 | [category stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding], | ||
97 | device | ||
98 | ]; | ||
99 | |||
100 | // NSLog(@"%@", url); | ||
101 | |||
102 | NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:url] | ||
103 | cachePolicy:NSURLRequestUseProtocolCachePolicy | ||
104 | timeoutInterval:10.0]; | ||
105 | |||
106 | // create the connection with the request | ||
107 | // and start loading the data | ||
108 | self.connection=[NSURLConnection connectionWithRequest:request delegate:self]; | ||
109 | if (! connection_) | ||
110 | return NO; | ||
111 | |||
112 | return YES; | ||
113 | } | ||
114 | |||
115 | -(BOOL) requestScores:(tQueryType)type | ||
116 | limit:(int)limit | ||
117 | offset:(int)offset | ||
118 | flags:(tQueryFlags)flags | ||
119 | { | ||
120 | // create the request | ||
121 | [receivedData setLength:0]; | ||
122 | |||
123 | // arguments: | ||
124 | // query: type of query | ||
125 | // limit: how many scores are being requested. Maximun is 100 | ||
126 | // offset: offset of the scores | ||
127 | // flags: bring only country scores, world scores, etc. | ||
128 | return [self requestScores:type limit:limit offset:offset flags:flags category:@""]; | ||
129 | } | ||
130 | |||
131 | -(NSArray*) parseScores | ||
132 | { | ||
133 | NSArray *array = nil; | ||
134 | NSError *error = nil; | ||
135 | NSDictionary *dictionary = [[CJSONDeserializer deserializer] deserializeAsDictionary:receivedData error:&error]; | ||
136 | |||
137 | // NSLog(@"r: %@", dictionary); | ||
138 | if( ! error ) { | ||
139 | array = [dictionary objectForKey:@"scores"]; | ||
140 | } else { | ||
141 | CCLOG(@"Error parsing scores: %@", error); | ||
142 | } | ||
143 | return array; | ||
144 | } | ||
145 | |||
146 | #pragma mark Request rank for score | ||
147 | |||
148 | -(BOOL) requestRankForScore:(int)score andCategory:(NSString*)category { | ||
149 | // create the request | ||
150 | [receivedData setLength:0]; | ||
151 | |||
152 | reqRankOnly = YES; | ||
153 | |||
154 | // arguments: | ||
155 | // score: score for which you need rank | ||
156 | // category: user defined string used to filter | ||
157 | NSString *url= [NSString stringWithFormat:@"%@?gamename=%@&category=%@&score=%d", | ||
158 | SCORE_SERVER_GETRANK_URL, | ||
159 | gameName, | ||
160 | [category stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding], | ||
161 | score | ||
162 | ]; | ||
163 | |||
164 | NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:url] | ||
165 | cachePolicy:NSURLRequestUseProtocolCachePolicy | ||
166 | timeoutInterval:10.0]; | ||
167 | |||
168 | // create the connection with the request | ||
169 | // and start loading the data | ||
170 | self.connection=[NSURLConnection connectionWithRequest:request delegate:self]; | ||
171 | if (! connection_) | ||
172 | return NO; | ||
173 | |||
174 | return YES; | ||
175 | } | ||
176 | |||
177 | -(int) parseRank { | ||
178 | // NSString *rankStr = [NSString stringWithCString:[receivedData bytes] length: [receivedData length]]; | ||
179 | NSString *rankStr = [NSString stringWithCString:[receivedData bytes] encoding: NSASCIIStringEncoding]; | ||
180 | |||
181 | // NSLog(@"XXXX: Ranking: %@", rankStr); | ||
182 | |||
183 | // creating trimmed string by trimming everything that's not numbers from the receivedData | ||
184 | NSString *trimmedStr = [rankStr stringByTrimmingCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]; | ||
185 | |||
186 | int scoreInt = [trimmedStr intValue]; | ||
187 | |||
188 | return scoreInt; | ||
189 | } | ||
190 | |||
191 | |||
192 | #pragma mark NSURLConnection Delegate | ||
193 | |||
194 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response | ||
195 | { | ||
196 | // this method is called when the server has determined that it | ||
197 | // has enough information to create the NSURLResponse | ||
198 | |||
199 | // it can be called multiple times, for example in the case of a | ||
200 | // redirect, so each time we reset the data. | ||
201 | // receivedData is declared as a method instance elsewhere | ||
202 | |||
203 | [receivedData setLength:0]; | ||
204 | } | ||
205 | |||
206 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data | ||
207 | { | ||
208 | // append the new data to the receivedData | ||
209 | // receivedData is declared as a method instance elsewhere | ||
210 | [receivedData appendData:data]; | ||
211 | } | ||
212 | |||
213 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error | ||
214 | { | ||
215 | // release the connection, and the data object | ||
216 | self.connection = nil; | ||
217 | |||
218 | |||
219 | CCLOG(@"Error getting scores: %@", error); | ||
220 | |||
221 | if( [delegate respondsToSelector:@selector(scoreRequestFail:) ] ) | ||
222 | [delegate scoreRequestFail:self]; | ||
223 | |||
224 | } | ||
225 | |||
226 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection | ||
227 | { | ||
228 | // release the connection, and the data object | ||
229 | self.connection = nil; | ||
230 | |||
231 | |||
232 | if(reqRankOnly) { | ||
233 | // because it's request for rank, different delegate method is called scoreRequestRankOk: | ||
234 | // if connection failed the same delegate method is used as for standard scores - scoreRequestFail: | ||
235 | if( [delegate respondsToSelector:@selector(scoreRequestRankOk:) ] ) { | ||
236 | [delegate scoreRequestRankOk:self]; | ||
237 | } | ||
238 | } else { | ||
239 | if( [delegate respondsToSelector:@selector(scoreRequestOk:) ] ) { | ||
240 | [delegate scoreRequestOk:self]; | ||
241 | } | ||
242 | |||
243 | } | ||
244 | } | ||
245 | |||
246 | -(NSURLRequest *)connection:(NSURLConnection *)connection | ||
247 | willSendRequest:(NSURLRequest *)request | ||
248 | redirectResponse:(NSURLResponse *)redirectResponse | ||
249 | { | ||
250 | NSURLRequest *newRequest=request; | ||
251 | if (redirectResponse) { | ||
252 | newRequest=nil; | ||
253 | } | ||
254 | return newRequest; | ||
255 | } | ||
256 | |||
257 | @end | ||
diff --git a/libs/cocoslive/cocoslive.h b/libs/cocoslive/cocoslive.h new file mode 100755 index 0000000..15dbe1a --- /dev/null +++ b/libs/cocoslive/cocoslive.h | |||
@@ -0,0 +1,43 @@ | |||
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 | |||
29 | // 0x00 HI ME LO | ||
30 | // 00 00 03 02 | ||
31 | #define COCOSLIVE_VERSION 0x00000302 | ||
32 | |||
33 | // to use localserver. DEBUG ONLY | ||
34 | //#define USE_LOCAL_SERVER 1 | ||
35 | |||
36 | // all cocos live include files | ||
37 | // | ||
38 | #import "CLScoreServerPost.h" | ||
39 | #import "CLScoreServerRequest.h" | ||
40 | |||
41 | |||
42 | // free functions | ||
43 | NSString * cocosLiveVersion(void); | ||
diff --git a/libs/cocoslive/cocoslive.m b/libs/cocoslive/cocoslive.m new file mode 100755 index 0000000..613a9d7 --- /dev/null +++ b/libs/cocoslive/cocoslive.m | |||
@@ -0,0 +1,37 @@ | |||
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 | #import <UIKit/UIKit.h> | ||
29 | |||
30 | #import "cocoslive.h" | ||
31 | |||
32 | static NSString *version = @"cocoslive v0.3.2"; | ||
33 | |||
34 | NSString *cocosLiveVersion() | ||
35 | { | ||
36 | return version; | ||
37 | } | ||