Adding Mac support!

This commit is contained in:
Nat Weiss 2012-07-20 21:23:40 -07:00
parent fe13388de4
commit d4b6d1262b
35 changed files with 8415 additions and 9 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -144,13 +144,20 @@ THE SOFTWARE.
#endif // CC_TARGET_PLATFROM == CC_PLATFORM_ANDROID
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
#include "platform/win32/CCAccelerometer.h"
#include "platform/win32/CCApplication.h"
#include "platform/win32/CCEGLView.h"
#include "platform/win32/CCGL.h"
#include "platform/win32/CCStdC.h"
#include "platform/win32/CCAccelerometer.h"
#include "platform/win32/CCApplication.h"
#include "platform/win32/CCEGLView.h"
#include "platform/win32/CCGL.h"
#include "platform/win32/CCStdC.h"
#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
#include "script_support/CCScriptSupport.h"

View File

@ -29,7 +29,7 @@ THE SOFTWARE.
#include "CCDirector.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 "CCSAXParser.h"
@ -455,4 +455,4 @@ bool CCFileUtils::isPopupNotify()
NS_CC_END
#endif // (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
#endif // (CC_TARGET_PLATFORM != CC_PLATFORM_IOS && CC_TARGET_PLATFORM != CC_PLATFORM_MAC)

View File

@ -36,7 +36,7 @@ THE SOFTWARE.
#include <string>
#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
@ -860,7 +860,7 @@ bool CCImage::_saveImageToJPG(const char * pszFilePath)
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,
so we cannot inclue it in this CCImage.cpp.
It makes a little difference on ios */

View File

@ -45,6 +45,7 @@ build for which target platform
#define CC_PLATFORM_LINUX 5
#define CC_PLATFORM_BADA 6
#define CC_PLATFORM_QNX 7
#define CC_PLATFORM_MAC 8
// Determine tartet platform by compile environment macro.
#define CC_TARGET_PLATFORM CC_PLATFORM_UNKNOWN
@ -92,6 +93,13 @@ build for which target platform
#define CC_TARGET_PLATFORM CC_PLATFORM_QNX
#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
//////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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__

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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__

View File

@ -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;

View File

@ -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__

View File

@ -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

View File

@ -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

View File

@ -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__

881
cocos2dx/platform/mac/CCImage.mm Executable file
View File

@ -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;

View File

@ -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__*/

View File

@ -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__

View File

@ -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__

View File

@ -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

111
cocos2dx/platform/mac/EAGLView.h Executable file
View File

@ -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__

429
cocos2dx/platform/mac/EAGLView.mm Executable file
View File

@ -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