CCMask and threads - cocos2d-iphone

I am using Gilles Lesire's CCMask class in my Kobold2d 2.0.3 (cocos2d-iphone v2.0 and OpenGL ES 2.0) game, but calling "createMaskForObject:withMask:" I get the following error:
-[CCRenderTexture initWithWidth:height:pixelFormat:depthStencilFormat:] : cocos2d: WARNING. CCRenderTexture is running on its own thread. Make sure that an OpenGL context is being used on this thread!
I don't really understand how to work with threads/opengl, but I was hoping someone would know how to fix this.

I see this as well for cocos2d 2.0. I don't think there is anything to fix. If you look at line 81 of CCRenderTexture.m you will see:
if( [director runningThread] != [NSThread currentThread] )
If that is false, the warning is given.
But, if you're creating textures before the game/app is running, the background thread for CVDisplayLink doesn't look like it has been created yet. [director runningThread] (the thread for the CVDisplayLink) returns nil. So that "if" statement will always be false.

Related

Change image on StaticBitmap wxWidgets

I would like to have a window, in which a picture changes depending on what is happening during an infinite loop.
Imagine someone walking around and when he leaves a given track, the program should display an arrow towards the direction of the track. Therefore I have a program, which determines the distance between user and track, but I have no idea on how to update the image.
I use code::blocks with wxWidgets and think I have to use the wxStaticBitmap class. (If there is a better way, please tell me.)
I tried with:
while(true)
{
updatePosition();
if(userNotOnTrack)
{
if(trackRightOfUser)
{
StaticDirectionBitmap->SetBitmap("D:\\WindowsDgps\\WindowsDgpsGraphic\\arrow_right.png");
}
}
}
(Note that this snippet is mostly pseudocode, except the StaticDirectionBitmap part.)
On default the Bitmap has a "no_arrow" image. With this I get an error: error: no matching function for call to 'wxStaticBitmap::SetBitmap(const char [51])'|. I see from the documentation that this cannot work, but I have no idea what could.
If anyone knows how to handle this, I would be happy to hear. I remember a few years back, when I tried something similar in C# and failed completely because of thread safety... I hope it is not this hard in C++ with wxWidgets.
SetBitmap takes a wxBitmap parameter not a string. So the call should look something like:
SetBitmap(wxBitmap( "D:\\WindowsDgps\\WindowsDgpsGraphic\\arrow_right.png", wxBITMAP_TYPE_PNG) );
Make sure prior to making this call that the png handler has been added with a call like one of the following:
wxImage::AddHandler(new wxPNGHandler);
or
::wxInitAllImageHandlers();
The easiest place to do this is in the applications OnInit() method.
If you want update the static bitmap from a worker thread, you should throw a wxThreadEvent and then make the call to SetBitmap in the event handler. The sample here shows how to generate and handle these events.

ObjectAL/OpenAL for iOS - stop/pause/mute sound at runtime?

Here is the ObjectAL/OpenAL iOS documentation:
http://kstenerud.github.io/ObjectAL-for-iPhone/documentation/index.html#use_objectal_sec
How in the world can you simply stop/pause/mute a particular sound (not all sounds) at runtime?
I've tried using OALSimpleAudio, OpenAL Objects and OALAudioTrack with no luck.
I'm using cocos2d v3.
You can follow the examples provided in: ObjectAL demos, for instance the SingleSourceDemo.
On of them is for the ALSource that #LearnCocos2D suggested in his comment. I will try to explain it here.
First, you should have the audio engine - let's say it is OALSimpleAudio. Moreover, let's assume you don't want to use it for playing effects - they will be managed by separate ALSources:
ALSource* effectSource;
ALBuffer* effectBuffer; //this is for the effect buffer
//don't reserve source for OALSimpleAudio
[OALSimpleAudio sharedInstance].reservedSources = 0;
//create the source for the effect.
source = [ALSource source];
//buffer the source file.
buffer = [[OpenALManager sharedInstance] bufferFromFile:#"audiofile.caf"];
Now you can use following methods to play/pause/pitch:
[source play:buffer loop:YES]; //play sound from buffer and loop
[source stop]; //stop
[source rewind]; //rewind sound to the beggining
[source fadeTo:0.0f duration:1.0f target:self selector:#selector(onFadeComplete:)]; //fade effect from source
[source pitchTo:0.0f duration:1.0f target:self selector:#selector(onFadeComplete:)]; //pitch effect from source
etc. Hope this will be helpful.

cocos2d Mac Shutdown and Startup at runtime

We are building a content editor that brings up a "cocos Player" in an NSWindow for test purposes. The user can test some content and then close the window.
So I need to be able to shutdown cocos and re-start within the same app.
Everything is working if I use the CC_MAC_USE_DISPLAY_LINK_THREAD threading model. I had to make a fix in CCDirectorMac to get this working. In CCDirectorMac | stopAnimation I had to set the _runningThread to nil since it is not set to nil by the #if and #elif when using CC_MAC_USE_DISPLAY_LINK_THREAD.
Anyway so now I am able to "end" a director and then re-start it later with no issues.
My question though is this: If I am building an AppKit editor with occasional use of cocos2D whould my threading model really be CC_MAC_USE_MAIN_THREAD as is suggested in the documentation?
When I do use CC_MAC_USE_MAIN_THREAD I get a HANG in in stopAnimation on the line:
CVDisplayLinkStop(displayLink);
I think the main thread would be fine and would avoid threading issues for our tool. Performance is not a concern. I can't find any sample code that shuts down and restarts cocos2d in an NSWindow ... so my assumption here is that I am in untested waters (or little tested waters).
My steps to shutdown/restart are:
Call [[CCDirector sharedDirector] end]
This calls stopAnimation
Then re-initialize cocos2d the same way I did originally
Any advice on threading models for a Mac desktop app ... and why CVDisplayLinkStop hangs would be greatly appreciated.
Thanks in advance.
Ok, I figured it out after reading this post and its answers on the Apple mailing list: http://lists.apple.com/archives/quartz-dev/2006/Oct/msg00056.html
When using CC_MAC_USE_MAIN_THREAD, the display link thread uses performSelector:onThread:waitUntilDone: to run drawScene: on the main thread. It passes YES for the waitUntilDone: parameter, so the display link thread blocks until the main thread can process the drawScene: call.
Here's the relevant fragment of the cocos2d code. MyDisplayLinkCallback is called on the display link thread.
static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{
CVReturn result = [(CCDirectorDisplayLink*)displayLinkContext getFrameForTime:outputTime];
return result;
}
- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime
{
#if (CC_DIRECTOR_MAC_THREAD == CC_MAC_USE_DISPLAY_LINK_THREAD)
...
#else
// Display link thread blocks here:
[self performSelector:#selector(drawScene) onThread:_runningThread withObject:nil waitUntilDone:YES];
#endif
return kCVReturnSuccess;
}
The problem appears when the main thread tries to run CVDisplayLinkStop() which blocks until the display link callback in the display link thread finishes. Since the callback is at the same time waiting for the main thread to process its drawScene: call, both threads become deadlocked.
- (void) stopAnimation
{
...
if( displayLink ) {
// Main thread blocks here:
CVDisplayLinkStop(displayLink);
...
}
So, now for my workaround. I added a line to run the main thread's runloop in order to force the drawScene: call to be executed, which unblocks the display link thread. That way, when you call CVDisplayLinkStop() you're safe. Here's my addition (CCDirectorMac.m line 473 in cocos2d 2.1 release):
- (void) stopAnimation
{
...
if( displayLink ) {
#if (CC_DIRECTOR_MAC_THREAD != CC_MAC_USE_DISPLAY_LINK_THREAD)
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
#endif
CVDisplayLinkStop(displayLink);
...
}
I'm not sure this is the right thing to do, there's probably a better way to deal with this, but this workaround is good enough for me at the moment.
Thanks for this post, it helped me figure out how to solve the same deadlock, in a non-cocos2d app, by processing the display link callback on a separate thread, never on the main thread.
static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime,
CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void *userInfo)
{
static dispatch_queue_t sDisplayQueue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sDisplayQueue = dispatch_queue_create("com.company.app.displayLink", NULL);
});
dispatch_sync(sDisplayQueue, ^{
<stuff>
});
return kCVReturnSuccess;
}

runAction do not works for sprites coming from CCSpriteBatchNode

I am using Cocos2d 2.1rc0.
I have this project that was working perfectly when I was not using CCSpriteBatchNode. Then I decided to use batch nodes to reduce draw calls and my problems started.
A lot of stuff is not working well. reorderChild is one. Another one is runAction and without runAction Cocos is useless.
This is an example of a method that works without batchNodes and do not work with it.
// move/rotate all objects
for (int i=0; i<[allObjects count]; i++) {
Card *object = [allObjects objectAtIndex:i];
[object stopAllActions];
CGPoint center = object.position;
center.x = center.x + 100;
center.y = center.y - 200;
CCMoveTo *moveAction = [CCMoveTo actionWithDuration:0.3f position:ccp(center.x, center.y)];
CCRotateTo *rotateAction = [CCRotateTo actionWithDuration:0.3 angle:0.0f];
CCSpawn *action = [CCSpawn actions:moveAction, rotateAction, nil];
[object runAction:[CCSequence actions: action,
[CCDelayTime actionWithDuration:0.1f],
nil]];
}
Exactly nothing happens.
I have tried to eliminate the CCSpanw and use runAction directly just with move and nothing works. If I use regular sprites, it works.
Objects in that array derive from a CCSprite based class.
Is there any workaround?
the solution is to cast the class to the object extracted from the array...
instead of
Card *object = [allObjects objectAtIndex:i];
this
Card *object = (Card *)[allObjects objectAtIndex:i];
After double-checking in a clean project that this isn't a weird side-effect of some kind, I have to say there's something fishy about your project. Hard to tell what, though.
What I did: create a sprite-batch, add a sprite to it, also store it in an array. In a scheduled method I'm receiving the sprite from the array (not casting) and run your action sequence posted above. It works fine, as expected.
The casting should not make any difference. Batched or non-batched sprite should not make any difference either.
If it does, something really weird is going on. After all the card object is the same with or without casting. If it were not actually running the runAction method, you'd be receiving an "unrecognized selector sent to instance" error. But that's not the case.
Try again without casting, after rebooting your device, your machine, cleaning the project in Xcode and rebuilding. Also test in debug and release configurations. I've had the weirdest issues that were gone after doing one of the above, and definitely all of the above. If that doesn't fix things, you can be sure it's a problem with the code (memory leak is my alltime favorite) or the project settings (ie uncommon compiler optimizations sometimes can have side-effects).
Step into the runAction method if it really doesn't run the action - I'm sure it will add the action to the action manager. Try with and without casting to see if there really is a different code path taken. I doubt it.

cocos2d-x CCTouchDispatcher - no sharedDispatcher

I'm currently porting an ObjC cocos2d game to cocos2d-x, but I'm encountering some problems when trying to create a registerWithTouchDispatcher method, at the moment I'm doing
void GameLayer::registerWithTouchDispatcher()
{
CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this,0,true);
}
but this gives an error 'No member named sharedDispatcher' in cocos2d::CCTouchDispatcher'.
Is there another way that this must be done in cocos2d-x?
If you are using 2.0, they have been merged in to CCDirector.
please use
CCDirector::sharedDirector()->getTouchDispatcher()
use those code instead ccdirector. put the code to cclayer init function.
setTouchMode(kCCTouchesOneByOne);
registerWithTouchDispatcher();
In the cocos2d-x you can do like this.
CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this,0);