mirror of https://github.com/axmolengine/axmol.git
Adding Mac support!
This commit is contained in:
parent
fe13388de4
commit
d4b6d1262b
|
@ -0,0 +1,246 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Steve Oldmeadow
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "CocosDenshion.h"
|
||||||
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 30000
|
||||||
|
#import <AVFoundation/AVFoundation.h>
|
||||||
|
#else
|
||||||
|
#import "CDXMacOSXSupport.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Different modes of the engine */
|
||||||
|
typedef enum {
|
||||||
|
kAMM_FxOnly, //!Other apps will be able to play audio
|
||||||
|
kAMM_FxPlusMusic, //!Only this app will play audio
|
||||||
|
kAMM_FxPlusMusicIfNoOtherAudio, //!If another app is playing audio at start up then allow it to continue and don't play music
|
||||||
|
kAMM_MediaPlayback, //!This app takes over audio e.g music player app
|
||||||
|
kAMM_PlayAndRecord //!App takes over audio and has input and output
|
||||||
|
} tAudioManagerMode;
|
||||||
|
|
||||||
|
/** Possible states of the engine */
|
||||||
|
typedef enum {
|
||||||
|
kAMStateUninitialised, //!Audio manager has not been initialised - do not use
|
||||||
|
kAMStateInitialising, //!Audio manager is in the process of initialising - do not use
|
||||||
|
kAMStateInitialised //!Audio manager is initialised - safe to use
|
||||||
|
} tAudioManagerState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kAMRBDoNothing, //Audio manager will not do anything on resign or becoming active
|
||||||
|
kAMRBStopPlay, //Background music is stopped on resign and resumed on become active
|
||||||
|
kAMRBStop //Background music is stopped on resign but not resumed - maybe because you want to do this from within your game
|
||||||
|
} tAudioManagerResignBehavior;
|
||||||
|
|
||||||
|
/** Notifications */
|
||||||
|
extern NSString * const kCDN_AudioManagerInitialised;
|
||||||
|
|
||||||
|
@interface CDAsynchInitialiser : NSOperation {}
|
||||||
|
@end
|
||||||
|
|
||||||
|
/** CDAudioManager supports two long audio source channels called left and right*/
|
||||||
|
typedef enum {
|
||||||
|
kASC_Left = 0,
|
||||||
|
kASC_Right = 1
|
||||||
|
} tAudioSourceChannel;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kLAS_Init,
|
||||||
|
kLAS_Loaded,
|
||||||
|
kLAS_Playing,
|
||||||
|
kLAS_Paused,
|
||||||
|
kLAS_Stopped,
|
||||||
|
} tLongAudioSourceState;
|
||||||
|
|
||||||
|
@class CDLongAudioSource;
|
||||||
|
@protocol CDLongAudioSourceDelegate <NSObject>
|
||||||
|
@optional
|
||||||
|
/** The audio source completed playing */
|
||||||
|
- (void) cdAudioSourceDidFinishPlaying:(CDLongAudioSource *) audioSource;
|
||||||
|
/** The file used to load the audio source has changed */
|
||||||
|
- (void) cdAudioSourceFileDidChange:(CDLongAudioSource *) audioSource;
|
||||||
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
CDLongAudioSource represents an audio source that has a long duration which makes
|
||||||
|
it costly to load into memory for playback as an effect using CDSoundEngine. Examples
|
||||||
|
include background music and narration tracks. The audio file may or may not be compressed.
|
||||||
|
Bear in mind that current iDevices can only use hardware to decode a single compressed
|
||||||
|
audio file at a time and playing multiple compressed files will result in a performance drop
|
||||||
|
as software decompression will take place.
|
||||||
|
@since v0.99
|
||||||
|
*/
|
||||||
|
@interface CDLongAudioSource : NSObject <AVAudioPlayerDelegate, CDAudioInterruptProtocol>{
|
||||||
|
AVAudioPlayer *audioSourcePlayer;
|
||||||
|
NSString *audioSourceFilePath;
|
||||||
|
NSInteger numberOfLoops;
|
||||||
|
float volume;
|
||||||
|
id<CDLongAudioSourceDelegate> delegate;
|
||||||
|
BOOL mute;
|
||||||
|
BOOL enabled_;
|
||||||
|
BOOL backgroundMusic;
|
||||||
|
// whether background music is paused
|
||||||
|
BOOL paused;
|
||||||
|
@public
|
||||||
|
BOOL systemPaused;//Used for auto resign handling
|
||||||
|
NSTimeInterval systemPauseLocation;//Used for auto resign handling
|
||||||
|
@protected
|
||||||
|
tLongAudioSourceState state;
|
||||||
|
}
|
||||||
|
@property (readonly) AVAudioPlayer *audioSourcePlayer;
|
||||||
|
@property (readonly) NSString *audioSourceFilePath;
|
||||||
|
@property (readwrite, nonatomic) NSInteger numberOfLoops;
|
||||||
|
@property (readwrite, nonatomic) float volume;
|
||||||
|
@property (assign) id<CDLongAudioSourceDelegate> delegate;
|
||||||
|
/* This long audio source functions as background music */
|
||||||
|
@property (readwrite, nonatomic) BOOL backgroundMusic;
|
||||||
|
@property (readonly) BOOL paused;
|
||||||
|
|
||||||
|
/** Loads the file into the audio source */
|
||||||
|
-(void) load:(NSString*) filePath;
|
||||||
|
/** Plays the audio source */
|
||||||
|
-(void) play;
|
||||||
|
/** Stops playing the audio soruce */
|
||||||
|
-(void) stop;
|
||||||
|
/** Pauses the audio source */
|
||||||
|
-(void) pause;
|
||||||
|
/** Rewinds the audio source */
|
||||||
|
-(void) rewind;
|
||||||
|
/** Resumes playing the audio source if it was paused */
|
||||||
|
-(void) resume;
|
||||||
|
/** Returns whether or not the audio source is playing */
|
||||||
|
-(BOOL) isPlaying;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
CDAudioManager manages audio requirements for a game. It provides access to a CDSoundEngine object
|
||||||
|
for playing sound effects. It provides access to two CDLongAudioSource object (left and right channel)
|
||||||
|
for playing long duration audio such as background music and narration tracks. Additionally it manages
|
||||||
|
the audio session to take care of things like audio session interruption and interacting with the audio
|
||||||
|
of other apps that are running on the device.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- Firmware: OS 2.2 or greater
|
||||||
|
- Files: CDAudioManager.*, CocosDenshion.*
|
||||||
|
- Frameworks: OpenAL, AudioToolbox, AVFoundation
|
||||||
|
@since v0.8
|
||||||
|
*/
|
||||||
|
@interface CDAudioManager : NSObject <CDLongAudioSourceDelegate, CDAudioInterruptProtocol, AVAudioSessionDelegate> {
|
||||||
|
CDSoundEngine *soundEngine;
|
||||||
|
CDLongAudioSource *backgroundMusic;
|
||||||
|
NSMutableArray *audioSourceChannels;
|
||||||
|
NSString* _audioSessionCategory;
|
||||||
|
BOOL _audioWasPlayingAtStartup;
|
||||||
|
tAudioManagerMode _mode;
|
||||||
|
SEL backgroundMusicCompletionSelector;
|
||||||
|
id backgroundMusicCompletionListener;
|
||||||
|
BOOL willPlayBackgroundMusic;
|
||||||
|
BOOL _mute;
|
||||||
|
BOOL _resigned;
|
||||||
|
BOOL _interrupted;
|
||||||
|
BOOL _audioSessionActive;
|
||||||
|
BOOL enabled_;
|
||||||
|
|
||||||
|
//For handling resign/become active
|
||||||
|
BOOL _isObservingAppEvents;
|
||||||
|
tAudioManagerResignBehavior _resignBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (readonly) CDSoundEngine *soundEngine;
|
||||||
|
@property (readonly) CDLongAudioSource *backgroundMusic;
|
||||||
|
@property (readonly) BOOL willPlayBackgroundMusic;
|
||||||
|
|
||||||
|
/** Returns the shared singleton */
|
||||||
|
+ (CDAudioManager *) sharedManager;
|
||||||
|
+ (tAudioManagerState) sharedManagerState;
|
||||||
|
/** Configures the shared singleton with a mode*/
|
||||||
|
+ (void) configure: (tAudioManagerMode) mode;
|
||||||
|
/** Initializes the engine asynchronously with a mode */
|
||||||
|
+ (void) initAsynchronously: (tAudioManagerMode) mode;
|
||||||
|
/** Initializes the engine synchronously with a mode, channel definition and a total number of channels */
|
||||||
|
- (id) init: (tAudioManagerMode) mode;
|
||||||
|
-(void) audioSessionInterrupted;
|
||||||
|
-(void) audioSessionResumed;
|
||||||
|
-(void) setResignBehavior:(tAudioManagerResignBehavior) resignBehavior autoHandle:(BOOL) autoHandle;
|
||||||
|
/** Returns true is audio is muted at a hardware level e.g user has ringer switch set to off */
|
||||||
|
-(BOOL) isDeviceMuted;
|
||||||
|
/** Returns true if another app is playing audio such as the iPod music player */
|
||||||
|
-(BOOL) isOtherAudioPlaying;
|
||||||
|
/** 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 */
|
||||||
|
-(void) setMode:(tAudioManagerMode) mode;
|
||||||
|
/** Shuts down the shared audio manager instance so that it can be reinitialised */
|
||||||
|
+(void) end;
|
||||||
|
|
||||||
|
/** Call if you want to use built in resign behavior but need to do some additional audio processing on resign active. */
|
||||||
|
- (void) applicationWillResignActive;
|
||||||
|
/** Call if you want to use built in resign behavior but need to do some additional audio processing on become active. */
|
||||||
|
- (void) applicationDidBecomeActive;
|
||||||
|
|
||||||
|
//New AVAudioPlayer API
|
||||||
|
/** Loads the data from the specified file path to the channel's audio source */
|
||||||
|
-(CDLongAudioSource*) audioSourceLoad:(NSString*) filePath channel:(tAudioSourceChannel) channel;
|
||||||
|
/** Retrieves the audio source for the specified channel */
|
||||||
|
-(CDLongAudioSource*) audioSourceForChannel:(tAudioSourceChannel) channel;
|
||||||
|
|
||||||
|
//Legacy AVAudioPlayer API
|
||||||
|
/** Plays music in background. The music can be looped or not
|
||||||
|
It is recommended to use .aac files as background music since they are decoded by the device (hardware).
|
||||||
|
*/
|
||||||
|
-(void) playBackgroundMusic:(NSString*) filePath loop:(BOOL) loop;
|
||||||
|
/** Preloads a background music */
|
||||||
|
-(void) preloadBackgroundMusic:(NSString*) filePath;
|
||||||
|
/** Stops playing the background music */
|
||||||
|
-(void) stopBackgroundMusic;
|
||||||
|
/** Pauses the background music */
|
||||||
|
-(void) pauseBackgroundMusic;
|
||||||
|
/** Rewinds the background music */
|
||||||
|
-(void) rewindBackgroundMusic;
|
||||||
|
/** Resumes playing the background music */
|
||||||
|
-(void) resumeBackgroundMusic;
|
||||||
|
/** Returns whether or not the background music is playing */
|
||||||
|
-(BOOL) isBackgroundMusicPlaying;
|
||||||
|
|
||||||
|
-(void) setBackgroundMusicCompletionListener:(id) listener selector:(SEL) selector;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/** Fader for long audio source objects */
|
||||||
|
@interface CDLongAudioSourceFader : CDPropertyModifier{}
|
||||||
|
@end
|
||||||
|
|
||||||
|
static const int kCDNoBuffer = -1;
|
||||||
|
|
||||||
|
/** Allows buffers to be associated with file names */
|
||||||
|
@interface CDBufferManager:NSObject{
|
||||||
|
NSMutableDictionary* loadedBuffers;
|
||||||
|
NSMutableArray *freedBuffers;
|
||||||
|
CDSoundEngine *soundEngine;
|
||||||
|
int nextBufferId;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(id) initWithEngine:(CDSoundEngine *) theSoundEngine;
|
||||||
|
-(int) bufferForFile:(NSString*) filePath create:(BOOL) create;
|
||||||
|
-(void) releaseBufferForFile:(NSString *) filePath;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
|
@ -0,0 +1,898 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Steve Oldmeadow
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#import "CDAudioManager.h"
|
||||||
|
|
||||||
|
NSString * const kCDN_AudioManagerInitialised = @"kCDN_AudioManagerInitialised";
|
||||||
|
|
||||||
|
//NSOperation object used to asynchronously initialise
|
||||||
|
@implementation CDAsynchInitialiser
|
||||||
|
|
||||||
|
-(void) main {
|
||||||
|
[super main];
|
||||||
|
[CDAudioManager sharedManager];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CDLongAudioSource
|
||||||
|
|
||||||
|
@synthesize audioSourcePlayer, audioSourceFilePath, delegate, backgroundMusic, paused;
|
||||||
|
|
||||||
|
-(id) init {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
state = kLAS_Init;
|
||||||
|
volume = 1.0f;
|
||||||
|
mute = NO;
|
||||||
|
enabled_ = YES;
|
||||||
|
paused = NO;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) dealloc {
|
||||||
|
CDLOGINFO(@"Denshion::CDLongAudioSource - deallocating %@", self);
|
||||||
|
[audioSourcePlayer release];
|
||||||
|
[audioSourceFilePath release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) load:(NSString*) filePath {
|
||||||
|
//We have alread loaded a file previously, check if we are being asked to load the same file
|
||||||
|
if (state == kLAS_Init || ![filePath isEqualToString:audioSourceFilePath]) {
|
||||||
|
CDLOGINFO(@"Denshion::CDLongAudioSource - Loading new audio source %@",filePath);
|
||||||
|
//New file
|
||||||
|
if (state != kLAS_Init) {
|
||||||
|
[audioSourceFilePath release];//Release old file path
|
||||||
|
[audioSourcePlayer release];//Release old AVAudioPlayer, they can't be reused
|
||||||
|
}
|
||||||
|
audioSourceFilePath = [filePath copy];
|
||||||
|
NSError *error = nil;
|
||||||
|
NSString *path = [CDUtilities fullPathFromRelativePath:audioSourceFilePath];
|
||||||
|
audioSourcePlayer = [(AVAudioPlayer*)[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
|
||||||
|
if (error == nil) {
|
||||||
|
[audioSourcePlayer prepareToPlay];
|
||||||
|
audioSourcePlayer.delegate = self;
|
||||||
|
if (delegate && [delegate respondsToSelector:@selector(cdAudioSourceFileDidChange:)]) {
|
||||||
|
//Tell our delegate the file has changed
|
||||||
|
[delegate cdAudioSourceFileDidChange:self];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CDLOG(@"Denshion::CDLongAudioSource - Error initialising audio player: %@",error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Same file - just return it to a consistent state
|
||||||
|
[self pause];
|
||||||
|
[self rewind];
|
||||||
|
}
|
||||||
|
audioSourcePlayer.volume = volume;
|
||||||
|
audioSourcePlayer.numberOfLoops = numberOfLoops;
|
||||||
|
state = kLAS_Loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) play {
|
||||||
|
if (enabled_) {
|
||||||
|
self->systemPaused = NO;
|
||||||
|
self->paused = NO;
|
||||||
|
[audioSourcePlayer play];
|
||||||
|
} else {
|
||||||
|
CDLOGINFO(@"Denshion::CDLongAudioSource long audio source didn't play because it is disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) stop {
|
||||||
|
self->paused = NO;
|
||||||
|
[audioSourcePlayer stop];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) pause {
|
||||||
|
self->paused = YES;
|
||||||
|
[audioSourcePlayer pause];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) rewind {
|
||||||
|
self->paused = NO;
|
||||||
|
[audioSourcePlayer setCurrentTime:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) resume {
|
||||||
|
self->paused = NO;
|
||||||
|
[audioSourcePlayer play];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) isPlaying {
|
||||||
|
if (state != kLAS_Init) {
|
||||||
|
return [audioSourcePlayer isPlaying];
|
||||||
|
} else {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setVolume:(float) newVolume
|
||||||
|
{
|
||||||
|
volume = newVolume;
|
||||||
|
if (state != kLAS_Init && !mute) {
|
||||||
|
audioSourcePlayer.volume = newVolume;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(float) volume
|
||||||
|
{
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Audio Interrupt Protocol
|
||||||
|
-(BOOL) mute
|
||||||
|
{
|
||||||
|
return mute;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setMute:(BOOL) muteValue
|
||||||
|
{
|
||||||
|
if (mute != muteValue) {
|
||||||
|
if (mute) {
|
||||||
|
//Turn sound back on
|
||||||
|
audioSourcePlayer.volume = volume;
|
||||||
|
} else {
|
||||||
|
audioSourcePlayer.volume = 0.0f;
|
||||||
|
}
|
||||||
|
mute = muteValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) enabled
|
||||||
|
{
|
||||||
|
return enabled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setEnabled:(BOOL)enabledValue
|
||||||
|
{
|
||||||
|
if (enabledValue != enabled_) {
|
||||||
|
enabled_ = enabledValue;
|
||||||
|
if (!enabled_) {
|
||||||
|
//"Stop" the sounds
|
||||||
|
[self pause];
|
||||||
|
[self rewind];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSInteger) numberOfLoops {
|
||||||
|
return numberOfLoops;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setNumberOfLoops:(NSInteger) loopCount
|
||||||
|
{
|
||||||
|
audioSourcePlayer.numberOfLoops = loopCount;
|
||||||
|
numberOfLoops = loopCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
|
||||||
|
CDLOGINFO(@"Denshion::CDLongAudioSource - audio player finished");
|
||||||
|
#if TARGET_IPHONE_SIMULATOR
|
||||||
|
CDLOGINFO(@"Denshion::CDLongAudioSource - workaround for OpenAL clobbered audio issue");
|
||||||
|
//This is a workaround for an issue in all simulators (tested to 3.1.2). Problem is
|
||||||
|
//that OpenAL audio playback is clobbered when an AVAudioPlayer stops. Workaround
|
||||||
|
//is to keep the player playing on an endless loop with 0 volume and then when
|
||||||
|
//it is played again reset the volume and set loop count appropriately.
|
||||||
|
//NB: this workaround is not foolproof but it is good enough for most situations.
|
||||||
|
player.numberOfLoops = -1;
|
||||||
|
player.volume = 0;
|
||||||
|
[player play];
|
||||||
|
#endif
|
||||||
|
if (delegate && [delegate respondsToSelector:@selector(cdAudioSourceDidFinishPlaying:)]) {
|
||||||
|
[delegate cdAudioSourceDidFinishPlaying:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player {
|
||||||
|
CDLOGINFO(@"Denshion::CDLongAudioSource - audio player interrupted");
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player {
|
||||||
|
CDLOGINFO(@"Denshion::CDLongAudioSource - audio player resumed");
|
||||||
|
if (self.backgroundMusic) {
|
||||||
|
//Check if background music can play as rules may have changed during
|
||||||
|
//the interruption. This is to address a specific issue in 4.x when
|
||||||
|
//fast task switching
|
||||||
|
if([CDAudioManager sharedManager].willPlayBackgroundMusic) {
|
||||||
|
[player play];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[player play];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@interface CDAudioManager (PrivateMethods)
|
||||||
|
-(BOOL) audioSessionSetActive:(BOOL) active;
|
||||||
|
-(BOOL) audioSessionSetCategory:(NSString*) category;
|
||||||
|
-(void) badAlContextHandler;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CDAudioManager
|
||||||
|
#define BACKGROUND_MUSIC_CHANNEL kASC_Left
|
||||||
|
|
||||||
|
@synthesize soundEngine, willPlayBackgroundMusic;
|
||||||
|
static CDAudioManager *sharedManager;
|
||||||
|
static tAudioManagerState _sharedManagerState = kAMStateUninitialised;
|
||||||
|
static tAudioManagerMode configuredMode;
|
||||||
|
static BOOL configured = FALSE;
|
||||||
|
|
||||||
|
-(BOOL) audioSessionSetActive:(BOOL) active {
|
||||||
|
NSError *activationError = nil;
|
||||||
|
if ([[AVAudioSession sharedInstance] setActive:active error:&activationError]) {
|
||||||
|
_audioSessionActive = active;
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Audio session set active %i succeeded", active);
|
||||||
|
return YES;
|
||||||
|
} else {
|
||||||
|
//Failed
|
||||||
|
CDLOG(@"Denshion::CDAudioManager - Audio session set active %i failed with error %@", active, activationError);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) audioSessionSetCategory:(NSString*) category {
|
||||||
|
NSError *categoryError = nil;
|
||||||
|
if ([[AVAudioSession sharedInstance] setCategory:category error:&categoryError]) {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Audio session set category %@ succeeded", category);
|
||||||
|
return YES;
|
||||||
|
} else {
|
||||||
|
//Failed
|
||||||
|
CDLOG(@"Denshion::CDAudioManager - Audio session set category %@ failed with error %@", category, categoryError);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init
|
||||||
|
+ (CDAudioManager *) sharedManager
|
||||||
|
{
|
||||||
|
@synchronized(self) {
|
||||||
|
if (!sharedManager) {
|
||||||
|
if (!configured) {
|
||||||
|
//Set defaults here
|
||||||
|
configuredMode = kAMM_FxPlusMusicIfNoOtherAudio;
|
||||||
|
}
|
||||||
|
sharedManager = [[CDAudioManager alloc] init:configuredMode];
|
||||||
|
_sharedManagerState = kAMStateInitialised;//This is only really relevant when using asynchronous initialisation
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:kCDN_AudioManagerInitialised object:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sharedManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (tAudioManagerState) sharedManagerState {
|
||||||
|
return _sharedManagerState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this to set up audio manager asynchronously. Initialisation is finished when sharedManagerState == kAMStateInitialised
|
||||||
|
*/
|
||||||
|
+ (void) initAsynchronously: (tAudioManagerMode) mode {
|
||||||
|
@synchronized(self) {
|
||||||
|
if (_sharedManagerState == kAMStateUninitialised) {
|
||||||
|
_sharedManagerState = kAMStateInitialising;
|
||||||
|
[CDAudioManager configure:mode];
|
||||||
|
CDAsynchInitialiser *initOp = [[[CDAsynchInitialiser alloc] init] autorelease];
|
||||||
|
NSOperationQueue *opQ = [[[NSOperationQueue alloc] init] autorelease];
|
||||||
|
[opQ addOperation:initOp];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id) alloc
|
||||||
|
{
|
||||||
|
@synchronized(self) {
|
||||||
|
NSAssert(sharedManager == nil, @"Attempted to allocate a second instance of a singleton.");
|
||||||
|
return [super alloc];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call this method before accessing the shared manager in order to configure the shared audio manager
|
||||||
|
*/
|
||||||
|
+ (void) configure: (tAudioManagerMode) mode {
|
||||||
|
configuredMode = mode;
|
||||||
|
configured = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) isOtherAudioPlaying {
|
||||||
|
UInt32 isPlaying = 0;
|
||||||
|
UInt32 varSize = sizeof(isPlaying);
|
||||||
|
AudioSessionGetProperty (kAudioSessionProperty_OtherAudioIsPlaying, &varSize, &isPlaying);
|
||||||
|
return (isPlaying != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setMode:(tAudioManagerMode) mode {
|
||||||
|
|
||||||
|
_mode = mode;
|
||||||
|
switch (_mode) {
|
||||||
|
|
||||||
|
case kAMM_FxOnly:
|
||||||
|
//Share audio with other app
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Audio will be shared");
|
||||||
|
//_audioSessionCategory = kAudioSessionCategory_AmbientSound;
|
||||||
|
_audioSessionCategory = AVAudioSessionCategoryAmbient;
|
||||||
|
willPlayBackgroundMusic = NO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kAMM_FxPlusMusic:
|
||||||
|
//Use audio exclusively - if other audio is playing it will be stopped
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Audio will be exclusive");
|
||||||
|
//_audioSessionCategory = kAudioSessionCategory_SoloAmbientSound;
|
||||||
|
_audioSessionCategory = AVAudioSessionCategorySoloAmbient;
|
||||||
|
willPlayBackgroundMusic = YES;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kAMM_MediaPlayback:
|
||||||
|
//Use audio exclusively, ignore mute switch and sleep
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Media playback mode, audio will be exclusive");
|
||||||
|
//_audioSessionCategory = kAudioSessionCategory_MediaPlayback;
|
||||||
|
_audioSessionCategory = AVAudioSessionCategoryPlayback;
|
||||||
|
willPlayBackgroundMusic = YES;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kAMM_PlayAndRecord:
|
||||||
|
//Use audio exclusively, ignore mute switch and sleep, has inputs and outputs
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Play and record mode, audio will be exclusive");
|
||||||
|
//_audioSessionCategory = kAudioSessionCategory_PlayAndRecord;
|
||||||
|
_audioSessionCategory = AVAudioSessionCategoryPlayAndRecord;
|
||||||
|
willPlayBackgroundMusic = YES;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//kAudioManagerFxPlusMusicIfNoOtherAudio
|
||||||
|
if ([self isOtherAudioPlaying]) {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Other audio is playing audio will be shared");
|
||||||
|
//_audioSessionCategory = kAudioSessionCategory_AmbientSound;
|
||||||
|
_audioSessionCategory = AVAudioSessionCategoryAmbient;
|
||||||
|
willPlayBackgroundMusic = NO;
|
||||||
|
} else {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Other audio is not playing audio will be exclusive");
|
||||||
|
//_audioSessionCategory = kAudioSessionCategory_SoloAmbientSound;
|
||||||
|
_audioSessionCategory = AVAudioSessionCategorySoloAmbient;
|
||||||
|
willPlayBackgroundMusic = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self audioSessionSetCategory:_audioSessionCategory];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is used to work around various bugs introduced in 4.x OS versions. In some circumstances the
|
||||||
|
* audio session is interrupted but never resumed, this results in the loss of OpenAL audio when following
|
||||||
|
* standard practices. If we detect this situation then we will attempt to resume the audio session ourselves.
|
||||||
|
* Known triggers: lock the device then unlock it (iOS 4.2 gm), playback a song using MPMediaPlayer (iOS 4.0)
|
||||||
|
*/
|
||||||
|
- (void) badAlContextHandler {
|
||||||
|
if (_interrupted && alcGetCurrentContext() == NULL) {
|
||||||
|
CDLOG(@"Denshion::CDAudioManager - bad OpenAL context detected, attempting to resume audio session");
|
||||||
|
[self audioSessionResumed];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) init: (tAudioManagerMode) mode {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
|
||||||
|
//Initialise the audio session
|
||||||
|
AVAudioSession* session = [AVAudioSession sharedInstance];
|
||||||
|
session.delegate = self;
|
||||||
|
|
||||||
|
_mode = mode;
|
||||||
|
backgroundMusicCompletionSelector = nil;
|
||||||
|
_isObservingAppEvents = FALSE;
|
||||||
|
_mute = NO;
|
||||||
|
_resigned = NO;
|
||||||
|
_interrupted = NO;
|
||||||
|
enabled_ = YES;
|
||||||
|
_audioSessionActive = NO;
|
||||||
|
[self setMode:mode];
|
||||||
|
soundEngine = [[CDSoundEngine alloc] init];
|
||||||
|
|
||||||
|
//Set up audioSource channels
|
||||||
|
audioSourceChannels = [[NSMutableArray alloc] init];
|
||||||
|
CDLongAudioSource *leftChannel = [[CDLongAudioSource alloc] init];
|
||||||
|
leftChannel.backgroundMusic = YES;
|
||||||
|
CDLongAudioSource *rightChannel = [[CDLongAudioSource alloc] init];
|
||||||
|
rightChannel.backgroundMusic = NO;
|
||||||
|
[audioSourceChannels insertObject:leftChannel atIndex:kASC_Left];
|
||||||
|
[audioSourceChannels insertObject:rightChannel atIndex:kASC_Right];
|
||||||
|
[leftChannel release];
|
||||||
|
[rightChannel release];
|
||||||
|
//Used to support legacy APIs
|
||||||
|
backgroundMusic = [self audioSourceForChannel:BACKGROUND_MUSIC_CHANNEL];
|
||||||
|
backgroundMusic.delegate = self;
|
||||||
|
|
||||||
|
//Add handler for bad al context messages, these are posted by the sound engine.
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(badAlContextHandler) name:kCDN_BadAlContext object:nil];
|
||||||
|
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) dealloc {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - deallocating");
|
||||||
|
[self stopBackgroundMusic];
|
||||||
|
[soundEngine release];
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
[self audioSessionSetActive:NO];
|
||||||
|
[audioSourceChannels release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieves the audio source for the specified channel */
|
||||||
|
-(CDLongAudioSource*) audioSourceForChannel:(tAudioSourceChannel) channel
|
||||||
|
{
|
||||||
|
return (CDLongAudioSource*)[audioSourceChannels objectAtIndex:channel];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Loads the data from the specified file path to the channel's audio source */
|
||||||
|
-(CDLongAudioSource*) audioSourceLoad:(NSString*) filePath channel:(tAudioSourceChannel) channel
|
||||||
|
{
|
||||||
|
CDLongAudioSource *audioSource = [self audioSourceForChannel:channel];
|
||||||
|
if (audioSource) {
|
||||||
|
[audioSource load:filePath];
|
||||||
|
}
|
||||||
|
return audioSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) isBackgroundMusicPlaying {
|
||||||
|
return [self.backgroundMusic isPlaying];
|
||||||
|
}
|
||||||
|
|
||||||
|
//NB: originally I tried using a route change listener and intended to store the current route,
|
||||||
|
//however, on a 3gs running 3.1.2 no route change is generated when the user switches the
|
||||||
|
//ringer mute switch to off (i.e. enables sound) therefore polling is the only reliable way to
|
||||||
|
//determine ringer switch state
|
||||||
|
-(BOOL) isDeviceMuted {
|
||||||
|
|
||||||
|
#if TARGET_IPHONE_SIMULATOR
|
||||||
|
//Calling audio route stuff on the simulator causes problems
|
||||||
|
return NO;
|
||||||
|
#else
|
||||||
|
CFStringRef newAudioRoute;
|
||||||
|
UInt32 propertySize = sizeof (CFStringRef);
|
||||||
|
|
||||||
|
AudioSessionGetProperty (
|
||||||
|
kAudioSessionProperty_AudioRoute,
|
||||||
|
&propertySize,
|
||||||
|
&newAudioRoute
|
||||||
|
);
|
||||||
|
|
||||||
|
if (newAudioRoute == NULL) {
|
||||||
|
//Don't expect this to happen but playing safe otherwise a null in the CFStringCompare will cause a crash
|
||||||
|
return YES;
|
||||||
|
} else {
|
||||||
|
CFComparisonResult newDeviceIsMuted = CFStringCompare (
|
||||||
|
newAudioRoute,
|
||||||
|
(CFStringRef) @"",
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
return (newDeviceIsMuted == kCFCompareEqualTo);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Audio Interrupt Protocol
|
||||||
|
|
||||||
|
-(BOOL) mute {
|
||||||
|
return _mute;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setMute:(BOOL) muteValue {
|
||||||
|
if (muteValue != _mute) {
|
||||||
|
_mute = muteValue;
|
||||||
|
[soundEngine setMute:muteValue];
|
||||||
|
for( CDLongAudioSource *audioSource in audioSourceChannels) {
|
||||||
|
audioSource.mute = muteValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) enabled {
|
||||||
|
return enabled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setEnabled:(BOOL) enabledValue {
|
||||||
|
if (enabledValue != enabled_) {
|
||||||
|
enabled_ = enabledValue;
|
||||||
|
[soundEngine setEnabled:enabled_];
|
||||||
|
for( CDLongAudioSource *audioSource in audioSourceChannels) {
|
||||||
|
audioSource.enabled = enabled_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(CDLongAudioSource*) backgroundMusic
|
||||||
|
{
|
||||||
|
return backgroundMusic;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Load background music ready for playing
|
||||||
|
-(void) preloadBackgroundMusic:(NSString*) filePath
|
||||||
|
{
|
||||||
|
[self.backgroundMusic load:filePath];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) playBackgroundMusic:(NSString*) filePath loop:(BOOL) loop
|
||||||
|
{
|
||||||
|
[self.backgroundMusic load:filePath];
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
[self.backgroundMusic setNumberOfLoops:-1];
|
||||||
|
} else {
|
||||||
|
[self.backgroundMusic setNumberOfLoops:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!willPlayBackgroundMusic || _mute) {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - play bgm aborted because audio is not exclusive or sound is muted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self.backgroundMusic play];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) stopBackgroundMusic
|
||||||
|
{
|
||||||
|
[self.backgroundMusic stop];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) pauseBackgroundMusic
|
||||||
|
{
|
||||||
|
[self.backgroundMusic pause];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) resumeBackgroundMusic
|
||||||
|
{
|
||||||
|
if (!willPlayBackgroundMusic || _mute) {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - resume bgm aborted because audio is not exclusive or sound is muted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![self.backgroundMusic paused]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self.backgroundMusic resume];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) rewindBackgroundMusic
|
||||||
|
{
|
||||||
|
[self.backgroundMusic rewind];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setBackgroundMusicCompletionListener:(id) listener selector:(SEL) selector {
|
||||||
|
backgroundMusicCompletionListener = listener;
|
||||||
|
backgroundMusicCompletionSelector = selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call this method to have the audio manager automatically handle application resign and
|
||||||
|
* become active. Pass a tAudioManagerResignBehavior to indicate the desired behavior
|
||||||
|
* for resigning and becoming active again.
|
||||||
|
*
|
||||||
|
* If autohandle is YES then the applicationWillResignActive and applicationDidBecomActive
|
||||||
|
* methods are automatically called, otherwise you must call them yourself at the appropriate time.
|
||||||
|
*
|
||||||
|
* Based on idea of Dominique Bongard
|
||||||
|
*/
|
||||||
|
-(void) setResignBehavior:(tAudioManagerResignBehavior) resignBehavior autoHandle:(BOOL) autoHandle {
|
||||||
|
|
||||||
|
if (!_isObservingAppEvents && autoHandle) {
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:@"UIApplicationWillResignActiveNotification" object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:@"UIApplicationDidBecomeActiveNotification" object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:@"UIApplicationWillTerminateNotification" object:nil];
|
||||||
|
_isObservingAppEvents = TRUE;
|
||||||
|
}
|
||||||
|
_resignBehavior = resignBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) applicationWillResignActive {
|
||||||
|
self->_resigned = YES;
|
||||||
|
|
||||||
|
//Set the audio sesssion to one that allows sharing so that other audio won't be clobbered on resume
|
||||||
|
[self audioSessionSetCategory:AVAudioSessionCategoryAmbient];
|
||||||
|
|
||||||
|
switch (_resignBehavior) {
|
||||||
|
|
||||||
|
case kAMRBStopPlay:
|
||||||
|
|
||||||
|
for( CDLongAudioSource *audioSource in audioSourceChannels) {
|
||||||
|
if (audioSource.isPlaying) {
|
||||||
|
audioSource->systemPaused = YES;
|
||||||
|
audioSource->systemPauseLocation = audioSource.audioSourcePlayer.currentTime;
|
||||||
|
[audioSource stop];
|
||||||
|
} else {
|
||||||
|
//Music is either paused or stopped, if it is paused it will be restarted
|
||||||
|
//by OS so we will stop it.
|
||||||
|
audioSource->systemPaused = NO;
|
||||||
|
[audioSource stop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kAMRBStop:
|
||||||
|
//Stop music regardless of whether it is playing or not because if it was paused
|
||||||
|
//then the OS would resume it
|
||||||
|
for( CDLongAudioSource *audioSource in audioSourceChannels) {
|
||||||
|
[audioSource stop];
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - handled resign active");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Called when application resigns active only if setResignBehavior has been called
|
||||||
|
- (void) applicationWillResignActive:(NSNotification *) notification
|
||||||
|
{
|
||||||
|
[self applicationWillResignActive];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) applicationDidBecomeActive {
|
||||||
|
|
||||||
|
if (self->_resigned) {
|
||||||
|
_resigned = NO;
|
||||||
|
//Reset the mode incase something changed with audio while we were inactive
|
||||||
|
[self setMode:_mode];
|
||||||
|
switch (_resignBehavior) {
|
||||||
|
|
||||||
|
case kAMRBStopPlay:
|
||||||
|
|
||||||
|
//Music had been stopped but stop maintains current time
|
||||||
|
//so playing again will continue from where music was before resign active.
|
||||||
|
//We check if music can be played because while we were inactive the user might have
|
||||||
|
//done something that should force music to not play such as starting a track in the iPod
|
||||||
|
if (self.willPlayBackgroundMusic) {
|
||||||
|
for( CDLongAudioSource *audioSource in audioSourceChannels) {
|
||||||
|
if (audioSource->systemPaused) {
|
||||||
|
[audioSource resume];
|
||||||
|
audioSource->systemPaused = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - audio manager handled become active");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Called when application becomes active only if setResignBehavior has been called
|
||||||
|
- (void) applicationDidBecomeActive:(NSNotification *) notification
|
||||||
|
{
|
||||||
|
[self applicationDidBecomeActive];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Called when application terminates only if setResignBehavior has been called
|
||||||
|
- (void) applicationWillTerminate:(NSNotification *) notification
|
||||||
|
{
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - audio manager handling terminate");
|
||||||
|
[self stopBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The audio source completed playing */
|
||||||
|
- (void) cdAudioSourceDidFinishPlaying:(CDLongAudioSource *) audioSource {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - audio manager got told background music finished");
|
||||||
|
if (backgroundMusicCompletionSelector != nil) {
|
||||||
|
[backgroundMusicCompletionListener performSelector:backgroundMusicCompletionSelector];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) beginInterruption {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - begin interruption");
|
||||||
|
[self audioSessionInterrupted];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) endInterruption {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - end interruption");
|
||||||
|
[self audioSessionResumed];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __CC_PLATFORM_IOS >= 40000
|
||||||
|
-(void) endInterruptionWithFlags:(NSUInteger)flags {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - interruption ended with flags %i",flags);
|
||||||
|
if (flags == AVAudioSessionInterruptionFlags_ShouldResume) {
|
||||||
|
[self audioSessionResumed];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-(void)audioSessionInterrupted
|
||||||
|
{
|
||||||
|
if (!_interrupted) {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Audio session interrupted");
|
||||||
|
_interrupted = YES;
|
||||||
|
|
||||||
|
// Deactivate the current audio session
|
||||||
|
[self audioSessionSetActive:NO];
|
||||||
|
|
||||||
|
if (alcGetCurrentContext() != NULL) {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Setting OpenAL context to NULL");
|
||||||
|
|
||||||
|
ALenum error = AL_NO_ERROR;
|
||||||
|
|
||||||
|
// set the current context to NULL will 'shutdown' openAL
|
||||||
|
alcMakeContextCurrent(NULL);
|
||||||
|
|
||||||
|
if((error = alGetError()) != AL_NO_ERROR) {
|
||||||
|
CDLOG(@"Denshion::CDAudioManager - Error making context current %x\n", error);
|
||||||
|
}
|
||||||
|
#pragma unused(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)audioSessionResumed
|
||||||
|
{
|
||||||
|
if (_interrupted) {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Audio session resumed");
|
||||||
|
_interrupted = NO;
|
||||||
|
|
||||||
|
BOOL activationResult = NO;
|
||||||
|
// Reactivate the current audio session
|
||||||
|
activationResult = [self audioSessionSetActive:YES];
|
||||||
|
|
||||||
|
//This code is to handle a problem with iOS 4.0 and 4.01 where reactivating the session can fail if
|
||||||
|
//task switching is performed too rapidly. A test case that reliably reproduces the issue is to call the
|
||||||
|
//iPhone and then hang up after two rings (timing may vary ;))
|
||||||
|
//Basically we keep waiting and trying to let the OS catch up with itself but the number of tries is
|
||||||
|
//limited.
|
||||||
|
if (!activationResult) {
|
||||||
|
CDLOG(@"Denshion::CDAudioManager - Failure reactivating audio session, will try wait-try cycle");
|
||||||
|
int activateCount = 0;
|
||||||
|
while (!activationResult && activateCount < 10) {
|
||||||
|
[NSThread sleepForTimeInterval:0.5];
|
||||||
|
activationResult = [self audioSessionSetActive:YES];
|
||||||
|
activateCount++;
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Reactivation attempt %i status = %i",activateCount,activationResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alcGetCurrentContext() == NULL) {
|
||||||
|
CDLOGINFO(@"Denshion::CDAudioManager - Restoring OpenAL context");
|
||||||
|
ALenum error = AL_NO_ERROR;
|
||||||
|
// Restore open al context
|
||||||
|
alcMakeContextCurrent([soundEngine openALContext]);
|
||||||
|
if((error = alGetError()) != AL_NO_ERROR) {
|
||||||
|
CDLOG(@"Denshion::CDAudioManager - Error making context current%x\n", error);
|
||||||
|
}
|
||||||
|
#pragma unused(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+(void) end {
|
||||||
|
[sharedManager release];
|
||||||
|
sharedManager = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@implementation CDLongAudioSourceFader
|
||||||
|
|
||||||
|
-(void) _setTargetProperty:(float) newVal {
|
||||||
|
((CDLongAudioSource*)target).volume = newVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(float) _getTargetProperty {
|
||||||
|
return ((CDLongAudioSource*)target).volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) _stopTarget {
|
||||||
|
//Pause instead of stop as stop releases resources and causes problems in the simulator
|
||||||
|
[((CDLongAudioSource*)target) pause];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(Class) _allowableType {
|
||||||
|
return [CDLongAudioSource class];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@implementation CDBufferManager
|
||||||
|
|
||||||
|
-(id) initWithEngine:(CDSoundEngine *) theSoundEngine {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
soundEngine = theSoundEngine;
|
||||||
|
loadedBuffers = [[NSMutableDictionary alloc] initWithCapacity:CD_BUFFERS_START];
|
||||||
|
freedBuffers = [[NSMutableArray alloc] init];
|
||||||
|
nextBufferId = 0;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) dealloc {
|
||||||
|
[loadedBuffers release];
|
||||||
|
[freedBuffers release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(int) bufferForFile:(NSString*) filePath create:(BOOL) create {
|
||||||
|
|
||||||
|
NSNumber* soundId = (NSNumber*)[loadedBuffers objectForKey:filePath];
|
||||||
|
if(soundId == nil)
|
||||||
|
{
|
||||||
|
if (create) {
|
||||||
|
NSNumber* bufferId = nil;
|
||||||
|
//First try to get a buffer from the free buffers
|
||||||
|
if ([freedBuffers count] > 0) {
|
||||||
|
bufferId = [[[freedBuffers lastObject] retain] autorelease];
|
||||||
|
[freedBuffers removeLastObject];
|
||||||
|
CDLOGINFO(@"Denshion::CDBufferManager reusing buffer id %i",[bufferId intValue]);
|
||||||
|
} else {
|
||||||
|
bufferId = [[NSNumber alloc] initWithInt:nextBufferId];
|
||||||
|
[bufferId autorelease];
|
||||||
|
CDLOGINFO(@"Denshion::CDBufferManager generating new buffer id %i",[bufferId intValue]);
|
||||||
|
nextBufferId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([soundEngine loadBuffer:[bufferId intValue] filePath:filePath]) {
|
||||||
|
//File successfully loaded
|
||||||
|
CDLOGINFO(@"Denshion::CDBufferManager buffer loaded %@ %@",bufferId,filePath);
|
||||||
|
[loadedBuffers setObject:bufferId forKey:filePath];
|
||||||
|
return [bufferId intValue];
|
||||||
|
} else {
|
||||||
|
//File didn't load, put buffer id on free list
|
||||||
|
[freedBuffers addObject:bufferId];
|
||||||
|
return kCDNoBuffer;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//No matching buffer was found
|
||||||
|
return kCDNoBuffer;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return [soundId intValue];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) releaseBufferForFile:(NSString *) filePath {
|
||||||
|
int bufferId = [self bufferForFile:filePath create:NO];
|
||||||
|
if (bufferId != kCDNoBuffer) {
|
||||||
|
[soundEngine unloadBuffer:bufferId];
|
||||||
|
[loadedBuffers removeObjectForKey:filePath];
|
||||||
|
NSNumber *freedBufferId = [[NSNumber alloc] initWithInt:bufferId];
|
||||||
|
[freedBufferId autorelease];
|
||||||
|
[freedBuffers addObject:freedBufferId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Steve Oldmeadow
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
#define COCOSDENSHION_VERSION "Aphex.rc"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
If enabled code useful for debugging such as parameter check assertions will be performed.
|
||||||
|
If you experience any problems you should enable this and test your code with a debug build.
|
||||||
|
*/
|
||||||
|
//#define CD_DEBUG 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
The total number of sounds/buffers that can be loaded assuming memory is sufficient
|
||||||
|
*/
|
||||||
|
//Number of buffers slots that will be initially created
|
||||||
|
#define CD_BUFFERS_START 64
|
||||||
|
//Number of buffers that will be added
|
||||||
|
#define CD_BUFFERS_INCREMENT 16
|
||||||
|
|
||||||
|
/**
|
||||||
|
If enabled, OpenAL code will use static buffers. When static buffers are used the audio
|
||||||
|
data is managed outside of OpenAL, this eliminates a memcpy operation which leads to
|
||||||
|
higher performance when loading sounds.
|
||||||
|
|
||||||
|
However, the downside is that when the audio data is freed you must
|
||||||
|
be certain that it is no longer being accessed otherwise your app will crash. Testing on OS 2.2.1
|
||||||
|
and 3.1.2 has shown that this may occur if a buffer is being used by a source with state = AL_PLAYING
|
||||||
|
when the buffer is deleted. If the data is freed too quickly after the source is stopped then
|
||||||
|
a crash will occur. The implemented workaround is that when static buffers are used the unloadBuffer code will wait for
|
||||||
|
any playing sources to finish playing before the associated buffer and data are deleted, however, this delay may negate any
|
||||||
|
performance gains that are achieved during loading.
|
||||||
|
|
||||||
|
Performance tests on a 1st gen iPod running OS 2.2.1 loading the CocosDenshionDemo sounds were ~0.14 seconds without
|
||||||
|
static buffers and ~0.12 seconds when using static buffers.
|
||||||
|
|
||||||
|
*/
|
||||||
|
//#define CD_USE_STATIC_BUFFERS 1
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Disclaimer: IMPORTANT: This Apple software is supplied to you by
|
||||||
|
Apple Inc. ("Apple") in consideration of your agreement to the
|
||||||
|
following terms, and your use, installation, modification or
|
||||||
|
redistribution of this Apple software constitutes acceptance of these
|
||||||
|
terms. If you do not agree with these terms, please do not use,
|
||||||
|
install, modify or redistribute this Apple software.
|
||||||
|
|
||||||
|
In consideration of your agreement to abide by the following terms, and
|
||||||
|
subject to these terms, Apple grants you a personal, non-exclusive
|
||||||
|
license, under Apple's copyrights in this original Apple software (the
|
||||||
|
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||||
|
Software, with or without modifications, in source and/or binary forms;
|
||||||
|
provided that if you redistribute the Apple Software in its entirety and
|
||||||
|
without modifications, you must retain this notice and the following
|
||||||
|
text and disclaimers in all such redistributions of the Apple Software.
|
||||||
|
Neither the name, trademarks, service marks or logos of Apple Inc.
|
||||||
|
may be used to endorse or promote products derived from the Apple
|
||||||
|
Software without specific prior written permission from Apple. Except
|
||||||
|
as expressly stated in this notice, no other rights or licenses, express
|
||||||
|
or implied, are granted by Apple herein, including but not limited to
|
||||||
|
any patent rights that may be infringed by your derivative works or by
|
||||||
|
other works in which the Apple Software may be incorporated.
|
||||||
|
|
||||||
|
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||||
|
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||||
|
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||||
|
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||||
|
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||||
|
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||||
|
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||||
|
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file contains code from version 1.1 and 1.4 of MyOpenALSupport.h taken from Apple's oalTouch version.
|
||||||
|
The 1.4 version code is used for loading IMA4 files, however, this code causes very noticeable clicking
|
||||||
|
when used to load wave files that are looped so the 1.1 version code is used specifically for loading
|
||||||
|
wav files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CD_OPENAL_H
|
||||||
|
#define __CD_OPENAL_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#import <OpenAL/al.h>
|
||||||
|
#import <OpenAL/alc.h>
|
||||||
|
#import <CoreFoundation/CFURL.h>
|
||||||
|
|
||||||
|
|
||||||
|
//Taken from oalTouch MyOpenALSupport 1.1
|
||||||
|
void* CDloadWaveAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate);
|
||||||
|
void* CDloadCafAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate);
|
||||||
|
void* CDGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,248 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Disclaimer: IMPORTANT: This Apple software is supplied to you by
|
||||||
|
Apple Inc. ("Apple") in consideration of your agreement to the
|
||||||
|
following terms, and your use, installation, modification or
|
||||||
|
redistribution of this Apple software constitutes acceptance of these
|
||||||
|
terms. If you do not agree with these terms, please do not use,
|
||||||
|
install, modify or redistribute this Apple software.
|
||||||
|
|
||||||
|
In consideration of your agreement to abide by the following terms, and
|
||||||
|
subject to these terms, Apple grants you a personal, non-exclusive
|
||||||
|
license, under Apple's copyrights in this original Apple software (the
|
||||||
|
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||||
|
Software, with or without modifications, in source and/or binary forms;
|
||||||
|
provided that if you redistribute the Apple Software in its entirety and
|
||||||
|
without modifications, you must retain this notice and the following
|
||||||
|
text and disclaimers in all such redistributions of the Apple Software.
|
||||||
|
Neither the name, trademarks, service marks or logos of Apple Inc.
|
||||||
|
may be used to endorse or promote products derived from the Apple
|
||||||
|
Software without specific prior written permission from Apple. Except
|
||||||
|
as expressly stated in this notice, no other rights or licenses, express
|
||||||
|
or implied, are granted by Apple herein, including but not limited to
|
||||||
|
any patent rights that may be infringed by your derivative works or by
|
||||||
|
other works in which the Apple Software may be incorporated.
|
||||||
|
|
||||||
|
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||||
|
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||||
|
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||||
|
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||||
|
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||||
|
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||||
|
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||||
|
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
$Id: CDOpenALSupport.h 16 2010-03-11 06:22:10Z steveoldmeadow $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "CDOpenALSupport.h"
|
||||||
|
#import "CocosDenshion.h"
|
||||||
|
#import <AudioToolbox/AudioToolbox.h>
|
||||||
|
#import <AudioToolbox/ExtendedAudioFile.h>
|
||||||
|
|
||||||
|
//Taken from oalTouch MyOpenALSupport 1.1
|
||||||
|
void* CDloadWaveAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate)
|
||||||
|
{
|
||||||
|
OSStatus err = noErr;
|
||||||
|
UInt64 fileDataSize = 0;
|
||||||
|
AudioStreamBasicDescription theFileFormat;
|
||||||
|
UInt32 thePropertySize = sizeof(theFileFormat);
|
||||||
|
AudioFileID afid = 0;
|
||||||
|
void* theData = NULL;
|
||||||
|
|
||||||
|
// Open a file with ExtAudioFileOpen()
|
||||||
|
err = AudioFileOpenURL(inFileURL, kAudioFileReadPermission, 0, &afid);
|
||||||
|
if(err) { CDLOG(@"MyGetOpenALAudioData: AudioFileOpenURL FAILED, Error = %ld\n", err); goto Exit; }
|
||||||
|
|
||||||
|
// Get the audio data format
|
||||||
|
err = AudioFileGetProperty(afid, kAudioFilePropertyDataFormat, &thePropertySize, &theFileFormat);
|
||||||
|
if(err) { CDLOG(@"MyGetOpenALAudioData: AudioFileGetProperty(kAudioFileProperty_DataFormat) FAILED, Error = %ld\n", err); goto Exit; }
|
||||||
|
|
||||||
|
if (theFileFormat.mChannelsPerFrame > 2) {
|
||||||
|
CDLOG(@"MyGetOpenALAudioData - Unsupported Format, channel count is greater than stereo\n"); goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((theFileFormat.mFormatID != kAudioFormatLinearPCM) || (!TestAudioFormatNativeEndian(theFileFormat))) {
|
||||||
|
CDLOG(@"MyGetOpenALAudioData - Unsupported Format, must be little-endian PCM\n"); goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((theFileFormat.mBitsPerChannel != 8) && (theFileFormat.mBitsPerChannel != 16)) {
|
||||||
|
CDLOG(@"MyGetOpenALAudioData - Unsupported Format, must be 8 or 16 bit PCM\n"); goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
thePropertySize = sizeof(fileDataSize);
|
||||||
|
err = AudioFileGetProperty(afid, kAudioFilePropertyAudioDataByteCount, &thePropertySize, &fileDataSize);
|
||||||
|
if(err) { CDLOG(@"MyGetOpenALAudioData: AudioFileGetProperty(kAudioFilePropertyAudioDataByteCount) FAILED, Error = %ld\n", err); goto Exit; }
|
||||||
|
|
||||||
|
// Read all the data into memory
|
||||||
|
UInt32 dataSize = (UInt32)fileDataSize;
|
||||||
|
theData = malloc(dataSize);
|
||||||
|
if (theData)
|
||||||
|
{
|
||||||
|
memset(theData, 0, dataSize);
|
||||||
|
AudioFileReadBytes(afid, false, 0, &dataSize, theData);
|
||||||
|
if(err == noErr)
|
||||||
|
{
|
||||||
|
// success
|
||||||
|
*outDataSize = (ALsizei)dataSize;
|
||||||
|
//This fix was added by me, however, 8 bit sounds have a clipping sound at the end so aren't really usable (SO)
|
||||||
|
if (theFileFormat.mBitsPerChannel == 16) {
|
||||||
|
*outDataFormat = (theFileFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
|
||||||
|
} else {
|
||||||
|
*outDataFormat = (theFileFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8;
|
||||||
|
}
|
||||||
|
*outSampleRate = (ALsizei)theFileFormat.mSampleRate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// failure
|
||||||
|
free (theData);
|
||||||
|
theData = NULL; // make sure to return NULL
|
||||||
|
CDLOG(@"MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %ld\n", err); goto Exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
// Dispose the ExtAudioFileRef, it is no longer needed
|
||||||
|
if (afid) AudioFileClose(afid);
|
||||||
|
return theData;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Taken from oalTouch MyOpenALSupport 1.4
|
||||||
|
void* CDloadCafAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate)
|
||||||
|
{
|
||||||
|
OSStatus status = noErr;
|
||||||
|
BOOL abort = NO;
|
||||||
|
SInt64 theFileLengthInFrames = 0;
|
||||||
|
AudioStreamBasicDescription theFileFormat;
|
||||||
|
UInt32 thePropertySize = sizeof(theFileFormat);
|
||||||
|
ExtAudioFileRef extRef = NULL;
|
||||||
|
void* theData = NULL;
|
||||||
|
AudioStreamBasicDescription theOutputFormat;
|
||||||
|
UInt32 dataSize = 0;
|
||||||
|
|
||||||
|
// Open a file with ExtAudioFileOpen()
|
||||||
|
status = ExtAudioFileOpenURL(inFileURL, &extRef);
|
||||||
|
if (status != noErr)
|
||||||
|
{
|
||||||
|
CDLOG(@"MyGetOpenALAudioData: ExtAudioFileOpenURL FAILED, Error = %ld\n", status);
|
||||||
|
abort = YES;
|
||||||
|
}
|
||||||
|
if (abort)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
// Get the audio data format
|
||||||
|
status = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &theFileFormat);
|
||||||
|
if (status != noErr)
|
||||||
|
{
|
||||||
|
CDLOG(@"MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %ld\n", status);
|
||||||
|
abort = YES;
|
||||||
|
}
|
||||||
|
if (abort)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
if (theFileFormat.mChannelsPerFrame > 2)
|
||||||
|
{
|
||||||
|
CDLOG(@"MyGetOpenALAudioData - Unsupported Format, channel count is greater than stereo\n");
|
||||||
|
abort = YES;
|
||||||
|
}
|
||||||
|
if (abort)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
// Set the client format to 16 bit signed integer (native-endian) data
|
||||||
|
// Maintain the channel count and sample rate of the original source format
|
||||||
|
theOutputFormat.mSampleRate = theFileFormat.mSampleRate;
|
||||||
|
theOutputFormat.mChannelsPerFrame = theFileFormat.mChannelsPerFrame;
|
||||||
|
|
||||||
|
theOutputFormat.mFormatID = kAudioFormatLinearPCM;
|
||||||
|
theOutputFormat.mBytesPerPacket = 2 * theOutputFormat.mChannelsPerFrame;
|
||||||
|
theOutputFormat.mFramesPerPacket = 1;
|
||||||
|
theOutputFormat.mBytesPerFrame = 2 * theOutputFormat.mChannelsPerFrame;
|
||||||
|
theOutputFormat.mBitsPerChannel = 16;
|
||||||
|
theOutputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
|
||||||
|
|
||||||
|
// Set the desired client (output) data format
|
||||||
|
status = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(theOutputFormat), &theOutputFormat);
|
||||||
|
if (status != noErr)
|
||||||
|
{
|
||||||
|
CDLOG(@"MyGetOpenALAudioData: ExtAudioFileSetProperty(kExtAudioFileProperty_ClientDataFormat) FAILED, Error = %ld\n", status);
|
||||||
|
abort = YES;
|
||||||
|
}
|
||||||
|
if (abort)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
// Get the total frame count
|
||||||
|
thePropertySize = sizeof(theFileLengthInFrames);
|
||||||
|
status = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames);
|
||||||
|
if (status != noErr)
|
||||||
|
{
|
||||||
|
CDLOG(@"MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileLengthFrames) FAILED, Error = %ld\n", status);
|
||||||
|
abort = YES;
|
||||||
|
}
|
||||||
|
if (abort)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
// Read all the data into memory
|
||||||
|
dataSize = (UInt32) theFileLengthInFrames * theOutputFormat.mBytesPerFrame;
|
||||||
|
theData = malloc(dataSize);
|
||||||
|
if (theData)
|
||||||
|
{
|
||||||
|
memset(theData, 0, dataSize);
|
||||||
|
AudioBufferList theDataBuffer;
|
||||||
|
theDataBuffer.mNumberBuffers = 1;
|
||||||
|
theDataBuffer.mBuffers[0].mDataByteSize = dataSize;
|
||||||
|
theDataBuffer.mBuffers[0].mNumberChannels = theOutputFormat.mChannelsPerFrame;
|
||||||
|
theDataBuffer.mBuffers[0].mData = theData;
|
||||||
|
|
||||||
|
// Read the data into an AudioBufferList
|
||||||
|
status = ExtAudioFileRead(extRef, (UInt32*)&theFileLengthInFrames, &theDataBuffer);
|
||||||
|
if(status == noErr)
|
||||||
|
{
|
||||||
|
// success
|
||||||
|
*outDataSize = (ALsizei)dataSize;
|
||||||
|
*outDataFormat = (theOutputFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
|
||||||
|
*outSampleRate = (ALsizei)theOutputFormat.mSampleRate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// failure
|
||||||
|
free (theData);
|
||||||
|
theData = NULL; // make sure to return NULL
|
||||||
|
CDLOG(@"MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %ld\n", status);
|
||||||
|
abort = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (abort)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
// Dispose the ExtAudioFileRef, it is no longer needed
|
||||||
|
if (extRef) ExtAudioFileDispose(extRef);
|
||||||
|
return theData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* CDGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate) {
|
||||||
|
|
||||||
|
CFStringRef extension = CFURLCopyPathExtension(inFileURL);
|
||||||
|
CFComparisonResult isWavFile = 0;
|
||||||
|
if (extension != NULL) {
|
||||||
|
isWavFile = CFStringCompare (extension,(CFStringRef)@"wav", kCFCompareCaseInsensitive);
|
||||||
|
CFRelease(extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWavFile == kCFCompareEqualTo) {
|
||||||
|
return CDloadWaveAudioData(inFileURL, outDataSize, outDataFormat, outSampleRate);
|
||||||
|
} else {
|
||||||
|
return CDloadCafAudioData(inFileURL, outDataSize, outDataFormat, outSampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Steve Oldmeadow
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
A set of proxy classes to allow iOS audio code to run on MacOS X. AVAudioPlayer is implemented using NSSound.
|
||||||
|
AVAudioSession is a "do nothing" class as it isn't really relevant on MacOS X.
|
||||||
|
|
||||||
|
Limitations:
|
||||||
|
AVAudioPlayer numberOfLoops not correctly supported. Looping is either on or off, can not specify a specific number of loops.
|
||||||
|
AVAudioPlayer panning not supported.
|
||||||
|
AVAudioPlayer metering not supported.
|
||||||
|
AVAudioSession nothing is supported, not applicable to MacOS X.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Availability.h>
|
||||||
|
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
|
||||||
|
#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <AppKit/NSSound.h>
|
||||||
|
|
||||||
|
enum AudioSessionProperties {
|
||||||
|
kAudioSessionProperty_OtherAudioIsPlaying,
|
||||||
|
kAudioSessionProperty_AudioRoute
|
||||||
|
};
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern OSStatus AudioSessionGetProperty(UInt32 inID, UInt32 *ioDataSize, void *outData);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
Based on AVAudioPlayer.h header in AVFoundation headers
|
||||||
|
*/
|
||||||
|
@class NSData, NSURL, NSError, NSDictionary;
|
||||||
|
@protocol AVAudioPlayerDelegate;
|
||||||
|
|
||||||
|
/* This class is available with iPhone 2.2 or later */
|
||||||
|
@interface AVAudioPlayer : NSObject <NSSoundDelegate> {
|
||||||
|
|
||||||
|
// properties
|
||||||
|
id<AVAudioPlayerDelegate> delegate;
|
||||||
|
NSUInteger numberOfChannels;
|
||||||
|
BOOL playing;
|
||||||
|
NSTimeInterval duration;
|
||||||
|
NSURL *url;
|
||||||
|
NSData *data;
|
||||||
|
float pan;
|
||||||
|
float volume;
|
||||||
|
NSTimeInterval currentTime;
|
||||||
|
NSTimeInterval deviceCurrentTime;
|
||||||
|
NSInteger numberOfLoops;
|
||||||
|
BOOL meteringEnabled;
|
||||||
|
|
||||||
|
|
||||||
|
@private
|
||||||
|
NSSound* _player;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For all of these init calls, if a return value of nil is given you can check outError to see what the problem was.
|
||||||
|
If not nil, then the object is usable for playing
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* all data must be in the form of an audio file understood by CoreAudio */
|
||||||
|
- (id)initWithContentsOfURL:(NSURL *)theUrl error:(NSError **)outError;
|
||||||
|
- (id)initWithData:(NSData *)theData error:(NSError **)outError;
|
||||||
|
|
||||||
|
/* transport control */
|
||||||
|
/* methods that return BOOL return YES on success and NO on failure. */
|
||||||
|
- (BOOL)prepareToPlay; /* get ready to play the sound. happens automatically on play. */
|
||||||
|
- (BOOL)play; /* sound is played asynchronously. */
|
||||||
|
- (BOOL)playAtTime:(NSTimeInterval) time; /* play a sound some time in the future. time should be greater than deviceCurrentTime. */
|
||||||
|
- (void)pause; /* pauses playback, but remains ready to play. */
|
||||||
|
- (void)stop; /* stops playback. no longer ready to play. */
|
||||||
|
|
||||||
|
/* properties */
|
||||||
|
|
||||||
|
@property(readonly, getter=isPlaying) BOOL playing;
|
||||||
|
|
||||||
|
@property(readonly) NSUInteger numberOfChannels;
|
||||||
|
@property(readonly) NSTimeInterval duration; /* the duration of the sound. */
|
||||||
|
|
||||||
|
@property(assign) id<AVAudioPlayerDelegate> delegate; /* the delegate will be sent playerDidFinishPlaying */
|
||||||
|
|
||||||
|
/* one of these three properties will be non-nil based on the init... method used */
|
||||||
|
@property(readonly) NSURL *url; /* returns nil if object was not created with a URL */
|
||||||
|
@property(readonly) NSData *data; /* returns nil if object was not created with a data object */
|
||||||
|
@property float pan; /* set panning. -1.0 is left, 0.0 is center, 1.0 is right. */
|
||||||
|
@property float volume; /* The volume for the sound. The nominal range is from 0.0 to 1.0. */
|
||||||
|
|
||||||
|
/* If the sound is playing, currentTime is the offset into the sound of the current playback position.
|
||||||
|
If the sound is not playing, currentTime is the offset into the sound where playing would start. */
|
||||||
|
@property NSTimeInterval currentTime;
|
||||||
|
|
||||||
|
/* returns the current time associated with the output device */
|
||||||
|
@property(readonly) NSTimeInterval deviceCurrentTime;
|
||||||
|
|
||||||
|
/* "numberOfLoops" is the number of times that the sound will return to the beginning upon reaching the end.
|
||||||
|
A value of zero means to play the sound just once.
|
||||||
|
A value of one will result in playing the sound twice, and so on..
|
||||||
|
Any negative number will loop indefinitely until stopped.
|
||||||
|
*/
|
||||||
|
@property NSInteger numberOfLoops;
|
||||||
|
|
||||||
|
/* metering */
|
||||||
|
|
||||||
|
@property(getter=isMeteringEnabled) BOOL meteringEnabled; /* turns level metering on or off. default is off. */
|
||||||
|
|
||||||
|
- (void)updateMeters; /* call to refresh meter values */
|
||||||
|
- (float)peakPowerForChannel:(NSUInteger)channelNumber; /* returns peak power in decibels for a given channel */
|
||||||
|
- (float)averagePowerForChannel:(NSUInteger)channelNumber; /* returns average power in decibels for a given channel */
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/* A protocol for delegates of AVAudioPlayer */
|
||||||
|
@protocol AVAudioPlayerDelegate <NSObject>
|
||||||
|
@optional
|
||||||
|
/* audioPlayerDidFinishPlaying:successfully: is called when a sound has finished playing. This method is NOT called if the player is stopped due to an interruption. */
|
||||||
|
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
|
||||||
|
|
||||||
|
/* if an error occurs while decoding it will be reported to the delegate. */
|
||||||
|
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error;
|
||||||
|
|
||||||
|
/* audioPlayerBeginInterruption: is called when the audio session has been interrupted while the player was playing. The player will have been paused. */
|
||||||
|
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player;
|
||||||
|
|
||||||
|
/* audioPlayerEndInterruption:withFlags: is called when the audio session interruption has ended and this player had been interrupted while playing. */
|
||||||
|
/* Currently the only flag is AVAudioSessionInterruptionFlags_ShouldResume. */
|
||||||
|
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withFlags:(NSUInteger)flags;
|
||||||
|
|
||||||
|
/* audioPlayerEndInterruption: is called when the preferred method, audioPlayerEndInterruption:withFlags:, is not implemented. */
|
||||||
|
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Taken from AVAudioSession.h header in AVFoundation headers
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This protocol is available with iPhone 3.0 or later */
|
||||||
|
@protocol AVAudioSessionDelegate;
|
||||||
|
@class NSError, NSString;
|
||||||
|
|
||||||
|
/* values for the category property */
|
||||||
|
extern NSString *const AVAudioSessionCategoryAmbient;
|
||||||
|
extern NSString *const AVAudioSessionCategorySoloAmbient;
|
||||||
|
extern NSString *const AVAudioSessionCategoryPlayback;
|
||||||
|
extern NSString *const AVAudioSessionCategoryRecord;
|
||||||
|
extern NSString *const AVAudioSessionCategoryPlayAndRecord;
|
||||||
|
extern NSString *const AVAudioSessionCategoryAudioProcessing;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AVAudioSessionInterruptionFlags_ShouldResume = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AVAudioSessionSetActiveFlags_NotifyOthersOnDeactivation = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
@interface AVAudioSession : NSObject {
|
||||||
|
|
||||||
|
// properties
|
||||||
|
NSString* category;
|
||||||
|
double preferredHardwareSampleRate;
|
||||||
|
NSTimeInterval preferredIOBufferDuration;
|
||||||
|
|
||||||
|
BOOL inputIsAvailable;
|
||||||
|
double currentHardwareSampleRate;
|
||||||
|
NSInteger currentHardwareInputNumberOfChannels;
|
||||||
|
NSInteger currentHardwareOutputNumberOfChannels;
|
||||||
|
id<AVAudioSessionDelegate> delegate;
|
||||||
|
|
||||||
|
@private
|
||||||
|
__strong void *_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns singleton instance */
|
||||||
|
+ (id)sharedInstance;
|
||||||
|
|
||||||
|
@property(assign) id<AVAudioSessionDelegate> delegate;
|
||||||
|
|
||||||
|
- (BOOL)setActive:(BOOL)beActive error:(NSError**)outError;
|
||||||
|
- (BOOL)setActive:(BOOL)beActive withFlags:(NSInteger)flags error:(NSError**)outError;
|
||||||
|
|
||||||
|
- (BOOL)setCategory:(NSString*)theCategory error:(NSError**)outError;
|
||||||
|
- (BOOL)setPreferredHardwareSampleRate:(double)sampleRate error:(NSError**)outError;
|
||||||
|
- (BOOL)setPreferredIOBufferDuration:(NSTimeInterval)duration error:(NSError**)outError;
|
||||||
|
|
||||||
|
@property(readonly) NSString* category;
|
||||||
|
@property(readonly) double preferredHardwareSampleRate;
|
||||||
|
@property(readonly) NSTimeInterval preferredIOBufferDuration;
|
||||||
|
|
||||||
|
@property(readonly) BOOL inputIsAvailable;
|
||||||
|
@property(readonly) double currentHardwareSampleRate;
|
||||||
|
@property(readonly) NSInteger currentHardwareInputNumberOfChannels;
|
||||||
|
@property(readonly) NSInteger currentHardwareOutputNumberOfChannels;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
/* A protocol for delegates of AVAudioSession */
|
||||||
|
@protocol AVAudioSessionDelegate <NSObject>
|
||||||
|
@optional
|
||||||
|
|
||||||
|
- (void)beginInterruption;
|
||||||
|
|
||||||
|
- (void)endInterruptionWithFlags:(NSUInteger)flags;
|
||||||
|
|
||||||
|
- (void)endInterruption; /* endInterruptionWithFlags: will be called instead if implemented. */
|
||||||
|
|
||||||
|
- (void)inputIsAvailableChanged:(BOOL)isInputAvailable;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,176 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Steve Oldmeadow
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Availability.h>
|
||||||
|
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
|
||||||
|
#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
|
||||||
|
|
||||||
|
#import "CDXMacOSXSupport.h"
|
||||||
|
#import "SimpleAudioEngine.h"
|
||||||
|
#import "CocosDenshion.h"
|
||||||
|
|
||||||
|
NSString * const AVAudioSessionCategoryAmbient = @"AVAudioSessionCategoryAmbient";
|
||||||
|
NSString *const AVAudioSessionCategorySoloAmbient = @"AVAudioSessionCategorySoloAmbient";
|
||||||
|
NSString *const AVAudioSessionCategoryPlayback = @"AVAudioSessionCategoryPlayback";
|
||||||
|
NSString *const AVAudioSessionCategoryRecord = @"AVAudioSessionCategoryRecord";
|
||||||
|
NSString *const AVAudioSessionCategoryPlayAndRecord = @"AVAudioSessionCategoryPlayAndRecord";
|
||||||
|
NSString *const AVAudioSessionCategoryAudioProcessing = @"AVAudioSessionCategoryAudioProcessing";
|
||||||
|
|
||||||
|
OSStatus AudioSessionGetProperty(UInt32 inID, UInt32 *ioDataSize, void *outData) {
|
||||||
|
//TODO: set outData appropriately
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation AVAudioPlayer
|
||||||
|
|
||||||
|
@synthesize delegate, numberOfChannels, pan, deviceCurrentTime, url, data;
|
||||||
|
|
||||||
|
- (id)initWithContentsOfURL:(NSURL *)theUrl error:(NSError **)outError {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
_player = [[NSSound alloc] initWithContentsOfURL:theUrl byReference:YES];
|
||||||
|
if (_player != nil) {
|
||||||
|
_player.delegate = self;
|
||||||
|
CDLOG(@"Denshion::CDXMacOSXSupport - NSSound allocated for %@", theUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithData:(NSData *)theData error:(NSError **)outError {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
_player = [[NSSound alloc] initWithData:theData];
|
||||||
|
if (_player != nil) {
|
||||||
|
_player.delegate = self;
|
||||||
|
CDLOG(@"Denshion::CDXMacOSXSupport - NSSound allocated for %@", theData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-(void) dealloc {
|
||||||
|
[_player release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finished {
|
||||||
|
if (self.delegate && [self.delegate respondsToSelector:@selector(audioPlayerDidFinishPlaying:successfully:)]) {
|
||||||
|
[self.delegate audioPlayerDidFinishPlaying:self successfully:finished];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)play {
|
||||||
|
BOOL result;
|
||||||
|
result = [_player play];
|
||||||
|
if (!result) {
|
||||||
|
//May be paused, try resuming instead
|
||||||
|
result = [_player resume];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) pause {
|
||||||
|
[_player pause];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) stop {
|
||||||
|
[_player stop];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) isPlaying {
|
||||||
|
return [_player isPlaying];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setVolume:(float) vol {
|
||||||
|
[_player setVolume:vol];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(float) volume {
|
||||||
|
return [_player volume];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setNumberOfLoops:(NSInteger) nOfLoops {
|
||||||
|
if (nOfLoops < 0) {
|
||||||
|
[_player setLoops:YES];
|
||||||
|
} else {
|
||||||
|
[_player setLoops:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSInteger) numberOfLoops {
|
||||||
|
if (_player.loops) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setCurrentTime:(NSTimeInterval) aCurrentTime {
|
||||||
|
[_player setCurrentTime:aCurrentTime];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSTimeInterval) currentTime {
|
||||||
|
return [_player currentTime];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSTimeInterval) duration {
|
||||||
|
return [_player duration];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark unsupported
|
||||||
|
- (BOOL)prepareToPlay {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
-(BOOL)playAtTime:(NSTimeInterval)time {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
-(void) setMeteringEnabled:(BOOL) enabled {
|
||||||
|
}
|
||||||
|
-(BOOL) isMeteringEnabled {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
- (void)updateMeters{}
|
||||||
|
- (float)peakPowerForChannel:(NSUInteger)channelNumber{return 0.0f;}
|
||||||
|
- (float)averagePowerForChannel:(NSUInteger)channelNumber{return 0.0f;}
|
||||||
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
A "do nothing" implementation - AVAudioSession is not really relevant to Mac OS X.
|
||||||
|
*/
|
||||||
|
@implementation AVAudioSession
|
||||||
|
@synthesize delegate, category, preferredHardwareSampleRate, preferredIOBufferDuration;
|
||||||
|
@synthesize inputIsAvailable, currentHardwareSampleRate, currentHardwareInputNumberOfChannels, currentHardwareOutputNumberOfChannels;
|
||||||
|
|
||||||
|
+ (id)sharedInstance {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setActive:(BOOL)beActive error:(NSError**)outError {return YES;}
|
||||||
|
- (BOOL)setActive:(BOOL)beActive withFlags:(NSInteger)flags error:(NSError**)outError {return YES;}
|
||||||
|
- (BOOL)setCategory:(NSString*)theCategory error:(NSError**)outError {return YES;}
|
||||||
|
- (BOOL)setPreferredHardwareSampleRate:(double)sampleRate error:(NSError**)outError {return YES;}
|
||||||
|
- (BOOL)setPreferredIOBufferDuration:(NSTimeInterval)duration error:(NSError**)outError {return YES;}
|
||||||
|
|
||||||
|
@end
|
||||||
|
#endif
|
|
@ -0,0 +1,448 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Steve Oldmeadow
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file
|
||||||
|
@b IMPORTANT
|
||||||
|
There are 3 different ways of using CocosDenshion. Depending on which you choose you
|
||||||
|
will need to include different files and frameworks.
|
||||||
|
|
||||||
|
@par SimpleAudioEngine
|
||||||
|
This is recommended for basic audio requirements. If you just want to play some sound fx
|
||||||
|
and some background music and have no interest in learning the lower level workings then
|
||||||
|
this is the interface to use.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- Firmware: OS 2.2 or greater
|
||||||
|
- Files: SimpleAudioEngine.*, CocosDenshion.*
|
||||||
|
- Frameworks: OpenAL, AudioToolbox, AVFoundation
|
||||||
|
|
||||||
|
@par CDAudioManager
|
||||||
|
CDAudioManager is basically a thin wrapper around an AVAudioPlayer object used for playing
|
||||||
|
background music and a CDSoundEngine object used for playing sound effects. It manages the
|
||||||
|
audio session for you deals with audio session interruption. It is fairly low level and it
|
||||||
|
is expected you have some understanding of the underlying technologies. For example, for
|
||||||
|
many use cases regarding background music it is expected you will work directly with the
|
||||||
|
backgroundMusic AVAudioPlayer which is exposed as a property.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- Firmware: OS 2.2 or greater
|
||||||
|
- Files: CDAudioManager.*, CocosDenshion.*
|
||||||
|
- Frameworks: OpenAL, AudioToolbox, AVFoundation
|
||||||
|
|
||||||
|
@par CDSoundEngine
|
||||||
|
CDSoundEngine is a sound engine built upon OpenAL and derived from Apple's oalTouch
|
||||||
|
example. It can playback up to 32 sounds simultaneously with control over pitch, pan
|
||||||
|
and gain. It can be set up to handle audio session interruption automatically. You
|
||||||
|
may decide to use CDSoundEngine directly instead of CDAudioManager or SimpleAudioEngine
|
||||||
|
because you require OS 2.0 compatibility.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- Firmware: OS 2.0 or greater
|
||||||
|
- Files: CocosDenshion.*
|
||||||
|
- Frameworks: OpenAL, AudioToolbox
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <OpenAL/al.h>
|
||||||
|
#import <OpenAL/alc.h>
|
||||||
|
#import <AudioToolbox/AudioToolbox.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "CDConfig.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(CD_DEBUG) || CD_DEBUG == 0
|
||||||
|
#define CDLOG(...) do {} while (0)
|
||||||
|
#define CDLOGINFO(...) do {} while (0)
|
||||||
|
|
||||||
|
#elif CD_DEBUG == 1
|
||||||
|
#define CDLOG(...) NSLog(__VA_ARGS__)
|
||||||
|
#define CDLOGINFO(...) do {} while (0)
|
||||||
|
|
||||||
|
#elif CD_DEBUG > 1
|
||||||
|
#define CDLOG(...) NSLog(__VA_ARGS__)
|
||||||
|
#define CDLOGINFO(...) NSLog(__VA_ARGS__)
|
||||||
|
#endif // CD_DEBUG
|
||||||
|
|
||||||
|
|
||||||
|
#import "CDOpenALSupport.h"
|
||||||
|
|
||||||
|
//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
|
||||||
|
#define CD_SOURCE_LIMIT 32 //Total number of sources we will ever want, may actually get less
|
||||||
|
#define CD_NO_SOURCE 0xFEEDFAC //Return value indicating playback failed i.e. no source
|
||||||
|
#define CD_IGNORE_AUDIO_SESSION 0xBEEFBEE //Used internally to indicate audio session will not be handled
|
||||||
|
#define CD_MUTE 0xFEEDBAB //Return value indicating sound engine is muted or non functioning
|
||||||
|
#define CD_NO_SOUND = -1;
|
||||||
|
|
||||||
|
#define CD_SAMPLE_RATE_HIGH 44100
|
||||||
|
#define CD_SAMPLE_RATE_MID 22050
|
||||||
|
#define CD_SAMPLE_RATE_LOW 16000
|
||||||
|
#define CD_SAMPLE_RATE_BASIC 8000
|
||||||
|
#define CD_SAMPLE_RATE_DEFAULT 44100
|
||||||
|
|
||||||
|
extern NSString * const kCDN_BadAlContext;
|
||||||
|
extern NSString * const kCDN_AsynchLoadComplete;
|
||||||
|
|
||||||
|
extern float const kCD_PitchDefault;
|
||||||
|
extern float const kCD_PitchLowerOneOctave;
|
||||||
|
extern float const kCD_PitchHigherOneOctave;
|
||||||
|
extern float const kCD_PanDefault;
|
||||||
|
extern float const kCD_PanFullLeft;
|
||||||
|
extern float const kCD_PanFullRight;
|
||||||
|
extern float const kCD_GainDefault;
|
||||||
|
|
||||||
|
enum bufferState {
|
||||||
|
CD_BS_EMPTY = 0,
|
||||||
|
CD_BS_LOADED = 1,
|
||||||
|
CD_BS_FAILED = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _sourceGroup {
|
||||||
|
int startIndex;
|
||||||
|
int currentIndex;
|
||||||
|
int totalSources;
|
||||||
|
bool enabled;
|
||||||
|
bool nonInterruptible;
|
||||||
|
int *sourceStatuses;//pointer into array of source status information
|
||||||
|
} sourceGroup;
|
||||||
|
|
||||||
|
typedef struct _bufferInfo {
|
||||||
|
ALuint bufferId;
|
||||||
|
int bufferState;
|
||||||
|
void* bufferData;
|
||||||
|
ALenum format;
|
||||||
|
ALsizei sizeInBytes;
|
||||||
|
ALsizei frequencyInHertz;
|
||||||
|
} bufferInfo;
|
||||||
|
|
||||||
|
typedef struct _sourceInfo {
|
||||||
|
bool usable;
|
||||||
|
ALuint sourceId;
|
||||||
|
ALuint attachedBufferId;
|
||||||
|
} sourceInfo;
|
||||||
|
|
||||||
|
#pragma mark CDAudioTransportProtocol
|
||||||
|
|
||||||
|
@protocol CDAudioTransportProtocol <NSObject>
|
||||||
|
/** Play the audio */
|
||||||
|
-(BOOL) play;
|
||||||
|
/** Pause the audio, retain resources */
|
||||||
|
-(BOOL) pause;
|
||||||
|
/** Stop the audio, release resources */
|
||||||
|
-(BOOL) stop;
|
||||||
|
/** Return playback to beginning */
|
||||||
|
-(BOOL) rewind;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDAudioInterruptProtocol
|
||||||
|
|
||||||
|
@protocol CDAudioInterruptProtocol <NSObject>
|
||||||
|
/** Is audio mute */
|
||||||
|
-(BOOL) mute;
|
||||||
|
/** If YES then audio is silenced but not stopped, calls to start new audio will proceed but silently */
|
||||||
|
-(void) setMute:(BOOL) muteValue;
|
||||||
|
/** Is audio enabled */
|
||||||
|
-(BOOL) enabled;
|
||||||
|
/** If NO then all audio is stopped and any calls to start new audio will be ignored */
|
||||||
|
-(void) setEnabled:(BOOL) enabledValue;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDUtilities
|
||||||
|
/**
|
||||||
|
Collection of utilities required by CocosDenshion
|
||||||
|
*/
|
||||||
|
@interface CDUtilities : NSObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fundamentally the same as the corresponding method is CCFileUtils but added to break binding to cocos2d */
|
||||||
|
+(NSString*) fullPathFromRelativePath:(NSString*) relPath;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark CDSoundEngine
|
||||||
|
|
||||||
|
/** CDSoundEngine is built upon OpenAL and works with SDK 2.0.
|
||||||
|
CDSoundEngine is a sound engine built upon OpenAL and derived from Apple's oalTouch
|
||||||
|
example. It can playback up to 32 sounds simultaneously with control over pitch, pan
|
||||||
|
and gain. It can be set up to handle audio session interruption automatically. You
|
||||||
|
may decide to use CDSoundEngine directly instead of CDAudioManager or SimpleAudioEngine
|
||||||
|
because you require OS 2.0 compatibility.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- Firmware: OS 2.0 or greater
|
||||||
|
- Files: CocosDenshion.*
|
||||||
|
- Frameworks: OpenAL, AudioToolbox
|
||||||
|
|
||||||
|
@since v0.8
|
||||||
|
*/
|
||||||
|
@class CDSoundSource;
|
||||||
|
@interface CDSoundEngine : NSObject <CDAudioInterruptProtocol> {
|
||||||
|
|
||||||
|
bufferInfo *_buffers;
|
||||||
|
sourceInfo *_sources;
|
||||||
|
sourceGroup *_sourceGroups;
|
||||||
|
ALCcontext *context;
|
||||||
|
NSUInteger _sourceGroupTotal;
|
||||||
|
UInt32 _audioSessionCategory;
|
||||||
|
BOOL _handleAudioSession;
|
||||||
|
ALfloat _preMuteGain;
|
||||||
|
NSObject *_mutexBufferLoad;
|
||||||
|
BOOL mute_;
|
||||||
|
BOOL enabled_;
|
||||||
|
|
||||||
|
ALenum lastErrorCode_;
|
||||||
|
BOOL functioning_;
|
||||||
|
float asynchLoadProgress_;
|
||||||
|
BOOL getGainWorks_;
|
||||||
|
|
||||||
|
//For managing dynamic allocation of sources and buffers
|
||||||
|
int sourceTotal_;
|
||||||
|
int bufferTotal;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (readwrite, nonatomic) ALfloat masterGain;
|
||||||
|
@property (readonly) ALenum lastErrorCode;//Last OpenAL error code that was generated
|
||||||
|
@property (readonly) BOOL functioning;//Is the sound engine functioning
|
||||||
|
@property (readwrite) float asynchLoadProgress;
|
||||||
|
@property (readonly) BOOL getGainWorks;//Does getting the gain for a source work
|
||||||
|
/** Total number of sources available */
|
||||||
|
@property (readonly) int sourceTotal;
|
||||||
|
/** Total number of source groups that have been defined */
|
||||||
|
@property (readonly) NSUInteger sourceGroupTotal;
|
||||||
|
|
||||||
|
/** Sets the sample rate for the audio mixer. For best performance this should match the sample rate of your audio content */
|
||||||
|
+(void) setMixerSampleRate:(Float32) sampleRate;
|
||||||
|
|
||||||
|
/** Initializes the engine with a group definition and a total number of groups */
|
||||||
|
-(id)init;
|
||||||
|
|
||||||
|
/** Plays a sound in a channel group with a pitch, pan and gain. The sound could played looped or not */
|
||||||
|
-(ALuint) playSound:(int) soundId sourceGroupId:(int)sourceGroupId pitch:(float) pitch pan:(float) pan gain:(float) gain loop:(BOOL) loop;
|
||||||
|
|
||||||
|
/** Creates and returns a sound source object for the specified sound within the specified source group.
|
||||||
|
*/
|
||||||
|
-(CDSoundSource *) soundSourceForSound:(int) soundId sourceGroupId:(int) sourceGroupId;
|
||||||
|
|
||||||
|
/** Stops playing a sound */
|
||||||
|
- (void) stopSound:(ALuint) sourceId;
|
||||||
|
/** Stops playing a source group */
|
||||||
|
- (void) stopSourceGroup:(int) sourceGroupId;
|
||||||
|
/** Stops all playing sounds */
|
||||||
|
-(void) stopAllSounds;
|
||||||
|
/** Pause a sound */
|
||||||
|
-(void) pauseSound:(ALuint) sourceId;
|
||||||
|
/** Pause all sounds */
|
||||||
|
-(void) pauseAllSounds;
|
||||||
|
/** Resume a sound */
|
||||||
|
-(void) resumeSound:(ALuint) sourceId;
|
||||||
|
/** Resume all sounds */
|
||||||
|
-(void) resumeAllSounds;
|
||||||
|
-(void) defineSourceGroups:(NSArray*) sourceGroupDefinitions;
|
||||||
|
-(void) defineSourceGroups:(int[]) sourceGroupDefinitions total:(NSUInteger) total;
|
||||||
|
-(void) setSourceGroupNonInterruptible:(int) sourceGroupId isNonInterruptible:(BOOL) isNonInterruptible;
|
||||||
|
-(void) setSourceGroupEnabled:(int) sourceGroupId enabled:(BOOL) enabled;
|
||||||
|
-(BOOL) sourceGroupEnabled:(int) sourceGroupId;
|
||||||
|
-(BOOL) loadBufferFromData:(int) soundId soundData:(ALvoid*) soundData format:(ALenum) format size:(ALsizei) size freq:(ALsizei) freq;
|
||||||
|
-(BOOL) loadBuffer:(int) soundId filePath:(NSString*) filePath;
|
||||||
|
-(void) loadBuffersAsynchronously:(NSArray *) loadRequests;
|
||||||
|
-(BOOL) unloadBuffer:(int) soundId;
|
||||||
|
-(ALCcontext *) openALContext;
|
||||||
|
|
||||||
|
/** Returns the duration of the buffer in seconds or a negative value if the buffer id is invalid */
|
||||||
|
-(float) bufferDurationInSeconds:(int) soundId;
|
||||||
|
/** Returns the size of the buffer in bytes or a negative value if the buffer id is invalid */
|
||||||
|
-(ALsizei) bufferSizeInBytes:(int) soundId;
|
||||||
|
/** Returns the sampling frequency of the buffer in hertz or a negative value if the buffer id is invalid */
|
||||||
|
-(ALsizei) bufferFrequencyInHertz:(int) soundId;
|
||||||
|
|
||||||
|
/** Used internally, never call unless you know what you are doing */
|
||||||
|
-(void) _soundSourcePreRelease:(CDSoundSource *) soundSource;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDSoundSource
|
||||||
|
/** CDSoundSource is a wrapper around an OpenAL sound source.
|
||||||
|
It allows you to manipulate properties such as pitch, gain, pan and looping while the
|
||||||
|
sound is playing. CDSoundSource is based on the old CDSourceWrapper class but with much
|
||||||
|
added functionality.
|
||||||
|
|
||||||
|
@since v1.0
|
||||||
|
*/
|
||||||
|
@interface CDSoundSource : NSObject <CDAudioTransportProtocol, CDAudioInterruptProtocol> {
|
||||||
|
ALenum lastError;
|
||||||
|
@public
|
||||||
|
ALuint _sourceId;
|
||||||
|
ALuint _sourceIndex;
|
||||||
|
CDSoundEngine* _engine;
|
||||||
|
int _soundId;
|
||||||
|
float _preMuteGain;
|
||||||
|
BOOL enabled_;
|
||||||
|
BOOL mute_;
|
||||||
|
}
|
||||||
|
@property (readwrite, nonatomic) float pitch;
|
||||||
|
@property (readwrite, nonatomic) float gain;
|
||||||
|
@property (readwrite, nonatomic) float pan;
|
||||||
|
@property (readwrite, nonatomic) BOOL looping;
|
||||||
|
@property (readonly) BOOL isPlaying;
|
||||||
|
@property (readwrite, nonatomic) int soundId;
|
||||||
|
/** Returns the duration of the attached buffer in seconds or a negative value if the buffer is invalid */
|
||||||
|
@property (readonly) float durationInSeconds;
|
||||||
|
|
||||||
|
/** Stores the last error code that occurred. Check against AL_NO_ERROR */
|
||||||
|
@property (readonly) ALenum lastError;
|
||||||
|
/** Do not init yourself, get an instance from the sourceForSound factory method on CDSoundEngine */
|
||||||
|
-(id)init:(ALuint) theSourceId sourceIndex:(int) index soundEngine:(CDSoundEngine*) engine;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDAudioInterruptTargetGroup
|
||||||
|
|
||||||
|
/** Container for objects that implement audio interrupt protocol i.e. they can be muted and enabled.
|
||||||
|
Setting mute and enabled for the group propagates to all children.
|
||||||
|
Designed to be used with your CDSoundSource objects to get them to comply with global enabled and mute settings
|
||||||
|
if that is what you want to do.*/
|
||||||
|
@interface CDAudioInterruptTargetGroup : NSObject <CDAudioInterruptProtocol> {
|
||||||
|
BOOL mute_;
|
||||||
|
BOOL enabled_;
|
||||||
|
NSMutableArray *children_;
|
||||||
|
}
|
||||||
|
-(void) addAudioInterruptTarget:(NSObject<CDAudioInterruptProtocol>*) interruptibleTarget;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDAsynchBufferLoader
|
||||||
|
|
||||||
|
/** CDAsynchBufferLoader
|
||||||
|
TODO
|
||||||
|
*/
|
||||||
|
@interface CDAsynchBufferLoader : NSOperation {
|
||||||
|
NSArray *_loadRequests;
|
||||||
|
CDSoundEngine *_soundEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(id) init:(NSArray *)loadRequests soundEngine:(CDSoundEngine *) theSoundEngine;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDBufferLoadRequest
|
||||||
|
|
||||||
|
/** CDBufferLoadRequest */
|
||||||
|
@interface CDBufferLoadRequest: NSObject
|
||||||
|
{
|
||||||
|
NSString *filePath;
|
||||||
|
int soundId;
|
||||||
|
//id loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (readonly) NSString *filePath;
|
||||||
|
@property (readonly) int soundId;
|
||||||
|
|
||||||
|
- (id)init:(int) theSoundId filePath:(const NSString *) theFilePath;
|
||||||
|
@end
|
||||||
|
|
||||||
|
/** Interpolation type */
|
||||||
|
typedef enum {
|
||||||
|
kIT_Linear, //!Straight linear interpolation fade
|
||||||
|
kIT_SCurve, //!S curved interpolation
|
||||||
|
kIT_Exponential //!Exponential interpolation
|
||||||
|
} tCDInterpolationType;
|
||||||
|
|
||||||
|
#pragma mark CDFloatInterpolator
|
||||||
|
@interface CDFloatInterpolator: NSObject
|
||||||
|
{
|
||||||
|
float start;
|
||||||
|
float end;
|
||||||
|
float lastValue;
|
||||||
|
tCDInterpolationType interpolationType;
|
||||||
|
}
|
||||||
|
@property (readwrite, nonatomic) float start;
|
||||||
|
@property (readwrite, nonatomic) float end;
|
||||||
|
@property (readwrite, nonatomic) tCDInterpolationType interpolationType;
|
||||||
|
|
||||||
|
/** Return a value between min and max based on t which represents fractional progress where 0 is the start
|
||||||
|
and 1 is the end */
|
||||||
|
-(float) interpolate:(float) t;
|
||||||
|
-(id) init:(tCDInterpolationType) type startVal:(float) startVal endVal:(float) endVal;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDPropertyModifier
|
||||||
|
|
||||||
|
/** Base class for classes that modify properties such as pitch, pan and gain */
|
||||||
|
@interface CDPropertyModifier: NSObject
|
||||||
|
{
|
||||||
|
CDFloatInterpolator *interpolator;
|
||||||
|
float startValue;
|
||||||
|
float endValue;
|
||||||
|
id target;
|
||||||
|
BOOL stopTargetWhenComplete;
|
||||||
|
|
||||||
|
}
|
||||||
|
@property (readwrite, nonatomic) BOOL stopTargetWhenComplete;
|
||||||
|
@property (readwrite, nonatomic) float startValue;
|
||||||
|
@property (readwrite, nonatomic) float endValue;
|
||||||
|
@property (readwrite, nonatomic) tCDInterpolationType interpolationType;
|
||||||
|
|
||||||
|
-(id) init:(id) theTarget interpolationType:(tCDInterpolationType) type startVal:(float) startVal endVal:(float) endVal;
|
||||||
|
/** Set to a fractional value between 0 and 1 where 0 equals the start and 1 equals the end*/
|
||||||
|
-(void) modify:(float) t;
|
||||||
|
|
||||||
|
-(void) _setTargetProperty:(float) newVal;
|
||||||
|
-(float) _getTargetProperty;
|
||||||
|
-(void) _stopTarget;
|
||||||
|
-(Class) _allowableType;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDSoundSourceFader
|
||||||
|
|
||||||
|
/** Fader for CDSoundSource objects */
|
||||||
|
@interface CDSoundSourceFader : CDPropertyModifier{}
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDSoundSourcePanner
|
||||||
|
|
||||||
|
/** Panner for CDSoundSource objects */
|
||||||
|
@interface CDSoundSourcePanner : CDPropertyModifier{}
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDSoundSourcePitchBender
|
||||||
|
|
||||||
|
/** Pitch bender for CDSoundSource objects */
|
||||||
|
@interface CDSoundSourcePitchBender : CDPropertyModifier{}
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark CDSoundEngineFader
|
||||||
|
|
||||||
|
/** Fader for CDSoundEngine objects */
|
||||||
|
@interface CDSoundEngineFader : CDPropertyModifier{}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,280 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "SimpleAudioEngine.h"
|
||||||
|
#include "SimpleAudioEngine_objc.h"
|
||||||
|
|
||||||
|
static void static_end()
|
||||||
|
{
|
||||||
|
[SimpleAudioEngine end];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_preloadBackgroundMusic(const char* pszFilePath)
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] preloadBackgroundMusic: [NSString stringWithUTF8String: pszFilePath]];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_playBackgroundMusic(const char* pszFilePath, bool bLoop)
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] playBackgroundMusic: [NSString stringWithUTF8String: pszFilePath] loop: bLoop];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_stopBackgroundMusic()
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] stopBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_pauseBackgroundMusic()
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] pauseBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_resumeBackgroundMusic()
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] resumeBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_rewindBackgroundMusic()
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] rewindBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool static_willPlayBackgroundMusic()
|
||||||
|
{
|
||||||
|
return [[SimpleAudioEngine sharedEngine] willPlayBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool static_isBackgroundMusicPlaying()
|
||||||
|
{
|
||||||
|
return [[SimpleAudioEngine sharedEngine] isBackgroundMusicPlaying];
|
||||||
|
}
|
||||||
|
|
||||||
|
static float static_getBackgroundMusicVolume()
|
||||||
|
{
|
||||||
|
return [[SimpleAudioEngine sharedEngine] backgroundMusicVolume];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_setBackgroundMusicVolume(float volume)
|
||||||
|
{
|
||||||
|
volume = MAX( MIN(volume, 1.0), 0 );
|
||||||
|
[SimpleAudioEngine sharedEngine].backgroundMusicVolume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float static_getEffectsVolume()
|
||||||
|
{
|
||||||
|
return [[SimpleAudioEngine sharedEngine] effectsVolume];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_setEffectsVolume(float volume)
|
||||||
|
{
|
||||||
|
volume = MAX( MIN(volume, 1.0), 0 );
|
||||||
|
[SimpleAudioEngine sharedEngine].effectsVolume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int static_playEffect(const char* pszFilePath, bool bLoop)
|
||||||
|
{
|
||||||
|
return [[SimpleAudioEngine sharedEngine] playEffect:[NSString stringWithUTF8String: pszFilePath] loop:bLoop];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_stopEffect(int nSoundId)
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] stopEffect: nSoundId];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_preloadEffect(const char* pszFilePath)
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] preloadEffect: [NSString stringWithUTF8String: pszFilePath]];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_unloadEffect(const char* pszFilePath)
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] unloadEffect: [NSString stringWithUTF8String: pszFilePath]];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_pauseEffect(unsigned int uSoundId)
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] pauseEffect: uSoundId];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_pauseAllEffects()
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] pauseAllEffects];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_resumeEffect(unsigned int uSoundId)
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] resumeEffect: uSoundId];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_resumeAllEffects()
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] resumeAllEffects];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_stopAllEffects()
|
||||||
|
{
|
||||||
|
[[SimpleAudioEngine sharedEngine] stopAllEffects];
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CocosDenshion {
|
||||||
|
|
||||||
|
static SimpleAudioEngine *s_pEngine;
|
||||||
|
|
||||||
|
SimpleAudioEngine::SimpleAudioEngine()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleAudioEngine::~SimpleAudioEngine()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleAudioEngine* SimpleAudioEngine::sharedEngine()
|
||||||
|
{
|
||||||
|
if (! s_pEngine)
|
||||||
|
{
|
||||||
|
s_pEngine = new SimpleAudioEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_pEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::end()
|
||||||
|
{
|
||||||
|
if (s_pEngine)
|
||||||
|
{
|
||||||
|
delete s_pEngine;
|
||||||
|
s_pEngine = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath)
|
||||||
|
{
|
||||||
|
static_preloadBackgroundMusic(pszFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop)
|
||||||
|
{
|
||||||
|
static_playBackgroundMusic(pszFilePath, bLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData)
|
||||||
|
{
|
||||||
|
static_stopBackgroundMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::pauseBackgroundMusic()
|
||||||
|
{
|
||||||
|
static_pauseBackgroundMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::resumeBackgroundMusic()
|
||||||
|
{
|
||||||
|
static_resumeBackgroundMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::rewindBackgroundMusic()
|
||||||
|
{
|
||||||
|
static_rewindBackgroundMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimpleAudioEngine::willPlayBackgroundMusic()
|
||||||
|
{
|
||||||
|
return static_willPlayBackgroundMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimpleAudioEngine::isBackgroundMusicPlaying()
|
||||||
|
{
|
||||||
|
return static_isBackgroundMusicPlaying();
|
||||||
|
}
|
||||||
|
|
||||||
|
float SimpleAudioEngine::getBackgroundMusicVolume()
|
||||||
|
{
|
||||||
|
return static_getBackgroundMusicVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::setBackgroundMusicVolume(float volume)
|
||||||
|
{
|
||||||
|
static_setBackgroundMusicVolume(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SimpleAudioEngine::getEffectsVolume()
|
||||||
|
{
|
||||||
|
return static_getEffectsVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::setEffectsVolume(float volume)
|
||||||
|
{
|
||||||
|
static_setEffectsVolume(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop)
|
||||||
|
{
|
||||||
|
return static_playEffect(pszFilePath, bLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::stopEffect(unsigned int nSoundId)
|
||||||
|
{
|
||||||
|
static_stopEffect(nSoundId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::preloadEffect(const char* pszFilePath)
|
||||||
|
{
|
||||||
|
static_preloadEffect(pszFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::unloadEffect(const char* pszFilePath)
|
||||||
|
{
|
||||||
|
static_unloadEffect(pszFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::pauseEffect(unsigned int uSoundId)
|
||||||
|
{
|
||||||
|
static_pauseEffect(uSoundId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::resumeEffect(unsigned int uSoundId)
|
||||||
|
{
|
||||||
|
static_resumeEffect(uSoundId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::pauseAllEffects()
|
||||||
|
{
|
||||||
|
static_pauseAllEffects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::resumeAllEffects()
|
||||||
|
{
|
||||||
|
static_resumeAllEffects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleAudioEngine::stopAllEffects()
|
||||||
|
{
|
||||||
|
static_stopAllEffects();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // endof namespace CocosDenshion {
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Steve Oldmeadow
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#import "CDAudioManager.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
A wrapper to the CDAudioManager object.
|
||||||
|
This is recommended for basic audio requirements. If you just want to play some sound fx
|
||||||
|
and some background music and have no interest in learning the lower level workings then
|
||||||
|
this is the interface to use.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- Firmware: OS 2.2 or greater
|
||||||
|
- Files: SimpleAudioEngine.*, CocosDenshion.*
|
||||||
|
- Frameworks: OpenAL, AudioToolbox, AVFoundation
|
||||||
|
@since v0.8
|
||||||
|
*/
|
||||||
|
@interface SimpleAudioEngine : NSObject <CDAudioInterruptProtocol> {
|
||||||
|
|
||||||
|
BOOL mute_;
|
||||||
|
BOOL enabled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Background music volume. Range is 0.0f to 1.0f. This will only have an effect if willPlayBackgroundMusic returns YES */
|
||||||
|
@property (readwrite) float backgroundMusicVolume;
|
||||||
|
/** Effects volume. Range is 0.0f to 1.0f */
|
||||||
|
@property (readwrite) float effectsVolume;
|
||||||
|
/** 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.*/
|
||||||
|
@property (readonly) BOOL willPlayBackgroundMusic;
|
||||||
|
|
||||||
|
/** returns the shared instance of the SimpleAudioEngine object */
|
||||||
|
+ (SimpleAudioEngine*) sharedEngine;
|
||||||
|
|
||||||
|
/** Preloads a music file so it will be ready to play as background music */
|
||||||
|
-(void) preloadBackgroundMusic:(NSString*) filePath;
|
||||||
|
|
||||||
|
/** plays background music in a loop*/
|
||||||
|
-(void) playBackgroundMusic:(NSString*) filePath;
|
||||||
|
/** plays background music, if loop is true the music will repeat otherwise it will be played once */
|
||||||
|
-(void) playBackgroundMusic:(NSString*) filePath loop:(BOOL) loop;
|
||||||
|
/** stops playing background music */
|
||||||
|
-(void) stopBackgroundMusic;
|
||||||
|
/** pauses the background music */
|
||||||
|
-(void) pauseBackgroundMusic;
|
||||||
|
/** resume background music that has been paused */
|
||||||
|
-(void) resumeBackgroundMusic;
|
||||||
|
/** rewind the background music */
|
||||||
|
-(void) rewindBackgroundMusic;
|
||||||
|
/** returns whether or not the background music is playing */
|
||||||
|
-(BOOL) isBackgroundMusicPlaying;
|
||||||
|
|
||||||
|
/** plays an audio effect with a file path*/
|
||||||
|
-(ALuint) playEffect:(NSString*) filePath loop:(BOOL) loop;
|
||||||
|
/** stop a sound that is playing, note you must pass in the soundId that is returned when you started playing the sound with playEffect */
|
||||||
|
-(void) stopEffect:(ALuint) soundId;
|
||||||
|
/** plays an audio effect with a file path, pitch, pan and gain */
|
||||||
|
-(ALuint) playEffect:(NSString*) filePath loop:(BOOL)loop pitch:(Float32) pitch pan:(Float32) pan gain:(Float32) gain;
|
||||||
|
/** pause an audio */
|
||||||
|
-(void) pauseEffect:(ALuint) soundId;
|
||||||
|
/** pause all audioes */
|
||||||
|
-(void) pauseAllEffects;
|
||||||
|
/** resume an audio */
|
||||||
|
-(void) resumeEffect:(ALuint) soundId;
|
||||||
|
/** resume all audioes */
|
||||||
|
-(void) resumeAllEffects;
|
||||||
|
/** stop all audioes */
|
||||||
|
-(void) stopAllEffects;
|
||||||
|
/** preloads an audio effect */
|
||||||
|
-(void) preloadEffect:(NSString*) filePath;
|
||||||
|
/** unloads an audio effect from memory */
|
||||||
|
-(void) unloadEffect:(NSString*) filePath;
|
||||||
|
/** Gets a CDSoundSource object set up to play the specified file. */
|
||||||
|
-(CDSoundSource *) soundSourceForFile:(NSString*) filePath;
|
||||||
|
|
||||||
|
/** Shuts down the shared audio engine instance so that it can be reinitialised */
|
||||||
|
+(void) end;
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,240 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Steve Oldmeadow
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "SimpleAudioEngine_objc.h"
|
||||||
|
|
||||||
|
@implementation SimpleAudioEngine
|
||||||
|
|
||||||
|
static SimpleAudioEngine *sharedEngine = nil;
|
||||||
|
static CDSoundEngine* soundEngine = nil;
|
||||||
|
static CDAudioManager *am = nil;
|
||||||
|
static CDBufferManager *bufferManager = nil;
|
||||||
|
|
||||||
|
// Init
|
||||||
|
+ (SimpleAudioEngine *) sharedEngine
|
||||||
|
{
|
||||||
|
@synchronized(self) {
|
||||||
|
if (!sharedEngine)
|
||||||
|
sharedEngine = [[SimpleAudioEngine alloc] init];
|
||||||
|
}
|
||||||
|
return sharedEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id) alloc
|
||||||
|
{
|
||||||
|
@synchronized(self) {
|
||||||
|
NSAssert(sharedEngine == nil, @"Attempted to allocate a second instance of a singleton.");
|
||||||
|
return [super alloc];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(id) init
|
||||||
|
{
|
||||||
|
if((self=[super init])) {
|
||||||
|
am = [CDAudioManager sharedManager];
|
||||||
|
soundEngine = am.soundEngine;
|
||||||
|
bufferManager = [[CDBufferManager alloc] initWithEngine:soundEngine];
|
||||||
|
mute_ = NO;
|
||||||
|
enabled_ = YES;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
am = nil;
|
||||||
|
soundEngine = nil;
|
||||||
|
bufferManager = nil;
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
+(void) end
|
||||||
|
{
|
||||||
|
am = nil;
|
||||||
|
[CDAudioManager end];
|
||||||
|
[bufferManager release];
|
||||||
|
[sharedEngine release];
|
||||||
|
sharedEngine = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark SimpleAudioEngine - background music
|
||||||
|
|
||||||
|
-(void) preloadBackgroundMusic:(NSString*) filePath {
|
||||||
|
[am preloadBackgroundMusic:filePath];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) playBackgroundMusic:(NSString*) filePath
|
||||||
|
{
|
||||||
|
[am playBackgroundMusic:filePath loop:TRUE];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) playBackgroundMusic:(NSString*) filePath loop:(BOOL) loop
|
||||||
|
{
|
||||||
|
[am playBackgroundMusic:filePath loop:loop];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) stopBackgroundMusic
|
||||||
|
{
|
||||||
|
[am stopBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) pauseBackgroundMusic {
|
||||||
|
[am pauseBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) resumeBackgroundMusic {
|
||||||
|
[am resumeBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) rewindBackgroundMusic {
|
||||||
|
[am rewindBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) isBackgroundMusicPlaying {
|
||||||
|
return [am isBackgroundMusicPlaying];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) willPlayBackgroundMusic {
|
||||||
|
return [am willPlayBackgroundMusic];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark SimpleAudioEngine - sound effects
|
||||||
|
|
||||||
|
-(ALuint) playEffect:(NSString*) filePath loop:(BOOL) loop
|
||||||
|
{
|
||||||
|
return [self playEffect:filePath loop:loop pitch:1.0f pan:0.0f gain:1.0f];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(ALuint) playEffect:(NSString*) filePath loop:(BOOL) loop pitch:(Float32) pitch pan:(Float32) pan gain:(Float32) gain
|
||||||
|
{
|
||||||
|
int soundId = [bufferManager bufferForFile:filePath create:YES];
|
||||||
|
if (soundId != kCDNoBuffer) {
|
||||||
|
return [soundEngine playSound:soundId sourceGroupId:0 pitch:pitch pan:pan gain:gain loop:loop];
|
||||||
|
} else {
|
||||||
|
return CD_MUTE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) stopEffect:(ALuint) soundId {
|
||||||
|
[soundEngine stopSound:soundId];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) pauseEffect:(ALuint) soundId {
|
||||||
|
[soundEngine pauseSound: soundId];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) pauseAllEffects {
|
||||||
|
[soundEngine pauseAllSounds];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) resumeEffect:(ALuint) soundId {
|
||||||
|
[soundEngine resumeSound: soundId];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) resumeAllEffects {
|
||||||
|
[soundEngine resumeAllSounds];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) stopAllEffects {
|
||||||
|
[soundEngine stopAllSounds];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) preloadEffect:(NSString*) filePath
|
||||||
|
{
|
||||||
|
int soundId = [bufferManager bufferForFile:filePath create:YES];
|
||||||
|
if (soundId == kCDNoBuffer) {
|
||||||
|
CDLOG(@"Denshion::SimpleAudioEngine sound failed to preload %@",filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) unloadEffect:(NSString*) filePath
|
||||||
|
{
|
||||||
|
CDLOGINFO(@"Denshion::SimpleAudioEngine unloadedEffect %@",filePath);
|
||||||
|
[bufferManager releaseBufferForFile:filePath];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Audio Interrupt Protocol
|
||||||
|
-(BOOL) mute
|
||||||
|
{
|
||||||
|
return mute_;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setMute:(BOOL) muteValue
|
||||||
|
{
|
||||||
|
if (mute_ != muteValue) {
|
||||||
|
mute_ = muteValue;
|
||||||
|
am.mute = mute_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) enabled
|
||||||
|
{
|
||||||
|
return enabled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setEnabled:(BOOL) enabledValue
|
||||||
|
{
|
||||||
|
if (enabled_ != enabledValue) {
|
||||||
|
enabled_ = enabledValue;
|
||||||
|
am.enabled = enabled_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark SimpleAudioEngine - BackgroundMusicVolume
|
||||||
|
-(float) backgroundMusicVolume
|
||||||
|
{
|
||||||
|
return am.backgroundMusic.volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setBackgroundMusicVolume:(float) volume
|
||||||
|
{
|
||||||
|
am.backgroundMusic.volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark SimpleAudioEngine - EffectsVolume
|
||||||
|
-(float) effectsVolume
|
||||||
|
{
|
||||||
|
return am.soundEngine.masterGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setEffectsVolume:(float) volume
|
||||||
|
{
|
||||||
|
am.soundEngine.masterGain = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(CDSoundSource *) soundSourceForFile:(NSString*) filePath {
|
||||||
|
int soundId = [bufferManager bufferForFile:filePath create:YES];
|
||||||
|
if (soundId != kCDNoBuffer) {
|
||||||
|
CDSoundSource *result = [soundEngine soundSourceForSound:soundId sourceGroupId:0];
|
||||||
|
CDLOGINFO(@"Denshion::SimpleAudioEngine sound source created for %@",filePath);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -144,13 +144,20 @@ THE SOFTWARE.
|
||||||
#endif // CC_TARGET_PLATFROM == CC_PLATFORM_ANDROID
|
#endif // CC_TARGET_PLATFROM == CC_PLATFORM_ANDROID
|
||||||
|
|
||||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
|
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
|
||||||
#include "platform/win32/CCAccelerometer.h"
|
#include "platform/win32/CCAccelerometer.h"
|
||||||
#include "platform/win32/CCApplication.h"
|
#include "platform/win32/CCApplication.h"
|
||||||
#include "platform/win32/CCEGLView.h"
|
#include "platform/win32/CCEGLView.h"
|
||||||
#include "platform/win32/CCGL.h"
|
#include "platform/win32/CCGL.h"
|
||||||
#include "platform/win32/CCStdC.h"
|
#include "platform/win32/CCStdC.h"
|
||||||
#endif // CC_TARGET_PLATFROM == CC_PLATFORM_WIN32
|
#endif // CC_TARGET_PLATFROM == CC_PLATFORM_WIN32
|
||||||
|
|
||||||
|
#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
|
||||||
|
#include "platform/mac/CCAccelerometer.h"
|
||||||
|
#include "platform/mac/CCApplication.h"
|
||||||
|
#include "platform/mac/CCEGLView.h"
|
||||||
|
#include "platform/mac/CCGL.h"
|
||||||
|
#include "platform/mac/CCStdC.h"
|
||||||
|
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_MAC
|
||||||
|
|
||||||
// script_support
|
// script_support
|
||||||
#include "script_support/CCScriptSupport.h"
|
#include "script_support/CCScriptSupport.h"
|
||||||
|
|
|
@ -29,7 +29,7 @@ THE SOFTWARE.
|
||||||
#include "CCDirector.h"
|
#include "CCDirector.h"
|
||||||
#include "cocoa/CCDictionary.h"
|
#include "cocoa/CCDictionary.h"
|
||||||
|
|
||||||
#if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
|
#if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS && CC_TARGET_PLATFORM != CC_PLATFORM_MAC)
|
||||||
|
|
||||||
#include "cocoa/CCString.h"
|
#include "cocoa/CCString.h"
|
||||||
#include "CCSAXParser.h"
|
#include "CCSAXParser.h"
|
||||||
|
@ -455,4 +455,4 @@ bool CCFileUtils::isPopupNotify()
|
||||||
|
|
||||||
NS_CC_END
|
NS_CC_END
|
||||||
|
|
||||||
#endif // (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
|
#endif // (CC_TARGET_PLATFORM != CC_PLATFORM_IOS && CC_TARGET_PLATFORM != CC_PLATFORM_MAC)
|
||||||
|
|
|
@ -36,7 +36,7 @@ THE SOFTWARE.
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
|
#if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS && CC_TARGET_PLATFORM != CC_PLATFORM_MAC)
|
||||||
|
|
||||||
NS_CC_BEGIN
|
NS_CC_BEGIN
|
||||||
|
|
||||||
|
@ -860,7 +860,7 @@ bool CCImage::_saveImageToJPG(const char * pszFilePath)
|
||||||
|
|
||||||
NS_CC_END
|
NS_CC_END
|
||||||
|
|
||||||
#endif // (CC_TARGET_PLATFORM != TARGET_OS_IPHONE)
|
#endif // (CC_TARGET_PLATFORM != TARGET_OS_IPHONE && CC_TARGET_PLATFORM != CC_PLATFORM_MAC)
|
||||||
/* ios/CCImage_ios.mm uses "mm" as the extension,
|
/* ios/CCImage_ios.mm uses "mm" as the extension,
|
||||||
so we cannot inclue it in this CCImage.cpp.
|
so we cannot inclue it in this CCImage.cpp.
|
||||||
It makes a little difference on ios */
|
It makes a little difference on ios */
|
||||||
|
|
|
@ -45,6 +45,7 @@ build for which target platform
|
||||||
#define CC_PLATFORM_LINUX 5
|
#define CC_PLATFORM_LINUX 5
|
||||||
#define CC_PLATFORM_BADA 6
|
#define CC_PLATFORM_BADA 6
|
||||||
#define CC_PLATFORM_QNX 7
|
#define CC_PLATFORM_QNX 7
|
||||||
|
#define CC_PLATFORM_MAC 8
|
||||||
|
|
||||||
// Determine tartet platform by compile environment macro.
|
// Determine tartet platform by compile environment macro.
|
||||||
#define CC_TARGET_PLATFORM CC_PLATFORM_UNKNOWN
|
#define CC_TARGET_PLATFORM CC_PLATFORM_UNKNOWN
|
||||||
|
@ -92,6 +93,13 @@ build for which target platform
|
||||||
#define CC_TARGET_PLATFORM CC_PLATFORM_QNX
|
#define CC_TARGET_PLATFORM CC_PLATFORM_QNX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// mac
|
||||||
|
#if ! CC_TARGET_PLATFORM && defined(TARGET_OS_MAC)
|
||||||
|
#undef CC_TARGET_PLATFORM
|
||||||
|
#define CC_TARGET_PLATFORM CC_PLATFORM_MAC
|
||||||
|
//#define CC_SUPPORT_PVRTC
|
||||||
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// post configure
|
// post configure
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __PLATFORM_MAC_CCACCELEROMETER_H__
|
||||||
|
#define __PLATFORM_MAC_CCACCELEROMETER_H__
|
||||||
|
|
||||||
|
#include "CCAccelerometerDelegate.h"
|
||||||
|
|
||||||
|
namespace cocos2d {
|
||||||
|
|
||||||
|
class CC_DLL CCAccelerometer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CCAccelerometer() {}
|
||||||
|
~CCAccelerometer() {}
|
||||||
|
|
||||||
|
void setDelegate(CCAccelerometerDelegate* pDelegate) { CC_UNUSED_PARAM(pDelegate); }
|
||||||
|
};
|
||||||
|
|
||||||
|
}//namespace cocos2d
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,79 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef __CC_APPLICATION_MAC_H__
|
||||||
|
#define __CC_APPLICATION_MAC_H__
|
||||||
|
|
||||||
|
#include "platform/CCCommon.h"
|
||||||
|
#include "platform/CCApplicationProtocol.h"
|
||||||
|
|
||||||
|
NS_CC_BEGIN;
|
||||||
|
|
||||||
|
class CCRect;
|
||||||
|
class CCApplication;
|
||||||
|
|
||||||
|
class CC_DLL CCApplication : public CCApplicationProtocol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CCApplication();
|
||||||
|
virtual ~CCApplication();
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Callback by CCDirector for limit FPS.
|
||||||
|
@interval The time, which expressed in second in second, between current frame and next.
|
||||||
|
*/
|
||||||
|
void setAnimationInterval(double interval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Get status bar rectangle in EGLView window.
|
||||||
|
*/
|
||||||
|
//void statusBarFrame(CCRect * rect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Run the message loop.
|
||||||
|
*/
|
||||||
|
int run();
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Get current applicaiton instance.
|
||||||
|
@return Current application instance pointer.
|
||||||
|
*/
|
||||||
|
static CCApplication& sharedApplication();
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Get current language config
|
||||||
|
@return Current language config
|
||||||
|
*/
|
||||||
|
virtual ccLanguageType getCurrentLanguage();
|
||||||
|
|
||||||
|
virtual bool isIpad();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static CCApplication * sm_pSharedApplication;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_CC_END;
|
||||||
|
|
||||||
|
#endif // end of __CC_APPLICATION_MAC_H__
|
|
@ -0,0 +1,113 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#import "CCApplication.h"
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
#import "CCGeometry.h"
|
||||||
|
#import "CCDirectorCaller.h"
|
||||||
|
|
||||||
|
NS_CC_BEGIN;
|
||||||
|
|
||||||
|
CCApplication* CCApplication::sm_pSharedApplication = 0;
|
||||||
|
|
||||||
|
CCApplication::CCApplication()
|
||||||
|
{
|
||||||
|
CC_ASSERT(! sm_pSharedApplication);
|
||||||
|
sm_pSharedApplication = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCApplication::~CCApplication()
|
||||||
|
{
|
||||||
|
CC_ASSERT(this == sm_pSharedApplication);
|
||||||
|
sm_pSharedApplication = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CCApplication::run()
|
||||||
|
{
|
||||||
|
if (/*initInstance() &&*/ applicationDidFinishLaunching())
|
||||||
|
{
|
||||||
|
[[CCDirectorCaller sharedDirectorCaller] startMainLoop];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCApplication::setAnimationInterval(double interval)
|
||||||
|
{
|
||||||
|
[[CCDirectorCaller sharedDirectorCaller] setAnimationInterval: interval ];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void CCApplication::statusBarFrame(cocos2d::CCRect * rect)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
rect->origin.x = [[NSApplication sharedApplication] statusBarFrame].origin.x;
|
||||||
|
rect->origin.y = [[NSApplication sharedApplication] statusBarFrame].origin.y;
|
||||||
|
rect->size.width = [[NSApplication sharedApplication] statusBarFrame].size.width;
|
||||||
|
rect->size.height = [[NSApplication sharedApplication] statusBarFrame].size.height;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool CCApplication::isIpad()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static member function
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
CCApplication& CCApplication::sharedApplication()
|
||||||
|
{
|
||||||
|
CC_ASSERT(sm_pSharedApplication);
|
||||||
|
return *sm_pSharedApplication;
|
||||||
|
}
|
||||||
|
|
||||||
|
ccLanguageType CCApplication::getCurrentLanguage()
|
||||||
|
{
|
||||||
|
// get the current language and country config
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSArray *languages = [defaults objectForKey:@"AppleLanguages"];
|
||||||
|
NSString *currentLanguage = [languages objectAtIndex:0];
|
||||||
|
|
||||||
|
// get the current language code.(such as English is "en", Chinese is "zh" and so on)
|
||||||
|
NSDictionary* temp = [NSLocale componentsFromLocaleIdentifier:currentLanguage];
|
||||||
|
NSString * languageCode = [temp objectForKey:NSLocaleLanguageCode];
|
||||||
|
|
||||||
|
ccLanguageType ret = kLanguageEnglish;
|
||||||
|
if ([languageCode isEqualToString:@"zh"])
|
||||||
|
{
|
||||||
|
ret = kLanguageChinese;
|
||||||
|
}
|
||||||
|
else if ([languageCode isEqualToString:@"en"])
|
||||||
|
{
|
||||||
|
ret = kLanguageEnglish;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_CC_END;
|
|
@ -0,0 +1,67 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
#include <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
#include "platform/CCCommon.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#import "EAGLView.h"
|
||||||
|
|
||||||
|
|
||||||
|
NS_CC_BEGIN;
|
||||||
|
|
||||||
|
void CCLog(const char * pszFormat, ...)
|
||||||
|
{
|
||||||
|
printf("Cocos2d: ");
|
||||||
|
char szBuf[kMaxLogLen];
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, pszFormat);
|
||||||
|
vsprintf(szBuf, pszFormat, ap);
|
||||||
|
va_end(ap);
|
||||||
|
printf("%s", szBuf);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ios no MessageBox, use CCLog instead
|
||||||
|
void CCMessageBox(const char * pszMsg, const char * pszTitle)
|
||||||
|
{
|
||||||
|
NSString * title = (pszTitle) ? [NSString stringWithUTF8String : pszTitle] : nil;
|
||||||
|
NSString * msg = (pszMsg) ? [NSString stringWithUTF8String : pszMsg] : nil;
|
||||||
|
|
||||||
|
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
||||||
|
[alert addButtonWithTitle:@"OK"];
|
||||||
|
[alert setMessageText:msg];
|
||||||
|
[alert setInformativeText:title];
|
||||||
|
[alert setAlertStyle:NSWarningAlertStyle];
|
||||||
|
|
||||||
|
NSWindow *window = [[EAGLView sharedEGLView] window];
|
||||||
|
[alert beginSheetModalForWindow:window
|
||||||
|
modalDelegate:[window delegate]
|
||||||
|
didEndSelector:nil
|
||||||
|
contextInfo:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_CC_END;
|
|
@ -0,0 +1,38 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <QuartzCore/CVDisplayLink.h>
|
||||||
|
|
||||||
|
@interface CCDirectorCaller : NSObject {
|
||||||
|
CVDisplayLinkRef displayLink;
|
||||||
|
NSTimer *renderTimer;
|
||||||
|
int interval;
|
||||||
|
}
|
||||||
|
@property (readwrite) int interval;
|
||||||
|
-(void) startMainLoop;
|
||||||
|
-(void) doCaller: (id) sender;
|
||||||
|
-(void) setAnimationInterval:(double)interval;
|
||||||
|
+(id) sharedDirectorCaller;
|
||||||
|
+(void) destroy;
|
||||||
|
@end
|
|
@ -0,0 +1,201 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "CCDirectorCaller.h"
|
||||||
|
#import "CCDirector.h"
|
||||||
|
#import "EAGLView.h"
|
||||||
|
#import "CCEventDispatcher.h"
|
||||||
|
#include "CCAutoreleasePool.h"
|
||||||
|
|
||||||
|
static id s_sharedDirectorCaller;
|
||||||
|
|
||||||
|
@interface NSObject(CADisplayLink)
|
||||||
|
+(id) displayLinkWithTarget: (id)arg1 selector:(SEL)arg2;
|
||||||
|
-(void) addToRunLoop: (id)arg1 forMode: (id)arg2;
|
||||||
|
-(void) setFrameInterval: (int)interval;
|
||||||
|
-(void) invalidate;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CCDirectorCaller
|
||||||
|
|
||||||
|
@synthesize interval;
|
||||||
|
|
||||||
|
+(id) sharedDirectorCaller
|
||||||
|
{
|
||||||
|
if (s_sharedDirectorCaller == nil)
|
||||||
|
{
|
||||||
|
s_sharedDirectorCaller = [CCDirectorCaller new];
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_sharedDirectorCaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
+(void) destroy
|
||||||
|
{
|
||||||
|
[s_sharedDirectorCaller release];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) alloc
|
||||||
|
{
|
||||||
|
interval = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) dealloc
|
||||||
|
{
|
||||||
|
if (displayLink) {
|
||||||
|
CVDisplayLinkRelease(displayLink);
|
||||||
|
}
|
||||||
|
if (renderTimer) {
|
||||||
|
[renderTimer release];
|
||||||
|
}
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime
|
||||||
|
{
|
||||||
|
#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
|
||||||
|
//if( ! runningThread_ )
|
||||||
|
//runningThread_ = [NSThread currentThread];
|
||||||
|
|
||||||
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
cocos2d::CCDirector::sharedDirector()->drawScene();
|
||||||
|
cocos2d::CCPoolManager::sharedPoolManager()->pop();
|
||||||
|
[[CCEventDispatcher sharedDispatcher] dispatchQueuedEvents];
|
||||||
|
|
||||||
|
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:nil];
|
||||||
|
|
||||||
|
// release the objects
|
||||||
|
[pool release];
|
||||||
|
|
||||||
|
#else
|
||||||
|
[self performSelector:@selector(drawScene) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return kCVReturnSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the renderer output callback function
|
||||||
|
static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
|
||||||
|
{
|
||||||
|
// CVReturn result = [(CCDirectorCaller*)displayLinkContext getFrameForTime:outputTime];
|
||||||
|
// return result;
|
||||||
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
cocos2d::CCDirector::sharedDirector()->mainLoop();
|
||||||
|
[pool release];
|
||||||
|
|
||||||
|
return kCVReturnSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)timerFired:(id)sender
|
||||||
|
{
|
||||||
|
// It is good practice in a Cocoa application to allow the system to send the -drawRect:
|
||||||
|
// message when it needs to draw, and not to invoke it directly from the timer.
|
||||||
|
// All we do here is tell the display it needs a refresh
|
||||||
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
// get the opengl view
|
||||||
|
EAGLView *openGLView = [EAGLView sharedEGLView];
|
||||||
|
[openGLView lockOpenGLContext];
|
||||||
|
|
||||||
|
// run the main cocos2d loop
|
||||||
|
cocos2d::CCDirector::sharedDirector()->mainLoop();
|
||||||
|
|
||||||
|
// flush buffer (this line is very important!)
|
||||||
|
[[openGLView openGLContext] flushBuffer];
|
||||||
|
|
||||||
|
[openGLView unlockOpenGLContext];
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) startMainLoop
|
||||||
|
{
|
||||||
|
// CCDirector::setAnimationInterval() is called, we should invalide it first
|
||||||
|
// [displayLink invalidate];
|
||||||
|
// displayLink = nil;
|
||||||
|
//
|
||||||
|
// displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(doCaller:)];
|
||||||
|
// [displayLink setFrameInterval: self.interval];
|
||||||
|
// [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||||
|
#if ! CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
|
||||||
|
NSThread* thread = [[NSThread alloc] initWithTarget:self selector:@selector(mainLoop) object:nil];
|
||||||
|
[thread start];
|
||||||
|
#endif
|
||||||
|
// NSTimer
|
||||||
|
renderTimer = [NSTimer timerWithTimeInterval:self.interval/60.0f //a 1ms time interval
|
||||||
|
target:self
|
||||||
|
selector:@selector(timerFired:)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:YES];
|
||||||
|
|
||||||
|
[[NSRunLoop currentRunLoop] addTimer:renderTimer
|
||||||
|
forMode:NSDefaultRunLoopMode];
|
||||||
|
[[NSRunLoop currentRunLoop] addTimer:renderTimer
|
||||||
|
forMode:NSEventTrackingRunLoopMode]; //Ensure timer fires during resize
|
||||||
|
|
||||||
|
/*
|
||||||
|
// CVDisplayLink
|
||||||
|
//cocos2d::CCDirector::sharedDirector()->gettimeofday();
|
||||||
|
|
||||||
|
// Create a display link capable of being used with all active displays
|
||||||
|
CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
|
||||||
|
|
||||||
|
// Set the renderer output callback function
|
||||||
|
CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, self);
|
||||||
|
|
||||||
|
// Set the display link for the current renderer
|
||||||
|
EAGLView *openGLView_ = (EAGLView*)[EAGLView sharedEGLView];
|
||||||
|
CGLContextObj cglContext = (CGLContextObj)[[openGLView_ openGLContext] CGLContextObj];
|
||||||
|
CGLPixelFormatObj cglPixelFormat = (CGLPixelFormatObj)[[openGLView_ pixelFormat] CGLPixelFormatObj];
|
||||||
|
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
|
||||||
|
|
||||||
|
// Activate the display link
|
||||||
|
CVDisplayLinkStart(displayLink);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) setAnimationInterval:(double)intervalNew
|
||||||
|
{
|
||||||
|
self.interval = 60.0 * intervalNew;
|
||||||
|
[renderTimer invalidate];
|
||||||
|
renderTimer = nil;
|
||||||
|
renderTimer = [NSTimer timerWithTimeInterval:self.interval/60.0f //a 1ms time interval
|
||||||
|
target:self
|
||||||
|
selector:@selector(timerFired:)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:YES];
|
||||||
|
|
||||||
|
[[NSRunLoop currentRunLoop] addTimer:renderTimer
|
||||||
|
forMode:NSDefaultRunLoopMode];
|
||||||
|
[[NSRunLoop currentRunLoop] addTimer:renderTimer
|
||||||
|
forMode:NSEventTrackingRunLoopMode];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) doCaller: (id) sender
|
||||||
|
{
|
||||||
|
cocos2d::CCDirector::sharedDirector()->mainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,61 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __CC_EGLVIEW_MAC_H__
|
||||||
|
#define __CC_EGLVIEW_MAC_H__
|
||||||
|
|
||||||
|
#include "platform/CCCommon.h"
|
||||||
|
#include "platform/CCEGLViewProtocol.h"
|
||||||
|
|
||||||
|
namespace cocos2d {
|
||||||
|
class CCSet;
|
||||||
|
class CCTouch;
|
||||||
|
class CCSize;
|
||||||
|
|
||||||
|
class CC_DLL CCEGLView : public CCEGLViewProtocol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CCEGLView();
|
||||||
|
virtual ~CCEGLView();
|
||||||
|
|
||||||
|
CCSize getSize();
|
||||||
|
bool isOpenGLReady();
|
||||||
|
bool canSetContentScaleFactor();
|
||||||
|
bool isIpad();
|
||||||
|
void setContentScaleFactor(float contentScaleFactor);
|
||||||
|
virtual CCSize getFrameSize();
|
||||||
|
void end();
|
||||||
|
void swapBuffers();
|
||||||
|
|
||||||
|
void setIMEKeyboardState(bool bOpen);
|
||||||
|
|
||||||
|
void setMultiTouchMask(bool mask);
|
||||||
|
|
||||||
|
static CCEGLView& sharedOpenGLView();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace cocos2d
|
||||||
|
|
||||||
|
#endif // end of __CC_EGLVIEW_MAC_H__
|
|
@ -0,0 +1,116 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
#include "CCEGLView.h"
|
||||||
|
#include "EAGLView.h"
|
||||||
|
#include "CCDirectorCaller.h"
|
||||||
|
#include "CCSet.h"
|
||||||
|
#include "CCTouch.h"
|
||||||
|
#include "CCTouchDispatcher.h"
|
||||||
|
|
||||||
|
namespace cocos2d {
|
||||||
|
|
||||||
|
CCEGLView::CCEGLView()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CCEGLView::~CCEGLView()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cocos2d::CCSize CCEGLView::getSize()
|
||||||
|
{
|
||||||
|
cocos2d::CCSize size([[EAGLView sharedEGLView] getWidth], [[EAGLView sharedEGLView] getHeight]);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCEGLView::isIpad()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCEGLView::isOpenGLReady()
|
||||||
|
{
|
||||||
|
return [EAGLView sharedEGLView] != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCEGLView::canSetContentScaleFactor()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
// return [[EAGLView sharedEGLView] respondsToSelector:@selector(setContentScaleFactor:)]
|
||||||
|
// && [[NSScreen mainScreen] scale] != 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCEGLView::setContentScaleFactor(float contentScaleFactor)
|
||||||
|
{
|
||||||
|
// NSView * view = [EAGLView sharedEGLView];
|
||||||
|
// view.contentScaleFactor = contentScaleFactor;
|
||||||
|
// [view setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCEGLView::end()
|
||||||
|
{
|
||||||
|
[CCDirectorCaller destroy];
|
||||||
|
|
||||||
|
// destroy EAGLView
|
||||||
|
[[EAGLView sharedEGLView] removeFromSuperview];
|
||||||
|
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCEGLView::swapBuffers()
|
||||||
|
{
|
||||||
|
[[EAGLView sharedEGLView] swapBuffers];
|
||||||
|
}
|
||||||
|
|
||||||
|
CCSize CCEGLView::getFrameSize()
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return CCSizeMake(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCEGLView::setIMEKeyboardState(bool bOpen)
|
||||||
|
{
|
||||||
|
if (bOpen)
|
||||||
|
{
|
||||||
|
[[EAGLView sharedEGLView] becomeFirstResponder];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[[EAGLView sharedEGLView] resignFirstResponder];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCEGLView::setMultiTouchMask(bool mask)
|
||||||
|
{
|
||||||
|
//EAGLView *glView = [EAGLView sharedEGLView];
|
||||||
|
//glView.multipleTouchEnabled = mask ? YES : NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCEGLView& CCEGLView::sharedOpenGLView()
|
||||||
|
{
|
||||||
|
static CCEGLView instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace cocos2d;
|
|
@ -0,0 +1,278 @@
|
||||||
|
/*
|
||||||
|
* cocos2d for iPhone: http://www.cocos2d-iphone.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010 Ricardo Quesada
|
||||||
|
* Copyright (c) 2011 Zynga Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Only compile this code on Mac. These files should not be included on your iOS project.
|
||||||
|
// But in case they are included, it won't be compiled.
|
||||||
|
#import <Availability.h>
|
||||||
|
#ifndef __CC_EVENT_DISPATCHER_H__
|
||||||
|
#define __CC_EVENT_DISPATCHER_H__
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
#import "EAGLView.h"
|
||||||
|
//#import "../../Support/uthash.h" // hack: uthash needs to be imported before utlist to prevent warning
|
||||||
|
//#import "../../Support/utlist.h"
|
||||||
|
#import "ccConfig.h"
|
||||||
|
|
||||||
|
//NS_CC_BEGIN;
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CCMouseEventDelegate
|
||||||
|
|
||||||
|
/** CCMouseEventDelegate protocol.
|
||||||
|
Implement it in your node to receive any of mouse events
|
||||||
|
*/
|
||||||
|
@protocol CCMouseEventDelegate <NSObject>
|
||||||
|
@optional
|
||||||
|
|
||||||
|
//
|
||||||
|
// left
|
||||||
|
//
|
||||||
|
/** called when the "mouseDown" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccMouseDown:(NSEvent*)event;
|
||||||
|
|
||||||
|
/** called when the "mouseDragged" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccMouseDragged:(NSEvent*)event;
|
||||||
|
|
||||||
|
/** called when the "mouseMoved" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
By default, "mouseMoved" is disabled. To enable it, send the "setAcceptsMouseMovedEvents:YES" message to the main window.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccMouseMoved:(NSEvent*)event;
|
||||||
|
|
||||||
|
/** called when the "mouseUp" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccMouseUp:(NSEvent*)event;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// right
|
||||||
|
//
|
||||||
|
|
||||||
|
/** called when the "rightMouseDown" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccRightMouseDown:(NSEvent*)event;
|
||||||
|
|
||||||
|
/** called when the "rightMouseDragged" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccRightMouseDragged:(NSEvent*)event;
|
||||||
|
|
||||||
|
/** called when the "rightMouseUp" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccRightMouseUp:(NSEvent*)event;
|
||||||
|
|
||||||
|
//
|
||||||
|
// other
|
||||||
|
//
|
||||||
|
|
||||||
|
/** called when the "otherMouseDown" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccOtherMouseDown:(NSEvent*)event;
|
||||||
|
|
||||||
|
/** called when the "otherMouseDragged" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccOtherMouseDragged:(NSEvent*)event;
|
||||||
|
|
||||||
|
/** called when the "otherMouseUp" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccOtherMouseUp:(NSEvent*)event;
|
||||||
|
|
||||||
|
//
|
||||||
|
// scroll wheel
|
||||||
|
//
|
||||||
|
|
||||||
|
/** called when the "scrollWheel" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
- (BOOL)ccScrollWheel:(NSEvent *)theEvent;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// enter / exit
|
||||||
|
//
|
||||||
|
|
||||||
|
/** called when the "mouseEntered" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
- (void)ccMouseEntered:(NSEvent *)theEvent;
|
||||||
|
|
||||||
|
/** called when the "mouseExited" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
- (void)ccMouseExited:(NSEvent *)theEvent;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CCKeyboardEventDelegate
|
||||||
|
|
||||||
|
/** CCKeyboardEventDelegate protocol.
|
||||||
|
Implement it in your node to receive any of keyboard events
|
||||||
|
*/
|
||||||
|
@protocol CCKeyboardEventDelegate <NSObject>
|
||||||
|
@optional
|
||||||
|
/** called when the "keyUp" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccKeyUp:(NSEvent*)event;
|
||||||
|
|
||||||
|
/** called when the "keyDown" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccKeyDown:(NSEvent*)event;
|
||||||
|
/** called when the "flagsChanged" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
-(BOOL) ccFlagsChanged:(NSEvent*)event;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CCTouchEventDelegate
|
||||||
|
|
||||||
|
/** CCTouchEventDelegate protocol.
|
||||||
|
Implement it in your node to receive any of touch events
|
||||||
|
*/
|
||||||
|
@protocol CCTouchEventDelegate <NSObject>
|
||||||
|
@optional
|
||||||
|
/** called when the "touchesBegan" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
- (BOOL)ccTouchesBeganWithEvent:(NSEvent *)event;
|
||||||
|
|
||||||
|
/** called when the "touchesMoved" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
- (BOOL)ccTouchesMovedWithEvent:(NSEvent *)event;
|
||||||
|
|
||||||
|
/** called when the "touchesEnded" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
- (BOOL)ccTouchesEndedWithEvent:(NSEvent *)event;
|
||||||
|
|
||||||
|
/** called when the "touchesCancelled" event is received.
|
||||||
|
Return YES to avoid propagating the event to other delegates.
|
||||||
|
*/
|
||||||
|
- (BOOL)ccTouchesCancelledWithEvent:(NSEvent *)event;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark CCEventDispatcher
|
||||||
|
|
||||||
|
struct _listEntry;
|
||||||
|
|
||||||
|
/** CCEventDispatcher
|
||||||
|
|
||||||
|
This is object is responsible for dispatching the events:
|
||||||
|
- Mouse events
|
||||||
|
- Keyboard events
|
||||||
|
- Touch events
|
||||||
|
|
||||||
|
Only available on Mac
|
||||||
|
*/
|
||||||
|
@interface CCEventDispatcher : NSObject <MacEventDelegate> {
|
||||||
|
|
||||||
|
BOOL dispatchEvents_;
|
||||||
|
|
||||||
|
struct _listEntry *keyboardDelegates_;
|
||||||
|
struct _listEntry *mouseDelegates_;
|
||||||
|
struct _listEntry *touchDelegates_;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (nonatomic, readwrite) BOOL dispatchEvents;
|
||||||
|
|
||||||
|
|
||||||
|
/** CCEventDispatcher singleton */
|
||||||
|
+(CCEventDispatcher*) sharedDispatcher;
|
||||||
|
|
||||||
|
#pragma mark CCEventDispatcher - Mouse
|
||||||
|
|
||||||
|
/** Adds a mouse delegate to the dispatcher's list.
|
||||||
|
Delegates with a lower priority value will be called before higher priority values.
|
||||||
|
All the events will be propgated to all the delegates, unless the one delegate returns YES.
|
||||||
|
|
||||||
|
IMPORTANT: The delegate will be retained.
|
||||||
|
*/
|
||||||
|
-(void) addMouseDelegate:(id<CCMouseEventDelegate>) delegate priority:(NSInteger)priority;
|
||||||
|
|
||||||
|
/** removes a mouse delegate */
|
||||||
|
-(void) removeMouseDelegate:(id) delegate;
|
||||||
|
|
||||||
|
/** Removes all mouse delegates, releasing all the delegates */
|
||||||
|
-(void) removeAllMouseDelegates;
|
||||||
|
|
||||||
|
#pragma mark CCEventDispatcher - Keyboard
|
||||||
|
|
||||||
|
/** Adds a Keyboard delegate to the dispatcher's list.
|
||||||
|
Delegates with a lower priority value will be called before higher priority values.
|
||||||
|
All the events will be propgated to all the delegates, unless the one delegate returns YES.
|
||||||
|
|
||||||
|
IMPORTANT: The delegate will be retained.
|
||||||
|
*/
|
||||||
|
-(void) addKeyboardDelegate:(id<CCKeyboardEventDelegate>) delegate priority:(NSInteger)priority;
|
||||||
|
|
||||||
|
/** removes a mouse delegate */
|
||||||
|
-(void) removeKeyboardDelegate:(id) delegate;
|
||||||
|
|
||||||
|
/** Removes all mouse delegates, releasing all the delegates */
|
||||||
|
-(void) removeAllKeyboardDelegates;
|
||||||
|
|
||||||
|
#pragma mark CCEventDispatcher - Touches
|
||||||
|
|
||||||
|
/** Adds a Touch delegate to the dispatcher's list.
|
||||||
|
Delegates with a lower priority value will be called before higher priority values.
|
||||||
|
All the events will be propgated to all the delegates, unless the one delegate returns YES.
|
||||||
|
|
||||||
|
IMPORTANT: The delegate will be retained.
|
||||||
|
*/
|
||||||
|
- (void)addTouchDelegate:(id<CCTouchEventDelegate>)delegate priority:(NSInteger)priority;
|
||||||
|
|
||||||
|
/** Removes a touch delegate */
|
||||||
|
- (void)removeTouchDelegate:(id) delegate;
|
||||||
|
|
||||||
|
/** Removes all touch delegates, releasing all the delegates */
|
||||||
|
- (void)removeAllTouchDelegates;
|
||||||
|
|
||||||
|
#pragma mark CCEventDispatcher - Dispatch Events
|
||||||
|
|
||||||
|
#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
|
||||||
|
-(void) dispatchQueuedEvents;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
//NS_CC_END;
|
||||||
|
#endif // __CC_EVENT_DISPATCHER_H__
|
|
@ -0,0 +1,643 @@
|
||||||
|
/*
|
||||||
|
* cocos2d for iPhone: http://www.cocos2d-iphone.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010 Ricardo Quesada
|
||||||
|
* Copyright (c) 2011 Zynga Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Only compile this code on Mac. These files should not be included on your iOS project.
|
||||||
|
// But in case they are included, it won't be compiled.
|
||||||
|
#import <Availability.h>
|
||||||
|
|
||||||
|
#import "CCEventDispatcher.h"
|
||||||
|
#import "ccConfig.h"
|
||||||
|
#include "support/data_support/utlist.h"
|
||||||
|
|
||||||
|
//NS_CC_BEGIN;
|
||||||
|
static CCEventDispatcher *sharedDispatcher = nil;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
// mouse
|
||||||
|
kCCImplementsMouseDown = 1 << 0,
|
||||||
|
kCCImplementsMouseMoved = 1 << 1,
|
||||||
|
kCCImplementsMouseDragged = 1 << 2,
|
||||||
|
kCCImplementsMouseUp = 1 << 3,
|
||||||
|
kCCImplementsRightMouseDown = 1 << 4,
|
||||||
|
kCCImplementsRightMouseDragged = 1 << 5,
|
||||||
|
kCCImplementsRightMouseUp = 1 << 6,
|
||||||
|
kCCImplementsOtherMouseDown = 1 << 7,
|
||||||
|
kCCImplementsOtherMouseDragged = 1 << 8,
|
||||||
|
kCCImplementsOtherMouseUp = 1 << 9,
|
||||||
|
kCCImplementsScrollWheel = 1 << 10,
|
||||||
|
kCCImplementsMouseEntered = 1 << 11,
|
||||||
|
kCCImplementsMouseExited = 1 << 12,
|
||||||
|
|
||||||
|
kCCImplementsTouchesBegan = 1 << 13,
|
||||||
|
kCCImplementsTouchesMoved = 1 << 14,
|
||||||
|
kCCImplementsTouchesEnded = 1 << 15,
|
||||||
|
kCCImplementsTouchesCancelled = 1 << 16,
|
||||||
|
|
||||||
|
// keyboard
|
||||||
|
kCCImplementsKeyUp = 1 << 0,
|
||||||
|
kCCImplementsKeyDown = 1 << 1,
|
||||||
|
kCCImplementsFlagsChanged = 1 << 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _listEntry
|
||||||
|
{
|
||||||
|
struct _listEntry *prev, *next;
|
||||||
|
id delegate;
|
||||||
|
NSInteger priority;
|
||||||
|
NSUInteger flags;
|
||||||
|
} tListEntry;
|
||||||
|
|
||||||
|
|
||||||
|
#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
|
||||||
|
|
||||||
|
#define QUEUE_EVENT_MAX 128
|
||||||
|
struct _eventQueue {
|
||||||
|
SEL selector;
|
||||||
|
NSEvent *event;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct _eventQueue eventQueue[QUEUE_EVENT_MAX];
|
||||||
|
static int eventQueueCount;
|
||||||
|
|
||||||
|
#endif // CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CCEventDispatcher
|
||||||
|
|
||||||
|
@synthesize dispatchEvents=dispatchEvents_;
|
||||||
|
|
||||||
|
|
||||||
|
+(CCEventDispatcher*) sharedDispatcher
|
||||||
|
{
|
||||||
|
@synchronized(self) {
|
||||||
|
if (sharedDispatcher == nil)
|
||||||
|
sharedDispatcher = [[self alloc] init]; // assignment not done here
|
||||||
|
}
|
||||||
|
return sharedDispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
+(id) allocWithZone:(NSZone *)zone
|
||||||
|
{
|
||||||
|
@synchronized(self) {
|
||||||
|
NSAssert(sharedDispatcher == nil, @"Attempted to allocate a second instance of a singleton.");
|
||||||
|
return [super allocWithZone:zone];
|
||||||
|
}
|
||||||
|
return nil; // on subsequent allocation attempts return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
-(id) init
|
||||||
|
{
|
||||||
|
if( (self = [super init]) )
|
||||||
|
{
|
||||||
|
// events enabled by default
|
||||||
|
dispatchEvents_ = YES;
|
||||||
|
|
||||||
|
// delegates
|
||||||
|
keyboardDelegates_ = NULL;
|
||||||
|
mouseDelegates_ = NULL;
|
||||||
|
touchDelegates_ = NULL;
|
||||||
|
|
||||||
|
#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
|
||||||
|
eventQueueCount = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark CCEventDispatcher - add / remove delegates
|
||||||
|
|
||||||
|
-(void) addDelegate:(id)delegate priority:(NSInteger)priority flags:(NSUInteger)flags list:(tListEntry**)list
|
||||||
|
{
|
||||||
|
tListEntry *listElement = (tListEntry *)malloc( sizeof(*listElement) );
|
||||||
|
|
||||||
|
listElement->delegate = [delegate retain];
|
||||||
|
listElement->priority = priority;
|
||||||
|
listElement->flags = flags;
|
||||||
|
listElement->next = listElement->prev = NULL;
|
||||||
|
|
||||||
|
// empty list ?
|
||||||
|
if( ! *list ) {
|
||||||
|
DL_APPEND( *list, listElement );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
BOOL added = NO;
|
||||||
|
|
||||||
|
for( tListEntry *elem = *list; elem ; elem = elem->next ) {
|
||||||
|
if( priority < elem->priority ) {
|
||||||
|
|
||||||
|
if( elem == *list )
|
||||||
|
DL_PREPEND(*list, listElement);
|
||||||
|
else {
|
||||||
|
listElement->next = elem;
|
||||||
|
listElement->prev = elem->prev;
|
||||||
|
|
||||||
|
elem->prev->next = listElement;
|
||||||
|
elem->prev = listElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
added = YES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not added? priority has the higher value. Append it.
|
||||||
|
if( !added )
|
||||||
|
DL_APPEND(*list, listElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) removeDelegate:(id)delegate fromList:(tListEntry**)list
|
||||||
|
{
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
// updates with priority < 0
|
||||||
|
DL_FOREACH_SAFE( *list, entry, tmp ) {
|
||||||
|
if( entry->delegate == delegate ) {
|
||||||
|
DL_DELETE( *list, entry );
|
||||||
|
[delegate release];
|
||||||
|
free(entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) removeAllDelegatesFromList:(tListEntry**)list
|
||||||
|
{
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( *list, entry, tmp ) {
|
||||||
|
DL_DELETE( *list, entry );
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-(void) addMouseDelegate:(id<CCMouseEventDelegate>) delegate priority:(NSInteger)priority
|
||||||
|
{
|
||||||
|
NSUInteger flags = 0;
|
||||||
|
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccMouseDown:)] ? kCCImplementsMouseDown : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccMouseDragged:)] ? kCCImplementsMouseDragged : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccMouseMoved:)] ? kCCImplementsMouseMoved : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccMouseUp:)] ? kCCImplementsMouseUp : 0 );
|
||||||
|
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccRightMouseDown:)] ? kCCImplementsRightMouseDown : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccRightMouseDragged:)] ? kCCImplementsRightMouseDragged : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccRightMouseUp:)] ? kCCImplementsRightMouseUp : 0 );
|
||||||
|
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccOtherMouseDown:)] ? kCCImplementsOtherMouseDown : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccOtherMouseDragged:)] ? kCCImplementsOtherMouseDragged : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccOtherMouseUp:)] ? kCCImplementsOtherMouseUp : 0 );
|
||||||
|
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccMouseEntered:)] ? kCCImplementsMouseEntered : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccMouseExited:)] ? kCCImplementsMouseExited : 0 );
|
||||||
|
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccScrollWheel:)] ? kCCImplementsScrollWheel : 0 );
|
||||||
|
|
||||||
|
[self addDelegate:delegate priority:priority flags:flags list:&mouseDelegates_];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) removeMouseDelegate:(id) delegate
|
||||||
|
{
|
||||||
|
[self removeDelegate:delegate fromList:&mouseDelegates_];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) removeAllMouseDelegates
|
||||||
|
{
|
||||||
|
[self removeAllDelegatesFromList:&mouseDelegates_];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) addKeyboardDelegate:(id<CCKeyboardEventDelegate>) delegate priority:(NSInteger)priority
|
||||||
|
{
|
||||||
|
NSUInteger flags = 0;
|
||||||
|
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccKeyUp:)] ? kCCImplementsKeyUp : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccKeyDown:)] ? kCCImplementsKeyDown : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccFlagsChanged:)] ? kCCImplementsFlagsChanged : 0 );
|
||||||
|
|
||||||
|
[self addDelegate:delegate priority:priority flags:flags list:&keyboardDelegates_];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) removeKeyboardDelegate:(id) delegate
|
||||||
|
{
|
||||||
|
[self removeDelegate:delegate fromList:&keyboardDelegates_];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) removeAllKeyboardDelegates
|
||||||
|
{
|
||||||
|
[self removeAllDelegatesFromList:&keyboardDelegates_];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) addTouchDelegate:(id<CCTouchEventDelegate>) delegate priority:(NSInteger)priority
|
||||||
|
{
|
||||||
|
NSUInteger flags = 0;
|
||||||
|
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccTouchesBeganWithEvent:)] ? kCCImplementsTouchesBegan : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccTouchesMovedWithEvent:)] ? kCCImplementsTouchesMoved : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccTouchesEndedWithEvent:)] ? kCCImplementsTouchesEnded : 0 );
|
||||||
|
flags |= ( [delegate respondsToSelector:@selector(ccTouchesCancelledWithEvent:)] ? kCCImplementsTouchesCancelled : 0 );
|
||||||
|
|
||||||
|
[self addDelegate:delegate priority:priority flags:flags list:&touchDelegates_];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) removeTouchDelegate:(id) delegate
|
||||||
|
{
|
||||||
|
[self removeDelegate:delegate fromList:&touchDelegates_];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) removeAllTouchDelegates
|
||||||
|
{
|
||||||
|
[self removeAllDelegatesFromList:&touchDelegates_];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark CCEventDispatcher - Mouse events
|
||||||
|
//
|
||||||
|
// Mouse events
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Left
|
||||||
|
//
|
||||||
|
- (void)mouseDown:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsMouseDown ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccMouseDown:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseMoved:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsMouseMoved ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccMouseMoved:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDragged:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsMouseDragged ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccMouseDragged:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseUp:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsMouseUp ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccMouseUp:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Mouse Right
|
||||||
|
//
|
||||||
|
- (void)rightMouseDown:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsRightMouseDown ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccRightMouseDown:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)rightMouseDragged:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsRightMouseDragged ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccRightMouseDragged:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)rightMouseUp:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsRightMouseUp ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccRightMouseUp:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Mouse Other
|
||||||
|
//
|
||||||
|
- (void)otherMouseDown:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsOtherMouseDown ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccOtherMouseDown:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)otherMouseDragged:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsOtherMouseDragged ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccOtherMouseDragged:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)otherMouseUp:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsOtherMouseUp ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccOtherMouseUp:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Scroll Wheel
|
||||||
|
//
|
||||||
|
- (void)scrollWheel:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsScrollWheel ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccScrollWheel:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Mouse enter / exit
|
||||||
|
- (void)mouseExited:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsMouseEntered ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccMouseEntered:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseEntered:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsMouseExited) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccMouseExited:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark CCEventDispatcher - Keyboard events
|
||||||
|
|
||||||
|
// Keyboard events
|
||||||
|
- (void)keyDown:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( keyboardDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsKeyDown ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccKeyDown:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyUp:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( keyboardDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsKeyUp ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccKeyUp:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)flagsChanged:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( keyboardDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsFlagsChanged ) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccFlagsChanged:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark CCEventDispatcher - Touch events
|
||||||
|
|
||||||
|
- (void)touchesBeganWithEvent:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsTouchesBegan) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccTouchesBeganWithEvent:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesMovedWithEvent:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsTouchesMoved) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccTouchesMovedWithEvent:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesEndedWithEvent:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsTouchesEnded) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccTouchesEndedWithEvent:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesCancelledWithEvent:(NSEvent *)event
|
||||||
|
{
|
||||||
|
if( dispatchEvents_ ) {
|
||||||
|
tListEntry *entry, *tmp;
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) {
|
||||||
|
if ( entry->flags & kCCImplementsTouchesCancelled) {
|
||||||
|
void *swallows = [entry->delegate performSelector:@selector(ccTouchesCancelledWithEvent:) withObject:event];
|
||||||
|
if( swallows )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark CCEventDispatcher - queue events
|
||||||
|
|
||||||
|
#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
|
||||||
|
-(void) queueEvent:(NSEvent*)event selector:(SEL)selector
|
||||||
|
{
|
||||||
|
NSAssert( eventQueueCount < QUEUE_EVENT_MAX, @"CCEventDispatcher: recompile. Increment QUEUE_EVENT_MAX value");
|
||||||
|
|
||||||
|
@synchronized (self) {
|
||||||
|
eventQueue[eventQueueCount].selector = selector;
|
||||||
|
eventQueue[eventQueueCount].event = [event copy];
|
||||||
|
|
||||||
|
eventQueueCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) dispatchQueuedEvents
|
||||||
|
{
|
||||||
|
@synchronized (self) {
|
||||||
|
for( int i=0; i < eventQueueCount; i++ ) {
|
||||||
|
SEL sel = eventQueue[i].selector;
|
||||||
|
NSEvent *event = eventQueue[i].event;
|
||||||
|
|
||||||
|
[self performSelector:sel withObject:event];
|
||||||
|
|
||||||
|
[event release];
|
||||||
|
}
|
||||||
|
|
||||||
|
eventQueueCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
|
||||||
|
|
||||||
|
//NS_CC_END;
|
||||||
|
@end
|
|
@ -0,0 +1,476 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <stack>
|
||||||
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/tree.h>
|
||||||
|
#include <libxml/xmlmemory.h>
|
||||||
|
#include "CCString.h"
|
||||||
|
#include "CCFileUtils.h"
|
||||||
|
#include "CCDirector.h"
|
||||||
|
#include "CCSAXParser.h"
|
||||||
|
#include "CCImage.h"
|
||||||
|
#include "CCDictionary.h"
|
||||||
|
#include "CCArray.h"
|
||||||
|
|
||||||
|
#define MAX_PATH 260
|
||||||
|
|
||||||
|
using namespace cocos2d;
|
||||||
|
|
||||||
|
static void static_addValueToCCDict(id key, id value, CCDictionary* pDict);
|
||||||
|
static void static_addItemToCCArray(id item, CCArray *pArray);
|
||||||
|
|
||||||
|
static const char *static_ccRemoveHDSuffixFromFile( const char *pszPath)
|
||||||
|
{
|
||||||
|
#if CC_IS_RETINA_DISPLAY_SUPPORTED
|
||||||
|
|
||||||
|
if(cocos2d::CC_CONTENT_SCALE_FACTOR() == 2 ) {
|
||||||
|
NSString *path = [NSString stringWithUTF8String: pszPath];
|
||||||
|
NSString *name = [path lastPathComponent];
|
||||||
|
NSString *suffix = [NSString stringWithUTF8String: CC_RETINA_DISPLAY_FILENAME_SUFFIX];
|
||||||
|
|
||||||
|
// check if path already has the suffix.
|
||||||
|
if( [name rangeOfString: suffix].location != NSNotFound ) {
|
||||||
|
|
||||||
|
CCLOG("cocos2d: Filename(%@) contains %@ suffix. Removing it. See cocos2d issue #1040", path, CC_RETINA_DISPLAY_FILENAME_SUFFIX);
|
||||||
|
|
||||||
|
NSString *newLastname = [name stringByReplacingOccurrencesOfString: suffix withString:@""];
|
||||||
|
|
||||||
|
NSString *pathWithoutLastname = [path stringByDeletingLastPathComponent];
|
||||||
|
return [[pathWithoutLastname stringByAppendingPathComponent:newLastname] UTF8String];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CC_IS_RETINA_DISPLAY_SUPPORTED
|
||||||
|
|
||||||
|
return pszPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSString* getDoubleResolutionImage(NSString* path)
|
||||||
|
{
|
||||||
|
#if CC_IS_RETINA_DISPLAY_SUPPORTED
|
||||||
|
|
||||||
|
if( cocos2d::CC_CONTENT_SCALE_FACTOR() == 2 )
|
||||||
|
{
|
||||||
|
|
||||||
|
NSString *pathWithoutExtension = [path stringByDeletingPathExtension];
|
||||||
|
NSString *name = [pathWithoutExtension lastPathComponent];
|
||||||
|
NSString *suffix = [NSString stringWithUTF8String: CC_RETINA_DISPLAY_FILENAME_SUFFIX];
|
||||||
|
|
||||||
|
// check if path already has the suffix.
|
||||||
|
if( [name rangeOfString: suffix].location != NSNotFound ) {
|
||||||
|
|
||||||
|
CCLOG("cocos2d: WARNING Filename(%@) already has the suffix %@. Using it.", name, CC_RETINA_DISPLAY_FILENAME_SUFFIX);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NSString *extension = [path pathExtension];
|
||||||
|
|
||||||
|
if( [extension isEqualToString:@"ccz"] || [extension isEqualToString:@"gz"] )
|
||||||
|
{
|
||||||
|
// All ccz / gz files should be in the format filename.xxx.ccz
|
||||||
|
// so we need to pull off the .xxx part of the extension as well
|
||||||
|
extension = [NSString stringWithFormat:@"%@.%@", [pathWithoutExtension pathExtension], extension];
|
||||||
|
pathWithoutExtension = [pathWithoutExtension stringByDeletingPathExtension];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NSString *retinaName = [pathWithoutExtension stringByAppendingString: suffix];
|
||||||
|
retinaName = [retinaName stringByAppendingPathExtension:extension];
|
||||||
|
|
||||||
|
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||||
|
if( [fileManager fileExistsAtPath:retinaName] )
|
||||||
|
return retinaName;
|
||||||
|
|
||||||
|
CCLOG("cocos2d: CCFileUtils: Warning HD file not found: %@", [retinaName lastPathComponent] );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CC_IS_RETINA_DISPLAY_SUPPORTED
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* static_fullPathFromRelativePath(const char *pszRelativePath)
|
||||||
|
{
|
||||||
|
|
||||||
|
// NSAssert(pszRelativePath != nil, @"CCFileUtils: Invalid path");
|
||||||
|
|
||||||
|
// do not convert an absolute path (starting with '/')
|
||||||
|
NSString *relPath = [NSString stringWithUTF8String: pszRelativePath];
|
||||||
|
NSString *fullpath = nil;
|
||||||
|
|
||||||
|
// only if it is not an absolute path
|
||||||
|
if( ! [relPath isAbsolutePath] )
|
||||||
|
{
|
||||||
|
NSString *file = [relPath lastPathComponent];
|
||||||
|
NSString *imageDirectory = [relPath stringByDeletingLastPathComponent];
|
||||||
|
|
||||||
|
fullpath = [[NSBundle mainBundle] pathForResource:file
|
||||||
|
ofType:nil
|
||||||
|
inDirectory:imageDirectory];
|
||||||
|
|
||||||
|
if (CC_CONTENT_SCALE_FACTOR() > 1.0f &&
|
||||||
|
fullpath == nil && [file rangeOfString:@"@2x" options:NSBackwardsSearch].length == 0
|
||||||
|
&& ([file rangeOfString:@".png" options:NSBackwardsSearch | NSCaseInsensitiveSearch].length != 0
|
||||||
|
|| [file rangeOfString:@".jpg" options:NSBackwardsSearch | NSCaseInsensitiveSearch].length != 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NSMutableString *newFile = [NSMutableString stringWithString:file];
|
||||||
|
NSRange range = [newFile rangeOfString:@"." options:NSBackwardsSearch];
|
||||||
|
if (range.length > 0 )
|
||||||
|
{
|
||||||
|
[newFile insertString:@"@2x" atIndex:range.location];
|
||||||
|
fullpath = [[NSBundle mainBundle] pathForResource:newFile
|
||||||
|
ofType:nil
|
||||||
|
inDirectory:imageDirectory];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullpath)
|
||||||
|
{
|
||||||
|
imageDirectory = [fullpath stringByDeletingLastPathComponent];
|
||||||
|
fullpath = [imageDirectory stringByAppendingPathComponent:file];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CCLog("miss file %s", [[imageDirectory stringByAppendingPathComponent:newFile] UTF8String]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullpath == nil)
|
||||||
|
fullpath = relPath;
|
||||||
|
|
||||||
|
fullpath = getDoubleResolutionImage(fullpath);
|
||||||
|
|
||||||
|
return [fullpath UTF8String];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_addItemToCCArray(id item, CCArray *pArray)
|
||||||
|
{
|
||||||
|
// add string value into array
|
||||||
|
if ([item isKindOfClass:[NSString class]]) {
|
||||||
|
CCString* pValue = new CCString([item UTF8String]);
|
||||||
|
|
||||||
|
pArray->addObject(pValue);
|
||||||
|
pValue->release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add number value into array(such as int, float, bool and so on)
|
||||||
|
if ([item isKindOfClass:[NSNumber class]]) {
|
||||||
|
NSString* pStr = [item stringValue];
|
||||||
|
CCString* pValue = new CCString([pStr UTF8String]);
|
||||||
|
|
||||||
|
pArray->addObject(pValue);
|
||||||
|
pValue->release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add dictionary value into array
|
||||||
|
if ([item isKindOfClass:[NSDictionary class]]) {
|
||||||
|
CCDictionary* pDictItem = new CCDictionary();
|
||||||
|
for (id subKey in [item allKeys]) {
|
||||||
|
id subValue = [item objectForKey:subKey];
|
||||||
|
static_addValueToCCDict(subKey, subValue, pDictItem);
|
||||||
|
}
|
||||||
|
pArray->addObject(pDictItem);
|
||||||
|
pDictItem->release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add array value into array
|
||||||
|
if ([item isKindOfClass:[NSArray class]]) {
|
||||||
|
CCArray *pArrayItem = new CCArray();
|
||||||
|
for (id subItem in item) {
|
||||||
|
static_addItemToCCArray(subItem, pArrayItem);
|
||||||
|
}
|
||||||
|
pArray->addObject(pArrayItem);
|
||||||
|
pArrayItem->release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_addValueToCCDict(id key, id value, CCDictionary* pDict)
|
||||||
|
{
|
||||||
|
// the key must be a string
|
||||||
|
CCAssert([key isKindOfClass:[NSString class]], "The key should be a string!");
|
||||||
|
std::string pKey = [key UTF8String];
|
||||||
|
|
||||||
|
// the value is a new dictionary
|
||||||
|
if ([value isKindOfClass:[NSDictionary class]]) {
|
||||||
|
CCDictionary* pSubDict = new CCDictionary();
|
||||||
|
for (id subKey in [value allKeys]) {
|
||||||
|
id subValue = [value objectForKey:subKey];
|
||||||
|
static_addValueToCCDict(subKey, subValue, pSubDict);
|
||||||
|
}
|
||||||
|
pDict->setObject(pSubDict, pKey);
|
||||||
|
pSubDict->release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the value is a string
|
||||||
|
if ([value isKindOfClass:[NSString class]]) {
|
||||||
|
CCString* pValue = new CCString([value UTF8String]);
|
||||||
|
|
||||||
|
pDict->setObject(pValue, pKey);
|
||||||
|
pValue->release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the value is a number
|
||||||
|
if ([value isKindOfClass:[NSNumber class]]) {
|
||||||
|
NSString* pStr = [value stringValue];
|
||||||
|
CCString* pValue = new CCString([pStr UTF8String]);
|
||||||
|
|
||||||
|
pDict->setObject(pValue, pKey);
|
||||||
|
pValue->release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the value is a array
|
||||||
|
if ([value isKindOfClass:[NSArray class]]) {
|
||||||
|
CCArray *pArray = new CCArray();
|
||||||
|
for (id item in value) {
|
||||||
|
static_addItemToCCArray(item, pArray);
|
||||||
|
}
|
||||||
|
pDict->setObject(pArray, pKey);
|
||||||
|
pArray->release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cocos2d {
|
||||||
|
|
||||||
|
static CCFileUtils* s_pFileUtils = NULL;
|
||||||
|
|
||||||
|
CCDictionary* ccFileUtils_dictionaryWithContentsOfFileThreadSafe(const char *pFileName);
|
||||||
|
CCArray* ccFileUtils_arrayWithContentsOfFileThreadSafe(const char* pFileName);
|
||||||
|
|
||||||
|
CCFileUtils* CCFileUtils::sharedFileUtils()
|
||||||
|
{
|
||||||
|
if (s_pFileUtils == NULL)
|
||||||
|
{
|
||||||
|
s_pFileUtils = new CCFileUtils();
|
||||||
|
}
|
||||||
|
return s_pFileUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCFileUtils::purgeFileUtils()
|
||||||
|
{
|
||||||
|
if (s_pFileUtils != NULL)
|
||||||
|
{
|
||||||
|
s_pFileUtils->purgeCachedEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
CC_SAFE_DELETE(s_pFileUtils);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCFileUtils::purgeCachedEntries()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// record the resource path
|
||||||
|
static char s_pszResourcePath[MAX_PATH] = {0};
|
||||||
|
|
||||||
|
void CCFileUtils::setResourcePath(const char *pszResourcePath)
|
||||||
|
{
|
||||||
|
// NSAssert(pszResourcePath != NULL, "[FileUtils setResourcePath] -- wrong resource path");
|
||||||
|
// NSAssert(strlen(pszResourcePath) <= MAX_PATH, "[FileUtils setResourcePath] -- resource path too long");
|
||||||
|
|
||||||
|
strcpy(s_pszResourcePath, pszResourcePath);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
const char* CCFileUtils::getResourcePath()
|
||||||
|
{
|
||||||
|
return s_pszResourcePath;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
//int CCFileUtils::ccLoadFileIntoMemory(const char *filename, unsigned char **out)
|
||||||
|
unsigned char* CCFileUtils::getFileData(const char *pszFileName, const char *pszMode, unsigned long *pSize)
|
||||||
|
{
|
||||||
|
unsigned char* out = NULL;
|
||||||
|
|
||||||
|
int size = 0;
|
||||||
|
FILE *f = fopen(pszFileName, pszMode);
|
||||||
|
if( !f ) {
|
||||||
|
*pSize = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
size = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
out = (unsigned char*)malloc(size);
|
||||||
|
int read = fread(out, 1, size, f);
|
||||||
|
if( read != size ) {
|
||||||
|
free(out);
|
||||||
|
*pSize = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
*pSize = size;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& CCFileUtils::removeSuffixFromFile(std::string& path )
|
||||||
|
{
|
||||||
|
path = static_ccRemoveHDSuffixFromFile(path.c_str());
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* CCFileUtils::fullPathFromRelativePath(const char *pszRelativePath)
|
||||||
|
{
|
||||||
|
return static_fullPathFromRelativePath(pszRelativePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *CCFileUtils::fullPathFromRelativeFile(const char *pszFilename, const char *pszRelativeFile)
|
||||||
|
{
|
||||||
|
std::string relativeFile = fullPathFromRelativePath(pszRelativeFile);
|
||||||
|
CCString *pRet = new CCString();
|
||||||
|
pRet->autorelease();
|
||||||
|
pRet->m_sString = relativeFile.substr(0, relativeFile.rfind('/')+1);
|
||||||
|
pRet->m_sString += pszFilename;
|
||||||
|
return pRet->m_sString.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCDictionary* ccFileUtils_dictionaryWithContentsOfFileThreadSafe(const char *pFileName)
|
||||||
|
{
|
||||||
|
const char* pszFullPath = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(pFileName);
|
||||||
|
NSString* pPath = [NSString stringWithUTF8String:pszFullPath];
|
||||||
|
NSDictionary* pDict = [NSDictionary dictionaryWithContentsOfFile:pPath];
|
||||||
|
|
||||||
|
CCDictionary* pRet = new CCDictionary();
|
||||||
|
for (id key in [pDict allKeys]) {
|
||||||
|
id value = [pDict objectForKey:key];
|
||||||
|
static_addValueToCCDict(key, value, pRet);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCArray* ccFileUtils_arrayWithContentsOfFileThreadSafe(const char* pFileName)
|
||||||
|
{
|
||||||
|
NSString* pPath = [NSString stringWithUTF8String:pFileName];
|
||||||
|
NSString* pathExtension= [pPath pathExtension];
|
||||||
|
pPath = [pPath stringByDeletingPathExtension];
|
||||||
|
pPath = [[NSBundle mainBundle] pathForResource:pPath ofType:pathExtension];
|
||||||
|
NSArray* pArray = [NSArray arrayWithContentsOfFile:pPath];
|
||||||
|
|
||||||
|
CCArray* pRet = new CCArray();
|
||||||
|
for (id value in pArray) {
|
||||||
|
static_addItemToCCArray(value, pRet);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
CCDictionary *CCFileUtils::dictionaryWithContentsOfFile(const char *pFileName)
|
||||||
|
{
|
||||||
|
NSString* pPath = [NSString stringWithUTF8String:pFileName];
|
||||||
|
NSDictionary* pDict = [NSDictionary dictionaryWithContentsOfFile:pPath];
|
||||||
|
|
||||||
|
CCDictionary* pRet = new CCDictionary();
|
||||||
|
for (id key in [pDict allKeys]) {
|
||||||
|
id value = [pDict objectForKey:key];
|
||||||
|
static_addValueToCCDict(key, value, pRet);
|
||||||
|
}
|
||||||
|
pRet->autorelease();
|
||||||
|
return pRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned char* CCFileUtils::getFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize)
|
||||||
|
{
|
||||||
|
unsigned char * pBuffer = NULL;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// read the file from hardware
|
||||||
|
FILE *fp = fopen(pszFileName, pszMode);
|
||||||
|
CC_BREAK_IF(!fp);
|
||||||
|
|
||||||
|
fseek(fp,0,SEEK_END);
|
||||||
|
*pSize = ftell(fp);
|
||||||
|
fseek(fp,0,SEEK_SET);
|
||||||
|
pBuffer = new unsigned char[*pSize];
|
||||||
|
*pSize = fread(pBuffer,sizeof(unsigned char), *pSize,fp);
|
||||||
|
fclose(fp);
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
if (! pBuffer && getIsPopupNotify())
|
||||||
|
{
|
||||||
|
std::string title = "Notification";
|
||||||
|
std::string msg = "Get data from file(";
|
||||||
|
msg.append(pszFileName).append(") failed!");
|
||||||
|
|
||||||
|
CCMessageBox(msg.c_str(), title.c_str());
|
||||||
|
}
|
||||||
|
return pBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCFileUtils::setResource(const char* pszZipFileName)
|
||||||
|
{
|
||||||
|
CCAssert(0, "Have not implement!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCFileUtils::setRelativePath(const char* pszRelativePath)
|
||||||
|
{
|
||||||
|
CCAssert(0, "Have not implement!");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// notification support when getFileData from a invalid file
|
||||||
|
static bool s_bPopupNotify = true;
|
||||||
|
|
||||||
|
void CCFileUtils::setPopupNotify(bool bNotify)
|
||||||
|
{
|
||||||
|
s_bPopupNotify = bNotify;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCFileUtils::isPopupNotify()
|
||||||
|
{
|
||||||
|
return s_bPopupNotify;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CCFileUtils::getWriteablePath()
|
||||||
|
{
|
||||||
|
// save to document folder
|
||||||
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||||
|
NSString *documentsDirectory = [paths objectAtIndex:0];
|
||||||
|
std::string strRet = [documentsDirectory UTF8String];
|
||||||
|
strRet.append("/");
|
||||||
|
return strRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
}//namespace cocos2d
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __CCGL_H__
|
||||||
|
#define __CCGL_H__
|
||||||
|
|
||||||
|
#import <OpenGL/gl.h>
|
||||||
|
#import <OpenGL/glext.h>
|
||||||
|
|
||||||
|
#define CC_GL_DEPTH24_STENCIL8 -1
|
||||||
|
|
||||||
|
#endif // __CCGL_H__
|
|
@ -0,0 +1,881 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
#include <Foundation/Foundation.h>
|
||||||
|
#include <Cocoa/Cocoa.h>
|
||||||
|
#include "CCDirector.h"
|
||||||
|
#include "ccMacros.h"
|
||||||
|
#include "CCImage.h"
|
||||||
|
#include "CCFileUtils.h"
|
||||||
|
#include "CCTexture2D.h"
|
||||||
|
#include <string>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int height;
|
||||||
|
unsigned int width;
|
||||||
|
int bitsPerComponent;
|
||||||
|
bool hasAlpha;
|
||||||
|
bool isPremultipliedAlpha;
|
||||||
|
unsigned char* data;
|
||||||
|
} tImageInfo;
|
||||||
|
|
||||||
|
static unsigned int nextPOT(unsigned int x)
|
||||||
|
{
|
||||||
|
x = x - 1;
|
||||||
|
x = x | (x >> 1);
|
||||||
|
x = x | (x >> 2);
|
||||||
|
x = x | (x >> 4);
|
||||||
|
x = x | (x >> 8);
|
||||||
|
x = x | (x >> 16);
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kCCTexture2DPixelFormat_Automatic = 0,
|
||||||
|
//! 32-bit texture: RGBA8888
|
||||||
|
kCCTexture2DPixelFormat_RGBA8888,
|
||||||
|
//! 24-bit texture: RGBA888
|
||||||
|
kCCTexture2DPixelFormat_RGB888,
|
||||||
|
//! 16-bit texture without Alpha channel
|
||||||
|
kCCTexture2DPixelFormat_RGB565,
|
||||||
|
//! 8-bit textures used as masks
|
||||||
|
kCCTexture2DPixelFormat_A8,
|
||||||
|
//! 16-bit textures: RGBA4444
|
||||||
|
kCCTexture2DPixelFormat_RGBA4444,
|
||||||
|
//! 16-bit textures: RGB5A1
|
||||||
|
kCCTexture2DPixelFormat_RGB5A1,
|
||||||
|
|
||||||
|
//! Default texture format: RGBA8888
|
||||||
|
kCCTexture2DPixelFormat_Default = kCCTexture2DPixelFormat_RGBA8888,
|
||||||
|
|
||||||
|
// backward compatibility stuff
|
||||||
|
kTexture2DPixelFormat_Automatic = kCCTexture2DPixelFormat_Automatic,
|
||||||
|
kTexture2DPixelFormat_RGBA8888 = kCCTexture2DPixelFormat_RGBA8888,
|
||||||
|
kTexture2DPixelFormat_RGB888 = kCCTexture2DPixelFormat_RGB888,
|
||||||
|
kTexture2DPixelFormat_RGB565 = kCCTexture2DPixelFormat_RGB565,
|
||||||
|
kTexture2DPixelFormat_A8 = kCCTexture2DPixelFormat_A8,
|
||||||
|
kTexture2DPixelFormat_RGBA4444 = kCCTexture2DPixelFormat_RGBA4444,
|
||||||
|
kTexture2DPixelFormat_RGB5A1 = kCCTexture2DPixelFormat_RGB5A1,
|
||||||
|
kTexture2DPixelFormat_Default = kCCTexture2DPixelFormat_Default
|
||||||
|
|
||||||
|
} CCTexture2DPixelFormat;
|
||||||
|
|
||||||
|
static bool _initPremultipliedATextureWithImage(CGImageRef image, NSUInteger POTWide, NSUInteger POTHigh, tImageInfo *pImageInfo)
|
||||||
|
{
|
||||||
|
NSUInteger i;
|
||||||
|
CGContextRef context = nil;
|
||||||
|
unsigned char* data = nil;;
|
||||||
|
CGColorSpaceRef colorSpace;
|
||||||
|
unsigned char* tempData;
|
||||||
|
unsigned int* inPixel32;
|
||||||
|
unsigned short* outPixel16;
|
||||||
|
bool hasAlpha;
|
||||||
|
CGImageAlphaInfo info;
|
||||||
|
CGSize imageSize;
|
||||||
|
CCTexture2DPixelFormat pixelFormat;
|
||||||
|
|
||||||
|
info = CGImageGetAlphaInfo(image);
|
||||||
|
hasAlpha = ((info == kCGImageAlphaPremultipliedLast) || (info == kCGImageAlphaPremultipliedFirst) || (info == kCGImageAlphaLast) || (info == kCGImageAlphaFirst) ? YES : NO);
|
||||||
|
|
||||||
|
size_t bpp = CGImageGetBitsPerComponent(image);
|
||||||
|
colorSpace = CGImageGetColorSpace(image);
|
||||||
|
|
||||||
|
if(colorSpace)
|
||||||
|
{
|
||||||
|
if(hasAlpha || bpp >= 8)
|
||||||
|
{
|
||||||
|
pixelFormat = kCCTexture2DPixelFormat_Default;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pixelFormat = kCCTexture2DPixelFormat_RGB565;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NOTE: No colorspace means a mask image
|
||||||
|
pixelFormat = kCCTexture2DPixelFormat_A8;
|
||||||
|
}
|
||||||
|
|
||||||
|
imageSize.width = CGImageGetWidth(image);
|
||||||
|
imageSize.height = CGImageGetHeight(image);
|
||||||
|
|
||||||
|
// Create the bitmap graphics context
|
||||||
|
|
||||||
|
switch(pixelFormat)
|
||||||
|
{
|
||||||
|
case kCCTexture2DPixelFormat_RGBA8888:
|
||||||
|
case kCCTexture2DPixelFormat_RGBA4444:
|
||||||
|
case kCCTexture2DPixelFormat_RGB5A1:
|
||||||
|
colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||||
|
data = new unsigned char[POTHigh * POTWide * 4];
|
||||||
|
info = hasAlpha ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast;
|
||||||
|
context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, 4 * POTWide, colorSpace, info | kCGBitmapByteOrder32Big);
|
||||||
|
CGColorSpaceRelease(colorSpace);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kCCTexture2DPixelFormat_RGB565:
|
||||||
|
colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||||
|
data = new unsigned char[POTHigh * POTWide * 4];
|
||||||
|
info = kCGImageAlphaNoneSkipLast;
|
||||||
|
context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, 4 * POTWide, colorSpace, info | kCGBitmapByteOrder32Big);
|
||||||
|
CGColorSpaceRelease(colorSpace);
|
||||||
|
break;
|
||||||
|
case kCCTexture2DPixelFormat_A8:
|
||||||
|
data = new unsigned char[POTHigh * POTWide];
|
||||||
|
info = kCGImageAlphaOnly;
|
||||||
|
context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide, NULL, info);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGRect rect;
|
||||||
|
rect.size.width = POTWide;
|
||||||
|
rect.size.height = POTHigh;
|
||||||
|
rect.origin.x = 0;
|
||||||
|
rect.origin.y = 0;
|
||||||
|
|
||||||
|
CGContextClearRect(context, rect);
|
||||||
|
CGContextTranslateCTM(context, 0, 0);
|
||||||
|
CGContextDrawImage(context, rect, image);
|
||||||
|
|
||||||
|
// Repack the pixel data into the right format
|
||||||
|
|
||||||
|
if(pixelFormat == kCCTexture2DPixelFormat_RGB565)
|
||||||
|
{
|
||||||
|
//Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB"
|
||||||
|
tempData = new unsigned char[POTHigh * POTWide * 2];
|
||||||
|
inPixel32 = (unsigned int*)data;
|
||||||
|
outPixel16 = (unsigned short*)tempData;
|
||||||
|
for(i = 0; i < POTWide * POTHigh; ++i, ++inPixel32)
|
||||||
|
{
|
||||||
|
*outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
data = tempData;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (pixelFormat == kCCTexture2DPixelFormat_RGBA4444)
|
||||||
|
{
|
||||||
|
//Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA"
|
||||||
|
tempData = new unsigned char[POTHigh * POTWide * 2];
|
||||||
|
inPixel32 = (unsigned int*)data;
|
||||||
|
outPixel16 = (unsigned short*)tempData;
|
||||||
|
for(i = 0; i < POTWide * POTHigh; ++i, ++inPixel32)
|
||||||
|
{
|
||||||
|
*outPixel16++ =
|
||||||
|
((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R
|
||||||
|
((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G
|
||||||
|
((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B
|
||||||
|
((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
data = tempData;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (pixelFormat == kCCTexture2DPixelFormat_RGB5A1)
|
||||||
|
{
|
||||||
|
//Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA"
|
||||||
|
tempData = new unsigned char[POTHigh * POTWide * 2];
|
||||||
|
inPixel32 = (unsigned int*)data;
|
||||||
|
outPixel16 = (unsigned short*)tempData;
|
||||||
|
for(i = 0; i < POTWide * POTHigh; ++i, ++inPixel32)
|
||||||
|
{
|
||||||
|
*outPixel16++ =
|
||||||
|
((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R
|
||||||
|
((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G
|
||||||
|
((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B
|
||||||
|
((((*inPixel32 >> 24) & 0xFF) >> 7) << 0); // A
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
data = tempData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// should be after calling super init
|
||||||
|
pImageInfo->isPremultipliedAlpha = true;
|
||||||
|
pImageInfo->hasAlpha = true;
|
||||||
|
pImageInfo->bitsPerComponent = bpp;
|
||||||
|
pImageInfo->width = POTWide;
|
||||||
|
pImageInfo->height = POTHigh;
|
||||||
|
|
||||||
|
if (pImageInfo->data)
|
||||||
|
{
|
||||||
|
delete [] pImageInfo->data;
|
||||||
|
}
|
||||||
|
pImageInfo->data = data;
|
||||||
|
|
||||||
|
CGContextRelease(context);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _initWithImage(CGImageRef CGImage, tImageInfo *pImageinfo, double scaleX, double scaleY)
|
||||||
|
{
|
||||||
|
NSUInteger POTWide, POTHigh;
|
||||||
|
|
||||||
|
if(CGImage == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (cocos2d::CCImage::getIsScaleEnabled())
|
||||||
|
if( cocos2d::CCDirector::sharedDirector()->getContentScaleFactor() > 1.0f )
|
||||||
|
{
|
||||||
|
POTWide = CGImageGetWidth(CGImage) * scaleX;
|
||||||
|
POTHigh = CGImageGetHeight(CGImage) * scaleY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
POTWide = CGImageGetWidth(CGImage);
|
||||||
|
POTHigh = CGImageGetHeight(CGImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// always load premultiplied images
|
||||||
|
_initPremultipliedATextureWithImage(CGImage, POTWide, POTHigh, pImageinfo);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _initWithFile(const char* path, tImageInfo *pImageinfo)
|
||||||
|
{
|
||||||
|
CGImageRef CGImage;
|
||||||
|
NSImage *jpg;
|
||||||
|
NSImage *png;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
// convert jpg to png before loading the texture
|
||||||
|
|
||||||
|
NSString *fullPath = [NSString stringWithUTF8String:path];
|
||||||
|
jpg = [[NSImage alloc] initWithContentsOfFile: fullPath];
|
||||||
|
//png = [[NSImage alloc] initWithData:UIImagePNGRepresentation(jpg)];
|
||||||
|
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)[jpg TIFFRepresentation], NULL);
|
||||||
|
CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL);
|
||||||
|
|
||||||
|
ret = _initWithImage(CGImage, pImageinfo, 1.0, 1.0);
|
||||||
|
|
||||||
|
[png release];
|
||||||
|
[jpg release];
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool _initWithData(void * pBuffer, int length, tImageInfo *pImageinfo, double scaleX, double scaleY)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (pBuffer)
|
||||||
|
{
|
||||||
|
CGImageRef CGImage;
|
||||||
|
NSData *data;
|
||||||
|
|
||||||
|
data = [NSData dataWithBytes:pBuffer length:length];
|
||||||
|
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, NULL);
|
||||||
|
CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL);
|
||||||
|
|
||||||
|
ret = _initWithImage(CGImage, pImageinfo, scaleX, scaleY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _isValidFontName(const char *fontName)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
#if 0
|
||||||
|
NSString *fontNameNS = [NSString stringWithUTF8String:fontName];
|
||||||
|
|
||||||
|
for (NSString *familiName in [NSFont familyNames])
|
||||||
|
{
|
||||||
|
if ([familiName isEqualToString:fontNameNS])
|
||||||
|
{
|
||||||
|
ret = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(NSString *font in [NSFont fontNamesForFamilyName: familiName])
|
||||||
|
{
|
||||||
|
if ([font isEqualToString: fontNameNS])
|
||||||
|
{
|
||||||
|
ret = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _initWithString(const char * pText, cocos2d::CCImage::ETextAlign eAlign, const char * pFontName, int nSize, tImageInfo* pInfo, cocos2d::ccColor3B* pStrokeColor)
|
||||||
|
{
|
||||||
|
bool bRet = false;
|
||||||
|
|
||||||
|
CCAssert( pText, @"Invalid pText");
|
||||||
|
CCAssert( pInfo, @"Invalid pInfo");
|
||||||
|
|
||||||
|
do {
|
||||||
|
NSString * string = [NSString stringWithUTF8String:pText];
|
||||||
|
//string = [NSString stringWithFormat:@"d\r\nhello world hello kitty Hello what %@", string];
|
||||||
|
|
||||||
|
// font
|
||||||
|
NSFont *font = [[NSFontManager sharedFontManager]
|
||||||
|
fontWithFamily:[NSString stringWithUTF8String:pFontName]
|
||||||
|
traits:NSUnboldFontMask | NSUnitalicFontMask
|
||||||
|
weight:0
|
||||||
|
size:nSize];
|
||||||
|
|
||||||
|
if (font == nil) {
|
||||||
|
font = [[NSFontManager sharedFontManager]
|
||||||
|
fontWithFamily:@"Arial"
|
||||||
|
traits:NSUnboldFontMask | NSUnitalicFontMask
|
||||||
|
weight:0
|
||||||
|
size:nSize];
|
||||||
|
}
|
||||||
|
CC_BREAK_IF(!font);
|
||||||
|
|
||||||
|
// color
|
||||||
|
NSColor* foregroundColor;
|
||||||
|
if (pStrokeColor) {
|
||||||
|
foregroundColor = [NSColor colorWithDeviceRed:pStrokeColor->r/255.0 green:pStrokeColor->g/255.0 blue:pStrokeColor->b/255.0 alpha:1];
|
||||||
|
} else {
|
||||||
|
foregroundColor = [NSColor whiteColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// alignment, linebreak
|
||||||
|
unsigned uHoriFlag = eAlign & 0x0f;
|
||||||
|
unsigned uVertFlag = (eAlign & 0xf0) >> 4;
|
||||||
|
NSTextAlignment align = (2 == uHoriFlag) ? NSRightTextAlignment
|
||||||
|
: (3 == uHoriFlag) ? NSCenterTextAlignment
|
||||||
|
: NSLeftTextAlignment;
|
||||||
|
|
||||||
|
NSMutableParagraphStyle *paragraphStyle = [[[NSMutableParagraphStyle alloc] init] autorelease];
|
||||||
|
[paragraphStyle setParagraphStyle:[NSParagraphStyle defaultParagraphStyle]];
|
||||||
|
[paragraphStyle setLineBreakMode:NSLineBreakByCharWrapping];
|
||||||
|
[paragraphStyle setAlignment:align];
|
||||||
|
|
||||||
|
// attribute
|
||||||
|
NSDictionary* tokenAttributesDict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
foregroundColor,NSForegroundColorAttributeName,
|
||||||
|
font, NSFontAttributeName,
|
||||||
|
paragraphStyle, NSParagraphStyleAttributeName, nil];
|
||||||
|
|
||||||
|
// linebreak
|
||||||
|
if (pInfo->width > 0) {
|
||||||
|
if ([string sizeWithAttributes:tokenAttributesDict].width > pInfo->width) {
|
||||||
|
NSMutableString *lineBreak = [[[NSMutableString alloc] init] autorelease];
|
||||||
|
NSUInteger length = [string length];
|
||||||
|
NSRange range = NSMakeRange(0, 1);
|
||||||
|
NSUInteger width = 0;
|
||||||
|
for (NSUInteger i = 0; i < length; i++) {
|
||||||
|
range.location = i;
|
||||||
|
[lineBreak appendString:[string substringWithRange:range]];
|
||||||
|
width = [lineBreak sizeWithAttributes:tokenAttributesDict].width;
|
||||||
|
if (width > pInfo->width) {
|
||||||
|
[lineBreak insertString:@"\r\n" atIndex:[lineBreak length] - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string = lineBreak;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NSAttributedString *stringWithAttributes =[[[NSAttributedString alloc] initWithString:string
|
||||||
|
attributes:tokenAttributesDict] autorelease];
|
||||||
|
|
||||||
|
NSSize realDimensions = [stringWithAttributes size];
|
||||||
|
// Mac crashes if the width or height is 0
|
||||||
|
CC_BREAK_IF(realDimensions.width <= 0 || realDimensions.height <= 0);
|
||||||
|
|
||||||
|
CGSize dimensions = CGSizeMake(pInfo->width, pInfo->height);
|
||||||
|
|
||||||
|
|
||||||
|
if(dimensions.width <= 0 && dimensions.height <= 0) {
|
||||||
|
dimensions.width = realDimensions.width;
|
||||||
|
dimensions.height = realDimensions.height;
|
||||||
|
} else if (dimensions.height <= 0) {
|
||||||
|
dimensions.height = realDimensions.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSUInteger POTWide = (NSUInteger)dimensions.width;
|
||||||
|
NSUInteger POTHigh = (NSUInteger)(MAX(dimensions.height, realDimensions.height));
|
||||||
|
unsigned char* data;
|
||||||
|
//Alignment
|
||||||
|
|
||||||
|
CGFloat xPadding = 0;
|
||||||
|
switch (align) {
|
||||||
|
case NSLeftTextAlignment: xPadding = 0; break;
|
||||||
|
case NSCenterTextAlignment: xPadding = (dimensions.width-realDimensions.width)/2.0f; break;
|
||||||
|
case NSRightTextAlignment: xPadding = dimensions.width-realDimensions.width; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGFloat yPadding = (1 == uVertFlag || realDimensions.height >= dimensions.height) ? 0 // align to top
|
||||||
|
: (2 == uVertFlag) ? dimensions.height - realDimensions.height // align to bottom
|
||||||
|
: (dimensions.height - realDimensions.height) / 2.0f; // align to center
|
||||||
|
|
||||||
|
|
||||||
|
NSRect textRect = NSMakeRect(xPadding, POTHigh - dimensions.height + yPadding, realDimensions.width, realDimensions.height);
|
||||||
|
//Disable antialias
|
||||||
|
|
||||||
|
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
|
||||||
|
|
||||||
|
NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(POTWide, POTHigh)];
|
||||||
|
[image lockFocus];
|
||||||
|
|
||||||
|
//[stringWithAttributes drawAtPoint:NSMakePoint(xPadding, offsetY)]; // draw at offset position
|
||||||
|
[stringWithAttributes drawInRect:textRect];
|
||||||
|
//[stringWithAttributes drawInRect:textRect withAttributes:tokenAttributesDict];
|
||||||
|
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect (0.0f, 0.0f, POTWide, POTHigh)];
|
||||||
|
[image unlockFocus];
|
||||||
|
|
||||||
|
data = (unsigned char*) [bitmap bitmapData]; //Use the same buffer to improve the performance.
|
||||||
|
|
||||||
|
NSUInteger textureSize = POTWide*POTHigh*4;
|
||||||
|
|
||||||
|
unsigned char* dataNew = new unsigned char[textureSize];
|
||||||
|
CC_BREAK_IF(!dataNew);
|
||||||
|
memcpy(dataNew, data, textureSize);
|
||||||
|
|
||||||
|
[bitmap release];
|
||||||
|
[image release];
|
||||||
|
|
||||||
|
// output params
|
||||||
|
pInfo->width = POTWide;
|
||||||
|
pInfo->height = POTHigh;
|
||||||
|
pInfo->data = dataNew;
|
||||||
|
pInfo->hasAlpha = true;
|
||||||
|
pInfo->isPremultipliedAlpha = true;
|
||||||
|
pInfo->bitsPerComponent = 8;
|
||||||
|
|
||||||
|
bRet = true;
|
||||||
|
} while (0);
|
||||||
|
return bRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_CC_BEGIN;
|
||||||
|
|
||||||
|
static bool m_bEnabledScale = true;
|
||||||
|
|
||||||
|
bool isFileExists(const char* szFilePath);
|
||||||
|
|
||||||
|
bool isFileExists(const char* szFilePath)
|
||||||
|
{
|
||||||
|
#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
|
||||||
|
//TCHAR dirpath[MAX_PATH];
|
||||||
|
//MultiByteToWideChar(936,0,szFilePath,-1,dirpath,sizeof(dirpath));
|
||||||
|
DWORD dwFileAttr = GetFileAttributesA(szFilePath);
|
||||||
|
if (INVALID_FILE_ATTRIBUTES == dwFileAttr
|
||||||
|
|| (dwFileAttr&FILE_ATTRIBUTE_DIRECTORY)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||||
|
bool bFind = true;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
struct stat buf;
|
||||||
|
int n = stat(szFilePath, &buf);
|
||||||
|
if ((0 != n)
|
||||||
|
|| !(buf.st_mode&S_IFMT))
|
||||||
|
{
|
||||||
|
bFind = false;
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
if (!bFind)
|
||||||
|
{
|
||||||
|
//std::string strFilenName = s_strRelativePath + szFilePath;
|
||||||
|
unsigned char * pBuffer = NULL;
|
||||||
|
unzFile pFile = NULL;
|
||||||
|
unsigned long pSize = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pFile = unzOpen(s_strAndroidPackagePath.c_str());
|
||||||
|
if(!pFile)break;
|
||||||
|
|
||||||
|
int nRet = unzLocateFile(pFile, szFilePath, 1);
|
||||||
|
if(UNZ_OK != nRet)
|
||||||
|
bFind = false;
|
||||||
|
else
|
||||||
|
bFind = true;
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
if (pFile)
|
||||||
|
{
|
||||||
|
unzClose(pFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bFind;
|
||||||
|
#else
|
||||||
|
struct stat buf;
|
||||||
|
int n = stat(szFilePath, &buf);
|
||||||
|
if ((0 != n)
|
||||||
|
|| !(buf.st_mode&S_IFMT)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCImage::CCImage()
|
||||||
|
: m_nWidth(0)
|
||||||
|
, m_nHeight(0)
|
||||||
|
, m_nBitsPerComponent(0)
|
||||||
|
, m_pData(0)
|
||||||
|
, m_bHasAlpha(false)
|
||||||
|
, m_bPreMulti(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CCImage::~CCImage()
|
||||||
|
{
|
||||||
|
CC_SAFE_DELETE_ARRAY(m_pData);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCImage::initWithImageFile(const char * strPath, EImageFormat eImgFmt/* = eFmtPng*/)
|
||||||
|
{
|
||||||
|
std::string strTemp = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(strPath);
|
||||||
|
if (m_bEnabledScale)
|
||||||
|
{
|
||||||
|
if (!isFileExists(strTemp.c_str()))
|
||||||
|
{
|
||||||
|
if (strTemp.rfind("@2x") == std::string::npos)
|
||||||
|
{
|
||||||
|
int t = strTemp.rfind(".");
|
||||||
|
if (t != std::string::npos)
|
||||||
|
{
|
||||||
|
strTemp.insert(t, "@2x");
|
||||||
|
}
|
||||||
|
/* CCSize size = CCDirector::sharedDirector()->getWinSize();
|
||||||
|
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
|
||||||
|
m_dScaleX = size.width/800.0f;
|
||||||
|
m_dScaleY = size.height/480.0f;
|
||||||
|
#else
|
||||||
|
m_dScaleX = size.width/960.0f;
|
||||||
|
m_dScaleY = size.height/640.0f;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// m_dScaleX = 1.0;
|
||||||
|
// m_dScaleY = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CCFileData tempData(strTemp.c_str(), "rb");
|
||||||
|
// return initWithImageData(tempData.getBuffer(), tempData.getSize(), eImgFmt);
|
||||||
|
|
||||||
|
unsigned long fileSize = 0;
|
||||||
|
unsigned char* pFileData = CCFileUtils::sharedFileUtils()->getFileData(strTemp.c_str(), "rb", &fileSize);
|
||||||
|
bool ret = initWithImageData(pFileData, fileSize, eImgFmt);
|
||||||
|
free(pFileData);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCImage::initWithImageFileThreadSafe(const char *fullpath, EImageFormat imageType)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* CCFileUtils::fullPathFromRelativePath() is not thread-safe, it use autorelease().
|
||||||
|
*/
|
||||||
|
bool bRet = false;
|
||||||
|
unsigned long nSize = 0;
|
||||||
|
unsigned char* pBuffer = CCFileUtils::sharedFileUtils()->getFileData(fullpath, "rb", &nSize);
|
||||||
|
if (pBuffer != NULL && nSize > 0)
|
||||||
|
{
|
||||||
|
bRet = initWithImageData(pBuffer, nSize, imageType);
|
||||||
|
}
|
||||||
|
CC_SAFE_DELETE_ARRAY(pBuffer);
|
||||||
|
return bRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
// please uncomment this and integrate it somehow if you know what your doing, thanks
|
||||||
|
bool CCImage::potImageData(unsigned int POTWide, unsigned int POTHigh)
|
||||||
|
{
|
||||||
|
unsigned char* data = NULL;
|
||||||
|
unsigned char* tempData =NULL;
|
||||||
|
unsigned int* inPixel32 = NULL;
|
||||||
|
unsigned short* outPixel16 = NULL;
|
||||||
|
bool hasAlpha;
|
||||||
|
CCTexture2DPixelFormat pixelFormat;
|
||||||
|
|
||||||
|
hasAlpha = this->hasAlpha();
|
||||||
|
|
||||||
|
size_t bpp = this->getBitsPerComponent();
|
||||||
|
|
||||||
|
// compute pixel format
|
||||||
|
if(hasAlpha)
|
||||||
|
{
|
||||||
|
pixelFormat = CCTexture2D::defaultAlphaPixelFormat();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (bpp >= 8)
|
||||||
|
{
|
||||||
|
pixelFormat = kCCTexture2DPixelFormat_RGB888;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CCLOG("cocos2d: CCTexture2D: Using RGB565 texture since image has no alpha");
|
||||||
|
pixelFormat = kCCTexture2DPixelFormat_RGB565;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(pixelFormat) {
|
||||||
|
case kCCTexture2DPixelFormat_RGBA8888:
|
||||||
|
case kCCTexture2DPixelFormat_RGBA4444:
|
||||||
|
case kCCTexture2DPixelFormat_RGB5A1:
|
||||||
|
case kCCTexture2DPixelFormat_RGB565:
|
||||||
|
case kCCTexture2DPixelFormat_A8:
|
||||||
|
tempData = (unsigned char*)(this->getData());
|
||||||
|
CCAssert(tempData != NULL, "NULL image data.");
|
||||||
|
|
||||||
|
if(this->getWidth() == (short)POTWide && this->getHeight() == (short)POTHigh)
|
||||||
|
{
|
||||||
|
data = new unsigned char[POTHigh * POTWide * 4];
|
||||||
|
memcpy(data, tempData, POTHigh * POTWide * 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = new unsigned char[POTHigh * POTWide * 4];
|
||||||
|
memset(data, 0, POTHigh * POTWide * 4);
|
||||||
|
|
||||||
|
unsigned char* pPixelData = (unsigned char*) tempData;
|
||||||
|
unsigned char* pTargetData = (unsigned char*) data;
|
||||||
|
|
||||||
|
int imageHeight = this->getHeight();
|
||||||
|
for(int y = 0; y < imageHeight; ++y)
|
||||||
|
{
|
||||||
|
memcpy(pTargetData+POTWide*4*y, pPixelData+(this->getWidth())*4*y, (this->getWidth())*4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case kCCTexture2DPixelFormat_RGB888:
|
||||||
|
tempData = (unsigned char*)(this->getData());
|
||||||
|
CCAssert(tempData != NULL, "NULL image data.");
|
||||||
|
if(this->getWidth() == (short)POTWide && this->getHeight() == (short)POTHigh)
|
||||||
|
{
|
||||||
|
data = new unsigned char[POTHigh * POTWide * 3];
|
||||||
|
memcpy(data, tempData, POTHigh * POTWide * 3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = new unsigned char[POTHigh * POTWide * 3];
|
||||||
|
memset(data, 0, POTHigh * POTWide * 3);
|
||||||
|
|
||||||
|
unsigned char* pPixelData = (unsigned char*) tempData;
|
||||||
|
unsigned char* pTargetData = (unsigned char*) data;
|
||||||
|
|
||||||
|
int imageHeight = this->getHeight();
|
||||||
|
for(int y = 0; y < imageHeight; ++y)
|
||||||
|
{
|
||||||
|
memcpy(pTargetData+POTWide*3*y, pPixelData+(this->getWidth())*3*y, (this->getWidth())*3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CCAssert(0, "Invalid pixel format");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repack the pixel data into the right format
|
||||||
|
|
||||||
|
if(pixelFormat == kCCTexture2DPixelFormat_RGB565) {
|
||||||
|
//Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB"
|
||||||
|
tempData = new unsigned char[POTHigh * POTWide * 2];
|
||||||
|
inPixel32 = (unsigned int*)data;
|
||||||
|
outPixel16 = (unsigned short*)tempData;
|
||||||
|
|
||||||
|
unsigned int length = POTWide * POTHigh;
|
||||||
|
for(unsigned int i = 0; i < length; ++i, ++inPixel32)
|
||||||
|
{
|
||||||
|
*outPixel16++ =
|
||||||
|
((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R
|
||||||
|
((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | // G
|
||||||
|
((((*inPixel32 >> 16) & 0xFF) >> 3) << 0); // B
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] data;
|
||||||
|
data = tempData;
|
||||||
|
}
|
||||||
|
else if (pixelFormat == kCCTexture2DPixelFormat_RGBA4444) {
|
||||||
|
//Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA"
|
||||||
|
tempData = new unsigned char[POTHigh * POTWide * 2];
|
||||||
|
inPixel32 = (unsigned int*)data;
|
||||||
|
outPixel16 = (unsigned short*)tempData;
|
||||||
|
|
||||||
|
unsigned int length = POTWide * POTHigh;
|
||||||
|
for(unsigned int i = 0; i < length; ++i, ++inPixel32)
|
||||||
|
{
|
||||||
|
*outPixel16++ =
|
||||||
|
((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R
|
||||||
|
((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G
|
||||||
|
((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B
|
||||||
|
((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] data;
|
||||||
|
data = tempData;
|
||||||
|
}
|
||||||
|
else if (pixelFormat == kCCTexture2DPixelFormat_RGB5A1) {
|
||||||
|
//Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA"
|
||||||
|
tempData = new unsigned char[POTHigh * POTWide * 2];
|
||||||
|
inPixel32 = (unsigned int*)data;
|
||||||
|
outPixel16 = (unsigned short*)tempData;
|
||||||
|
|
||||||
|
unsigned int length = POTWide * POTHigh;
|
||||||
|
for(unsigned int i = 0; i < length; ++i, ++inPixel32)
|
||||||
|
{
|
||||||
|
*outPixel16++ =
|
||||||
|
((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R
|
||||||
|
((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G
|
||||||
|
((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B
|
||||||
|
((((*inPixel32 >> 24) & 0xFF) >> 7) << 0); // A
|
||||||
|
}
|
||||||
|
|
||||||
|
delete []data;
|
||||||
|
data = tempData;
|
||||||
|
}
|
||||||
|
else if (pixelFormat == kCCTexture2DPixelFormat_A8)
|
||||||
|
{
|
||||||
|
// fix me, how to convert to A8
|
||||||
|
pixelFormat = kCCTexture2DPixelFormat_RGBA8888;
|
||||||
|
|
||||||
|
//
|
||||||
|
//The code can not work, how to convert to A8?
|
||||||
|
//
|
||||||
|
//tempData = new unsigned char[POTHigh * POTWide];
|
||||||
|
//inPixel32 = (unsigned int*)data;
|
||||||
|
//outPixel8 = tempData;
|
||||||
|
|
||||||
|
//unsigned int length = POTWide * POTHigh;
|
||||||
|
//for(unsigned int i = 0; i < length; ++i, ++inPixel32)
|
||||||
|
//{
|
||||||
|
// *outPixel8++ = (*inPixel32 >> 24) & 0xFF;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//delete []data;
|
||||||
|
//data = tempData;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
CC_SAFE_DELETE_ARRAY(m_pData);
|
||||||
|
m_pData = data;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
//bool CCImage::initWithImageData(void * pData, int nDataLen, EImageFormat eFmt/* = eSrcFmtPng*/)
|
||||||
|
bool CCImage::initWithImageData(void * pData,
|
||||||
|
int nDataLen,
|
||||||
|
EImageFormat eFmt,
|
||||||
|
int nWidth,
|
||||||
|
int nHeight,
|
||||||
|
int nBitsPerComponent)
|
||||||
|
{
|
||||||
|
bool bRet = false;
|
||||||
|
tImageInfo info = {0};
|
||||||
|
do
|
||||||
|
{
|
||||||
|
CC_BREAK_IF(! pData || nDataLen <= 0);
|
||||||
|
bRet = _initWithData(pData, nDataLen, &info, 1.0f, 1.0f);//m_dScaleX, m_dScaleY);
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
if (bRet)
|
||||||
|
{
|
||||||
|
m_nHeight = (short)info.height;
|
||||||
|
m_nWidth = (short)info.width;
|
||||||
|
m_nBitsPerComponent = info.bitsPerComponent;
|
||||||
|
if (eFmt == kFmtJpg)
|
||||||
|
{
|
||||||
|
m_bHasAlpha = true;
|
||||||
|
m_bPreMulti = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_bHasAlpha = info.hasAlpha;
|
||||||
|
m_bPreMulti = info.isPremultipliedAlpha;
|
||||||
|
}
|
||||||
|
m_pData = info.data;
|
||||||
|
}
|
||||||
|
return bRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCImage::initWithString(
|
||||||
|
const char * pText,
|
||||||
|
int nWidth,
|
||||||
|
int nHeight,
|
||||||
|
ETextAlign eAlignMask,
|
||||||
|
const char * pFontName,
|
||||||
|
int nSize)
|
||||||
|
{
|
||||||
|
tImageInfo info = {0};
|
||||||
|
info.width = nWidth;
|
||||||
|
info.height = nHeight;
|
||||||
|
|
||||||
|
if (! _initWithString(pText, eAlignMask, pFontName, nSize, &info, NULL)) //pStrokeColor))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_nHeight = (short)info.height;
|
||||||
|
m_nWidth = (short)info.width;
|
||||||
|
m_nBitsPerComponent = info.bitsPerComponent;
|
||||||
|
m_bHasAlpha = info.hasAlpha;
|
||||||
|
m_bPreMulti = info.isPremultipliedAlpha;
|
||||||
|
if (m_pData) {
|
||||||
|
CC_SAFE_DELETE_ARRAY(m_pData);
|
||||||
|
}
|
||||||
|
m_pData = info.data;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCImage::saveToFile(const char *pszFilePath, bool bIsToRGB)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NS_CC_END;
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef __CCPLATFORMDEFINE_H__
|
||||||
|
#define __CCPLATFORMDEFINE_H__
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define CC_DLL
|
||||||
|
|
||||||
|
#define CC_ASSERT(cond) assert(cond)
|
||||||
|
|
||||||
|
|
||||||
|
#define CC_UNUSED_PARAM(unusedparam) (void)unusedparam
|
||||||
|
|
||||||
|
/* Define NULL pointer value */
|
||||||
|
#ifndef NULL
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define NULL 0
|
||||||
|
#else
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __CCPLATFORMDEFINE_H__*/
|
|
@ -0,0 +1,46 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __CC_STD_C_H__
|
||||||
|
#define __CC_STD_C_H__
|
||||||
|
|
||||||
|
#include "platform/CCPlatformMacros.h"
|
||||||
|
#include <float.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(x,y) (((x) > (y)) ? (y) : (x))
|
||||||
|
#endif // MIN
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(x,y) (((x) < (y)) ? (y) : (x))
|
||||||
|
#endif // MAX
|
||||||
|
|
||||||
|
#endif // __CC_STD_C_H__
|
|
@ -0,0 +1,38 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __CC_WINDOW_H__
|
||||||
|
#define __CC_WINDOW_H__
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
|
||||||
|
@interface CCWindow : NSWindow
|
||||||
|
{
|
||||||
|
}
|
||||||
|
- (id) initWithFrame:(NSRect)frame fullscreen:(BOOL)fullscreen;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // __CC_WINDOW_H__
|
|
@ -0,0 +1,63 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#import "CCWindow.h"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CCWindow
|
||||||
|
|
||||||
|
- (id) initWithFrame:(NSRect)frame fullscreen:(BOOL)fullscreen
|
||||||
|
{
|
||||||
|
int styleMask = fullscreen ? NSBackingStoreBuffered : ( NSTitledWindowMask | NSClosableWindowMask );
|
||||||
|
self = [self initWithContentRect:frame
|
||||||
|
styleMask:styleMask
|
||||||
|
backing:NSBackingStoreBuffered
|
||||||
|
defer:YES];
|
||||||
|
|
||||||
|
if (self != nil)
|
||||||
|
{
|
||||||
|
if(fullscreen)
|
||||||
|
{
|
||||||
|
[self setLevel:NSMainMenuWindowLevel+1];
|
||||||
|
[self setHidesOnDeactivate:YES];
|
||||||
|
[self setHasShadow:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setAcceptsMouseMovedEvents:NO];
|
||||||
|
[self setOpaque:YES];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) canBecomeKeyWindow
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) canBecomeMainWindow
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __EAGLVIEW_MAC_H__
|
||||||
|
#define __EAGLVIEW_MAC_H__
|
||||||
|
|
||||||
|
#include <Cocoa/Cocoa.h>
|
||||||
|
#include "ccConfig.h"
|
||||||
|
|
||||||
|
//PROTOCOLS:
|
||||||
|
|
||||||
|
@protocol MacEventDelegate <NSObject>
|
||||||
|
// Mouse
|
||||||
|
- (void)mouseDown:(NSEvent *)theEvent;
|
||||||
|
- (void)mouseUp:(NSEvent *)theEvent;
|
||||||
|
- (void)mouseMoved:(NSEvent *)theEvent;
|
||||||
|
- (void)mouseDragged:(NSEvent *)theEvent;
|
||||||
|
- (void)rightMouseDown:(NSEvent*)event;
|
||||||
|
- (void)rightMouseDragged:(NSEvent*)event;
|
||||||
|
- (void)rightMouseUp:(NSEvent*)event;
|
||||||
|
- (void)otherMouseDown:(NSEvent*)event;
|
||||||
|
- (void)otherMouseDragged:(NSEvent*)event;
|
||||||
|
- (void)otherMouseUp:(NSEvent*)event;
|
||||||
|
- (void)scrollWheel:(NSEvent *)theEvent;
|
||||||
|
- (void)mouseEntered:(NSEvent *)theEvent;
|
||||||
|
- (void)mouseExited:(NSEvent *)theEvent;
|
||||||
|
|
||||||
|
|
||||||
|
// Keyboard
|
||||||
|
- (void)keyDown:(NSEvent *)theEvent;
|
||||||
|
- (void)keyUp:(NSEvent *)theEvent;
|
||||||
|
- (void)flagsChanged:(NSEvent *)theEvent;
|
||||||
|
|
||||||
|
// Touches
|
||||||
|
- (void)touchesBeganWithEvent:(NSEvent *)event;
|
||||||
|
- (void)touchesMovedWithEvent:(NSEvent *)event;
|
||||||
|
- (void)touchesEndedWithEvent:(NSEvent *)event;
|
||||||
|
- (void)touchesCancelledWithEvent:(NSEvent *)event;
|
||||||
|
|
||||||
|
#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
|
||||||
|
- (void)queueEvent:(NSEvent*)event selector:(SEL)selector;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/** MacGLView
|
||||||
|
|
||||||
|
Only available for Mac OS X
|
||||||
|
*/
|
||||||
|
@interface EAGLView : NSOpenGLView {
|
||||||
|
id<MacEventDelegate> eventDelegate_;
|
||||||
|
|
||||||
|
BOOL isFullScreen_;
|
||||||
|
NSWindow *fullScreenWindow_;
|
||||||
|
|
||||||
|
// cache
|
||||||
|
NSWindow *windowGLView_;
|
||||||
|
NSView *superViewGLView_;
|
||||||
|
NSRect originalWinRect_; // Original size and position
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (nonatomic, readwrite, assign) id<MacEventDelegate> eventDelegate;
|
||||||
|
|
||||||
|
// whether or not the view is in fullscreen mode
|
||||||
|
@property (nonatomic, readonly) BOOL isFullScreen;
|
||||||
|
|
||||||
|
// initializes the MacGLView with a frame rect and an OpenGL context
|
||||||
|
- (id) initWithFrame:(NSRect)frameRect shareContext:(NSOpenGLContext*)context;
|
||||||
|
|
||||||
|
/** uses and locks the OpenGL context */
|
||||||
|
-(void) lockOpenGLContext;
|
||||||
|
|
||||||
|
/** unlocks the openGL context */
|
||||||
|
-(void) unlockOpenGLContext;
|
||||||
|
|
||||||
|
/** returns the depth format of the view in BPP */
|
||||||
|
- (NSUInteger) depthFormat;
|
||||||
|
|
||||||
|
// get the view object
|
||||||
|
+(id) sharedEGLView;
|
||||||
|
|
||||||
|
-(int) getWidth;
|
||||||
|
-(int) getHeight;
|
||||||
|
-(void) swapBuffers;
|
||||||
|
|
||||||
|
-(void) setFullScreen:(BOOL)fullscreen;
|
||||||
|
|
||||||
|
@end
|
||||||
|
#endif // __EAGLVIEW_MAC_H__
|
||||||
|
|
|
@ -0,0 +1,429 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2010 cocos2d-x.org
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Idea of subclassing NSOpenGLView was taken from "TextureUpload" Apple's sample
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Availability.h>
|
||||||
|
|
||||||
|
#import "EAGLView.h"
|
||||||
|
#import "CCEGLView.h"
|
||||||
|
#import <OpenGL/gl.h>
|
||||||
|
#import "CCDirector.h"
|
||||||
|
#import "ccConfig.h"
|
||||||
|
#import "CCSet.h"
|
||||||
|
#import "CCTouch.h"
|
||||||
|
#import "CCIMEDispatcher.h"
|
||||||
|
#import "CCWindow.h"
|
||||||
|
#import "CCEventDispatcher.h"
|
||||||
|
|
||||||
|
|
||||||
|
//USING_NS_CC;
|
||||||
|
static EAGLView *view;
|
||||||
|
|
||||||
|
@implementation EAGLView
|
||||||
|
|
||||||
|
@synthesize eventDelegate = eventDelegate_, isFullScreen = isFullScreen_;
|
||||||
|
|
||||||
|
+(id) sharedEGLView
|
||||||
|
{
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithFrame:(NSRect)frameRect
|
||||||
|
{
|
||||||
|
self = [self initWithFrame:frameRect shareContext:nil];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithFrame:(NSRect)frameRect shareContext:(NSOpenGLContext*)context
|
||||||
|
{
|
||||||
|
NSOpenGLPixelFormatAttribute attribs[] =
|
||||||
|
{
|
||||||
|
// NSOpenGLPFAAccelerated,
|
||||||
|
// NSOpenGLPFANoRecovery,
|
||||||
|
NSOpenGLPFADoubleBuffer,
|
||||||
|
NSOpenGLPFADepthSize, 24,
|
||||||
|
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||||
|
|
||||||
|
if (!pixelFormat)
|
||||||
|
NSLog(@"No OpenGL pixel format");
|
||||||
|
|
||||||
|
if( (self = [super initWithFrame:frameRect pixelFormat:[pixelFormat autorelease]]) ) {
|
||||||
|
|
||||||
|
if( context )
|
||||||
|
[self setOpenGLContext:context];
|
||||||
|
|
||||||
|
// event delegate
|
||||||
|
eventDelegate_ = [CCEventDispatcher sharedDispatcher];
|
||||||
|
}
|
||||||
|
|
||||||
|
view = self;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) update
|
||||||
|
{
|
||||||
|
// XXX: Should I do something here ?
|
||||||
|
[super update];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) prepareOpenGL
|
||||||
|
{
|
||||||
|
// XXX: Initialize OpenGL context
|
||||||
|
|
||||||
|
[super prepareOpenGL];
|
||||||
|
|
||||||
|
// Make this openGL context current to the thread
|
||||||
|
// (i.e. all openGL on this thread calls will go to this context)
|
||||||
|
[[self openGLContext] makeCurrentContext];
|
||||||
|
|
||||||
|
// Synchronize buffer swaps with vertical refresh rate
|
||||||
|
GLint swapInt = 1;
|
||||||
|
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
||||||
|
|
||||||
|
// GLint order = -1;
|
||||||
|
// [[self openGLContext] setValues:&order forParameter:NSOpenGLCPSurfaceOrder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger) depthFormat
|
||||||
|
{
|
||||||
|
return 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) reshape
|
||||||
|
{
|
||||||
|
// We draw on a secondary thread through the display link
|
||||||
|
// When resizing the view, -reshape is called automatically on the main thread
|
||||||
|
// Add a mutex around to avoid the threads accessing the context simultaneously when resizing
|
||||||
|
|
||||||
|
[self lockOpenGLContext];
|
||||||
|
|
||||||
|
NSRect rect = [self bounds];
|
||||||
|
|
||||||
|
cocos2d::CCDirector *director = cocos2d::CCDirector::sharedDirector();
|
||||||
|
CGSize size = NSSizeToCGSize(rect.size);
|
||||||
|
cocos2d::CCSize ccsize = cocos2d::CCSizeMake(size.width, size.height);
|
||||||
|
director->reshapeProjection(ccsize);
|
||||||
|
|
||||||
|
// avoid flicker
|
||||||
|
director->drawScene();
|
||||||
|
// [self setNeedsDisplay:YES];
|
||||||
|
|
||||||
|
[self unlockOpenGLContext];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) lockOpenGLContext
|
||||||
|
{
|
||||||
|
NSOpenGLContext *glContext = [self openGLContext];
|
||||||
|
NSAssert( glContext, @"FATAL: could not get openGL context");
|
||||||
|
|
||||||
|
[glContext makeCurrentContext];
|
||||||
|
CGLLockContext((CGLContextObj)[glContext CGLContextObj]);
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) unlockOpenGLContext
|
||||||
|
{
|
||||||
|
NSOpenGLContext *glContext = [self openGLContext];
|
||||||
|
NSAssert( glContext, @"FATAL: could not get openGL context");
|
||||||
|
|
||||||
|
CGLUnlockContext((CGLContextObj)[glContext CGLContextObj]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
CCLOGINFO(@"cocos2d: deallocing %@", self);
|
||||||
|
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(int) getWidth
|
||||||
|
{
|
||||||
|
NSSize bound = [self bounds].size;
|
||||||
|
return bound.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(int) getHeight
|
||||||
|
{
|
||||||
|
NSSize bound = [self bounds].size;
|
||||||
|
return bound.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) swapBuffers
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// setFullScreen code taken from GLFullScreen example by Apple
|
||||||
|
//
|
||||||
|
- (void) setFullScreen:(BOOL)fullscreen
|
||||||
|
{
|
||||||
|
// Mac OS X 10.6 and later offer a simplified mechanism to create full-screen contexts
|
||||||
|
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5
|
||||||
|
|
||||||
|
if (isFullScreen_ == fullscreen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EAGLView *openGLview = [[self class] sharedEGLView];
|
||||||
|
|
||||||
|
if( fullscreen ) {
|
||||||
|
originalWinRect_ = [openGLview frame];
|
||||||
|
|
||||||
|
// Cache normal window and superview of openGLView
|
||||||
|
if(!windowGLView_)
|
||||||
|
windowGLView_ = [[openGLview window] retain];
|
||||||
|
|
||||||
|
[superViewGLView_ release];
|
||||||
|
superViewGLView_ = [[openGLview superview] retain];
|
||||||
|
|
||||||
|
|
||||||
|
// Get screen size
|
||||||
|
NSRect displayRect = [[NSScreen mainScreen] frame];
|
||||||
|
|
||||||
|
// Create a screen-sized window on the display you want to take over
|
||||||
|
fullScreenWindow_ = [[CCWindow alloc] initWithFrame:displayRect fullscreen:YES];
|
||||||
|
|
||||||
|
// Remove glView from window
|
||||||
|
[openGLview removeFromSuperview];
|
||||||
|
|
||||||
|
// Set new frame
|
||||||
|
[openGLview setFrame:displayRect];
|
||||||
|
|
||||||
|
// Attach glView to fullscreen window
|
||||||
|
[fullScreenWindow_ setContentView:openGLview];
|
||||||
|
|
||||||
|
// Show the fullscreen window
|
||||||
|
[fullScreenWindow_ makeKeyAndOrderFront:self];
|
||||||
|
[fullScreenWindow_ makeMainWindow];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Remove glView from fullscreen window
|
||||||
|
[openGLview removeFromSuperview];
|
||||||
|
|
||||||
|
// Release fullscreen window
|
||||||
|
[fullScreenWindow_ release];
|
||||||
|
fullScreenWindow_ = nil;
|
||||||
|
|
||||||
|
// Attach glView to superview
|
||||||
|
[superViewGLView_ addSubview:openGLview];
|
||||||
|
|
||||||
|
// Set new frame
|
||||||
|
[openGLview setFrame:originalWinRect_];
|
||||||
|
|
||||||
|
// Show the window
|
||||||
|
[windowGLView_ makeKeyAndOrderFront:self];
|
||||||
|
[windowGLView_ makeMainWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
// issue #1189
|
||||||
|
[windowGLView_ makeFirstResponder:openGLview];
|
||||||
|
|
||||||
|
isFullScreen_ = fullscreen;
|
||||||
|
|
||||||
|
[openGLview retain]; // Retain +1
|
||||||
|
|
||||||
|
// is this necessary?
|
||||||
|
// re-configure glView
|
||||||
|
//cocos2d::CCDirector *director = cocos2d::CCDirector::sharedDirector();
|
||||||
|
//director->setOpenGLView(openGLview); //[self setView:openGLview];
|
||||||
|
|
||||||
|
[openGLview release]; // Retain -1
|
||||||
|
|
||||||
|
[openGLview setNeedsDisplay:YES];
|
||||||
|
#else
|
||||||
|
#error Full screen is not supported for Mac OS 10.5 or older yet
|
||||||
|
#error If you don't want FullScreen support, you can safely remove these 2 lines
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
|
||||||
|
#define DISPATCH_EVENT(__event__, __selector__) [eventDelegate_ queueEvent:__event__ selector:__selector__];
|
||||||
|
#else
|
||||||
|
#define DISPATCH_EVENT(__event__, __selector__) \
|
||||||
|
id obj = eventDelegate_; \
|
||||||
|
[obj performSelector:__selector__ \
|
||||||
|
onThread:[(cocos2d::CCDirectorMac*)[CCDirector sharedDirector] runningThread] \
|
||||||
|
withObject:__event__ \
|
||||||
|
waitUntilDone:NO];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma mark EAGLView - Mouse events
|
||||||
|
|
||||||
|
- (void)mouseDown:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
NSPoint event_location = [theEvent locationInWindow];
|
||||||
|
NSPoint local_point = [self convertPoint:event_location fromView:nil];
|
||||||
|
|
||||||
|
float x = local_point.x;
|
||||||
|
float y = [self getHeight] - local_point.y;
|
||||||
|
|
||||||
|
int ids[1] = {0};
|
||||||
|
float xs[1] = {0.0f};
|
||||||
|
float ys[1] = {0.0f};
|
||||||
|
|
||||||
|
ids[0] = (int)theEvent;
|
||||||
|
xs[0] = x;
|
||||||
|
ys[0] = y;
|
||||||
|
|
||||||
|
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->handleTouchesBegin(1, ids, xs, ys);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseMoved:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDragged:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
NSPoint event_location = [theEvent locationInWindow];
|
||||||
|
NSPoint local_point = [self convertPoint:event_location fromView:nil];
|
||||||
|
|
||||||
|
float x = local_point.x;
|
||||||
|
float y = [self getHeight] - local_point.y;
|
||||||
|
|
||||||
|
int ids[1] = {0};
|
||||||
|
float xs[1] = {0.0f};
|
||||||
|
float ys[1] = {0.0f};
|
||||||
|
|
||||||
|
ids[0] = (int)theEvent;
|
||||||
|
xs[0] = x;
|
||||||
|
ys[0] = y;
|
||||||
|
|
||||||
|
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->handleTouchesMove(1, ids, xs, ys);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseUp:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
NSPoint event_location = [theEvent locationInWindow];
|
||||||
|
NSPoint local_point = [self convertPoint:event_location fromView:nil];
|
||||||
|
|
||||||
|
float x = local_point.x;
|
||||||
|
float y = [self getHeight] - local_point.y;
|
||||||
|
|
||||||
|
int ids[1] = {0};
|
||||||
|
float xs[1] = {0.0f};
|
||||||
|
float ys[1] = {0.0f};
|
||||||
|
|
||||||
|
ids[0] = (int)theEvent; // index?
|
||||||
|
xs[0] = x;
|
||||||
|
ys[0] = y;
|
||||||
|
|
||||||
|
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->handleTouchesEnd(1, ids, xs, ys);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)rightMouseDown:(NSEvent *)theEvent {
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)rightMouseDragged:(NSEvent *)theEvent {
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)rightMouseUp:(NSEvent *)theEvent {
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)otherMouseDown:(NSEvent *)theEvent {
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)otherMouseDragged:(NSEvent *)theEvent {
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)otherMouseUp:(NSEvent *)theEvent {
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseEntered:(NSEvent *)theEvent {
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseExited:(NSEvent *)theEvent {
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) scrollWheel:(NSEvent *)theEvent {
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark EAGLView - Key events
|
||||||
|
|
||||||
|
-(BOOL) becomeFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL) resignFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyDown:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyUp:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)flagsChanged:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark EAGLView - Touch events
|
||||||
|
- (void)touchesBeganWithEvent:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesMovedWithEvent:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesEndedWithEvent:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesCancelledWithEvent:(NSEvent *)theEvent
|
||||||
|
{
|
||||||
|
DISPATCH_EVENT(theEvent, _cmd);
|
||||||
|
}
|
||||||
|
@end
|
Loading…
Reference in New Issue