PageRenderTime 92ms CodeModel.GetById 12ms app.highlight 74ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/cocos2d/CCNode.m

http://github.com/kstenerud/ObjectAL-for-iPhone
Objective C | 790 lines | 532 code | 171 blank | 87 comment | 94 complexity | 00619b2e559998abfbd0dbae37087c82 MD5 | raw file
  1/*
  2 * cocos2d for iPhone: http://www.cocos2d-iphone.org
  3 *
  4 * Copyright (c) 2008-2010 Ricardo Quesada
  5 * Copyright (c) 2009 Valentin Milea
  6 * 
  7 * Permission is hereby granted, free of charge, to any person obtaining a copy
  8 * of this software and associated documentation files (the "Software"), to deal
  9 * in the Software without restriction, including without limitation the rights
 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11 * copies of the Software, and to permit persons to whom the Software is
 12 * furnished to do so, subject to the following conditions:
 13 * 
 14 * The above copyright notice and this permission notice shall be included in
 15 * all copies or substantial portions of the Software.
 16 * 
 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23 * THE SOFTWARE.
 24 */
 25
 26
 27
 28#import "ccConfig.h"
 29#import "CCNode.h"
 30#import "CCCamera.h"
 31#import "CCGrid.h"
 32#import "CCScheduler.h"
 33#import "ccMacros.h"
 34#import "CCDirector.h"
 35#import "CCActionManager.h"
 36#import "Support/CGPointExtension.h"
 37#import "Support/ccCArray.h"
 38#import "Support/TransformUtils.h"
 39
 40
 41#if CC_COCOSNODE_RENDER_SUBPIXEL
 42#define RENDER_IN_SUBPIXEL
 43#else
 44#define RENDER_IN_SUBPIXEL (int)
 45#endif
 46
 47@interface CCNode (Private)
 48// lazy allocs
 49-(void) childrenAlloc;
 50// helper that reorder a child
 51-(void) insertChild:(CCNode*)child z:(int)z;
 52// used internally to alter the zOrder variable. DON'T call this method manually
 53-(void) _setZOrder:(int) z;
 54-(void) detachChild:(CCNode *)child cleanup:(BOOL)doCleanup;
 55@end
 56
 57@implementation CCNode
 58
 59@synthesize children = children_;
 60@synthesize visible=visible_;
 61@synthesize parent=parent_;
 62@synthesize grid=grid_;
 63@synthesize zOrder=zOrder_;
 64@synthesize tag=tag_;
 65@synthesize vertexZ = vertexZ_;
 66@synthesize isRunning=isRunning_;
 67
 68#pragma mark CCNode - Transform related properties
 69
 70@synthesize rotation=rotation_, scaleX=scaleX_, scaleY=scaleY_, position=position_;
 71@synthesize anchorPointInPixels=anchorPointInPixels_, isRelativeAnchorPoint=isRelativeAnchorPoint_;
 72@synthesize userData;
 73
 74// getters synthesized, setters explicit
 75-(void) setRotation: (float)newRotation
 76{
 77	rotation_ = newRotation;
 78	isTransformDirty_ = isInverseDirty_ = YES;
 79#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
 80	isTransformGLDirty_ = YES;
 81#endif
 82}
 83
 84-(void) setScaleX: (float)newScaleX
 85{
 86	scaleX_ = newScaleX;
 87	isTransformDirty_ = isInverseDirty_ = YES;
 88#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
 89	isTransformGLDirty_ = YES;
 90#endif	
 91}
 92
 93-(void) setScaleY: (float)newScaleY
 94{
 95	scaleY_ = newScaleY;
 96	isTransformDirty_ = isInverseDirty_ = YES;
 97#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
 98	isTransformGLDirty_ = YES;
 99#endif	
100}
101
102-(void) setPosition: (CGPoint)newPosition
103{
104	position_ = newPosition;
105	isTransformDirty_ = isInverseDirty_ = YES;
106#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
107	isTransformGLDirty_ = YES;
108#endif	
109}
110
111-(void) setIsRelativeAnchorPoint: (BOOL)newValue
112{
113	isRelativeAnchorPoint_ = newValue;
114	isTransformDirty_ = isInverseDirty_ = YES;
115#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
116	isTransformGLDirty_ = YES;
117#endif	
118}
119
120-(void) setAnchorPoint:(CGPoint)point
121{
122	if( ! CGPointEqualToPoint(point, anchorPoint_) ) {
123		anchorPoint_ = point;
124		anchorPointInPixels_ = ccp( contentSize_.width * anchorPoint_.x, contentSize_.height * anchorPoint_.y );
125		isTransformDirty_ = isInverseDirty_ = YES;
126#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
127		isTransformGLDirty_ = YES;
128#endif		
129	}
130}
131-(CGPoint) anchorPoint
132{
133	return anchorPoint_;
134}
135
136-(void) setContentSize:(CGSize)size
137{
138	if( ! CGSizeEqualToSize(size, contentSize_) ) {
139		contentSize_ = size;
140		anchorPointInPixels_ = ccp( contentSize_.width * anchorPoint_.x, contentSize_.height * anchorPoint_.y );
141		isTransformDirty_ = isInverseDirty_ = YES;
142#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
143		isTransformGLDirty_ = YES;
144#endif		
145	}
146}
147-(CGSize) contentSize
148{
149	return contentSize_;
150}
151
152- (CGRect) boundingBox
153{
154	CGRect rect = CGRectMake(0, 0, contentSize_.width, contentSize_.height);
155	return CGRectApplyAffineTransform(rect, [self nodeToParentTransform]);
156}
157
158-(float) scale
159{
160	NSAssert( scaleX_ == scaleY_, @"CCNode#scale. ScaleX != ScaleY. Don't know which one to return");
161	return scaleX_;
162}
163
164-(void) setScale:(float) s
165{
166	scaleX_ = scaleY_ = s;
167	isTransformDirty_ = isInverseDirty_ = YES;
168#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
169	isTransformGLDirty_ = YES;
170#endif	
171}
172
173#pragma mark CCNode - Init & cleanup
174
175+(id) node
176{
177	return [[[self alloc] init] autorelease];
178}
179
180-(id) init
181{
182	if ((self=[super init]) ) {
183		
184		isRunning_ = NO;
185		
186		rotation_ = 0.0f;
187		scaleX_ = scaleY_ = 1.0f;
188		position_ = CGPointZero;
189		anchorPointInPixels_ = anchorPoint_ = CGPointZero;
190		contentSize_ = CGSizeZero;
191		
192		
193		// "whole screen" objects. like Scenes and Layers, should set isRelativeAnchorPoint to NO
194		isRelativeAnchorPoint_ = YES; 
195		
196		isTransformDirty_ = isInverseDirty_ = YES;
197#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
198		isTransformGLDirty_ = YES;
199#endif
200		
201		vertexZ_ = 0;
202		
203		grid_ = nil;
204		
205		visible_ = YES;
206		
207		tag_ = kCCNodeTagInvalid;
208		
209		zOrder_ = 0;
210		
211		// lazy alloc
212		camera_ = nil;
213		
214		// children (lazy allocs)
215		children_ = nil;
216		
217		// userData is always inited as nil
218		userData = nil;
219	}
220	
221	return self;
222}
223
224- (void)cleanup
225{
226	// actions
227	[self stopAllActions];
228	[self unscheduleAllSelectors];
229	
230	// timers
231	
232	[children_ makeObjectsPerformSelector:@selector(cleanup)];
233}
234
235- (NSString*) description
236{
237	return [NSString stringWithFormat:@"<%@ = %08X | Tag = %i>", [self class], self, tag_];
238}
239
240- (void) dealloc
241{
242	CCLOGINFO( @"cocos2d: deallocing %@", self);
243	
244	// attributes
245	[camera_ release];
246	
247	[grid_ release];
248	
249	// children
250	
251	CCNode *child;
252	CCARRAY_FOREACH(children_, child)
253		child.parent = nil;
254	
255	[children_ release];
256	
257	[super dealloc];
258}
259
260#pragma mark CCNode Composition
261
262-(void) childrenAlloc
263{
264	children_ = [[CCArray alloc] initWithCapacity:4];
265}
266
267// camera: lazy alloc
268-(CCCamera*) camera
269{
270	if( ! camera_ ) {
271		camera_ = [[CCCamera alloc] init];
272		
273		// by default, center camera at the Sprite's anchor point
274		//		[camera_ setCenterX:anchorPointInPixels_.x centerY:anchorPointInPixels_.y centerZ:0];
275		//		[camera_ setEyeX:anchorPointInPixels_.x eyeY:anchorPointInPixels_.y eyeZ:1];
276		
277		//		[camera_ setCenterX:0 centerY:0 centerZ:0];
278		//		[camera_ setEyeX:0 eyeY:0 eyeZ:1];
279		
280	}
281	
282	return camera_;
283}
284
285-(CCNode*) getChildByTag:(int) aTag
286{
287	NSAssert( aTag != kCCNodeTagInvalid, @"Invalid tag");
288	
289	CCNode *node;
290	CCARRAY_FOREACH(children_, node){
291		if( node.tag == aTag )
292			return node;
293	}
294	// not found
295	return nil;
296}
297
298/* "add" logic MUST only be on this method
299 * If a class want's to extend the 'addChild' behaviour it only needs
300 * to override this method
301 */
302-(id) addChild: (CCNode*) child z:(int)z tag:(int) aTag
303{	
304	NSAssert( child != nil, @"Argument must be non-nil");
305	NSAssert( child.parent == nil, @"child already added. It can't be added again");
306	
307	if( ! children_ )
308		[self childrenAlloc];
309	
310	[self insertChild:child z:z];
311	
312	child.tag = aTag;
313	
314	[child setParent: self];
315	
316	if( isRunning_ )
317		[child onEnter];
318	return self;
319}
320
321-(id) addChild: (CCNode*) child z:(int)z
322{
323	NSAssert( child != nil, @"Argument must be non-nil");
324	return [self addChild:child z:z tag:child.tag];
325}
326
327-(id) addChild: (CCNode*) child
328{
329	NSAssert( child != nil, @"Argument must be non-nil");
330	return [self addChild:child z:child.zOrder tag:child.tag];
331}
332
333-(void) removeFromParentAndCleanup:(BOOL)cleanup
334{
335	[parent_ removeChild:self cleanup:cleanup];
336}
337
338/* "remove" logic MUST only be on this method
339 * If a class want's to extend the 'removeChild' behavior it only needs
340 * to override this method
341 */
342-(void) removeChild: (CCNode*)child cleanup:(BOOL)cleanup
343{
344	// explicit nil handling
345	if (child == nil)
346		return;
347	
348	if ( [children_ containsObject:child] )
349		[self detachChild:child cleanup:cleanup];
350}
351
352-(void) removeChildByTag:(int)aTag cleanup:(BOOL)cleanup
353{
354	NSAssert( aTag != kCCNodeTagInvalid, @"Invalid tag");
355	
356	CCNode *child = [self getChildByTag:aTag];
357	
358	if (child == nil)
359		CCLOG(@"cocos2d: removeChildByTag: child not found!");
360	else
361		[self removeChild:child cleanup:cleanup];
362}
363
364-(void) removeAllChildrenWithCleanup:(BOOL)cleanup
365{
366	// not using detachChild improves speed here
367	CCNode *c;
368	CCARRAY_FOREACH(children_, c)
369	{
370		// IMPORTANT:
371		//  -1st do onExit
372		//  -2nd cleanup
373		if (isRunning_)
374			[c onExit];
375		
376		if (cleanup)
377			[c cleanup];
378		
379		// set parent nil at the end (issue #476)
380		[c setParent:nil];
381	}
382	
383	[children_ removeAllObjects];
384}
385
386-(void) detachChild:(CCNode *)child cleanup:(BOOL)doCleanup
387{
388	// IMPORTANT:
389	//  -1st do onExit
390	//  -2nd cleanup
391	if (isRunning_)
392		[child onExit];
393	
394	// If you don't do cleanup, the child's actions will not get removed and the
395	// its scheduledSelectors_ dict will not get released!
396	if (doCleanup)
397		[child cleanup];
398	
399	// set parent nil at the end (issue #476)
400	[child setParent:nil];
401	
402	[children_ removeObject:child];
403}
404
405// used internally to alter the zOrder variable. DON'T call this method manually
406-(void) _setZOrder:(int) z
407{
408	zOrder_ = z;
409}
410
411// helper used by reorderChild & add
412-(void) insertChild:(CCNode*)child z:(int)z
413{
414	int index=0;
415	BOOL added = NO;
416	CCNode *a;
417	CCARRAY_FOREACH(children_, a){
418		if ( a.zOrder > z ) {
419			added = YES;
420			[ children_ insertObject:child atIndex:index];
421			break;
422		}
423		index++;
424	}
425	
426	if( ! added )
427		[children_ addObject:child];
428	
429	[child _setZOrder:z];
430}
431
432-(void) reorderChild:(CCNode*) child z:(int)z
433{
434	NSAssert( child != nil, @"Child must be non-nil");
435	
436	[child retain];
437	[children_ removeObject:child];
438	
439	[self insertChild:child z:z];
440	
441	[child release];
442}
443
444#pragma mark CCNode Draw
445
446-(void) draw
447{
448	// override me
449	// Only use this function to draw your staff.
450	// DON'T draw your stuff outside this method
451}
452
453-(void) visit
454{
455	// quick return if not visible
456	if (!visible_)
457		return;
458	
459	glPushMatrix();
460	
461	if ( grid_ && grid_.active) {
462		[grid_ beforeDraw];
463		[self transformAncestors];
464	}
465	
466	[self transform];
467	
468	if(children_) {
469		ccArray *arrayData = children_->data;
470		unsigned int i=0;
471		
472		// draw children zOrder < 0
473		for( ; i < arrayData->num; i++ ) {
474			CCNode *child =  arrayData->arr[i];
475			if ( [child zOrder] < 0 ) {
476				[child visit];
477			} else
478				break;
479		}
480		
481		// self draw
482		[self draw];
483		
484		// draw children zOrder >= 0
485		for( ; i < arrayData->num; i++ ) {
486			CCNode *child =  arrayData->arr[i];
487			[child visit];
488		}
489
490	} else
491		[self draw];	
492	
493	if ( grid_ && grid_.active)
494		[grid_ afterDraw:self];
495	
496	glPopMatrix();
497}
498
499#pragma mark CCNode - Transformations
500
501-(void) transformAncestors
502{
503	if( parent_ ) {
504		[parent_ transformAncestors];
505		[parent_ transform];
506	}
507}
508
509-(void) transform
510{	
511	// transformations
512	
513#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
514	// BEGIN alternative -- using cached transform
515	//
516	if( isTransformGLDirty_ ) {
517		CGAffineTransform t = [self nodeToParentTransform];
518		CGAffineToGL(&t, transformGL_);
519		isTransformGLDirty_ = NO;
520	}
521	
522	glMultMatrixf(transformGL_);
523	if( vertexZ_ )
524		glTranslatef(0, 0, vertexZ_);
525	
526	// XXX: Expensive calls. Camera should be integrated into the cached affine matrix
527	if ( camera_ && !(grid_ && grid_.active) ) {
528		BOOL translate = (anchorPointInPixels_.x != 0.0f || anchorPointInPixels_.y != 0.0f);
529		
530		if( translate )
531			glTranslatef(RENDER_IN_SUBPIXEL(anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(anchorPointInPixels_.y), 0);
532		
533		[camera_ locate];
534		
535		if( translate )
536			glTranslatef(RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0);
537	}
538	
539	
540	// END alternative
541	
542#else
543	// BEGIN original implementation
544	// 
545	// translate
546	if ( isRelativeAnchorPoint_ && (anchorPointInPixels_.x != 0 || anchorPointInPixels_.y != 0 ) )
547		glTranslatef( RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0);
548	
549	if (anchorPointInPixels_.x != 0 || anchorPointInPixels_.y != 0)
550		glTranslatef( RENDER_IN_SUBPIXEL(position_.x + anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(position_.y + anchorPointInPixels_.y), vertexZ_);
551	else if ( position_.x !=0 || position_.y !=0 || vertexZ_ != 0)
552		glTranslatef( RENDER_IN_SUBPIXEL(position_.x), RENDER_IN_SUBPIXEL(position_.y), vertexZ_ );
553	
554	// rotate
555	if (rotation_ != 0.0f )
556		glRotatef( -rotation_, 0.0f, 0.0f, 1.0f );
557	
558	// scale
559	if (scaleX_ != 1.0f || scaleY_ != 1.0f)
560		glScalef( scaleX_, scaleY_, 1.0f );
561	
562	if ( camera_ && !(grid_ && grid_.active) )
563		[camera_ locate];
564	
565	// restore and re-position point
566	if (anchorPointInPixels_.x != 0.0f || anchorPointInPixels_.y != 0.0f)
567		glTranslatef(RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0);
568	
569	//
570	// END original implementation
571#endif
572	
573}
574
575#pragma mark CCNode SceneManagement
576
577-(void) onEnter
578{
579	[children_ makeObjectsPerformSelector:@selector(onEnter)];
580	
581	[self resumeSchedulerAndActions];
582	
583	isRunning_ = YES;
584}
585
586-(void) onEnterTransitionDidFinish
587{
588	[children_ makeObjectsPerformSelector:@selector(onEnterTransitionDidFinish)];
589}
590
591-(void) onExit
592{
593	[self pauseSchedulerAndActions];
594	
595	isRunning_ = NO;	
596	
597	[children_ makeObjectsPerformSelector:@selector(onExit)];
598}
599
600#pragma mark CCNode Actions
601
602-(CCAction*) runAction:(CCAction*) action
603{
604	NSAssert( action != nil, @"Argument must be non-nil");
605	
606	[[CCActionManager sharedManager] addAction:action target:self paused:!isRunning_];
607	return action;
608}
609
610-(void) stopAllActions
611{
612	[[CCActionManager sharedManager] removeAllActionsFromTarget:self];
613}
614
615-(void) stopAction: (CCAction*) action
616{
617	[[CCActionManager sharedManager] removeAction:action];
618}
619
620-(void) stopActionByTag:(int)aTag
621{
622	NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag");
623	[[CCActionManager sharedManager] removeActionByTag:aTag target:self];
624}
625
626-(CCAction*) getActionByTag:(int) aTag
627{
628	NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag");
629	
630	return [[CCActionManager sharedManager] getActionByTag:aTag target:self];
631}
632
633-(int) numberOfRunningActions
634{
635	return [[CCActionManager sharedManager] numberOfRunningActionsInTarget:self];
636}
637
638
639#pragma mark CCNode - Callbacks
640
641-(void) scheduleUpdate
642{
643	[self scheduleUpdateWithPriority:0];
644}
645
646-(void) scheduleUpdateWithPriority:(int)priority
647{
648	[[CCScheduler sharedScheduler] scheduleUpdateForTarget:self priority:priority paused:!isRunning_];
649}
650
651-(void) unscheduleUpdate
652{
653	[[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self];
654}
655
656-(void) schedule:(SEL)selector
657{
658	[self schedule:selector interval:0];
659}
660
661-(void) schedule:(SEL)selector interval:(ccTime)interval
662{
663	NSAssert( selector != nil, @"Argument must be non-nil");
664	NSAssert( interval >=0, @"Arguemnt must be positive");
665	
666	[[CCScheduler sharedScheduler] scheduleSelector:selector forTarget:self interval:interval paused:!isRunning_];
667}
668
669-(void) unschedule:(SEL)selector
670{
671	// explicit nil handling
672	if (selector == nil)
673		return;
674	
675	[[CCScheduler sharedScheduler] unscheduleSelector:selector forTarget:self];
676}
677
678-(void) unscheduleAllSelectors
679{
680	[[CCScheduler sharedScheduler] unscheduleAllSelectorsForTarget:self];
681}
682- (void) resumeSchedulerAndActions
683{
684	[[CCScheduler sharedScheduler] resumeTarget:self];
685	[[CCActionManager sharedManager] resumeTarget:self];
686}
687
688- (void) pauseSchedulerAndActions
689{
690	[[CCScheduler sharedScheduler] pauseTarget:self];
691	[[CCActionManager sharedManager] pauseTarget:self];
692}
693
694#pragma mark CCNode Transform
695
696- (CGAffineTransform)nodeToParentTransform
697{
698	if ( isTransformDirty_ ) {
699		
700		transform_ = CGAffineTransformIdentity;
701		
702		if ( !isRelativeAnchorPoint_ && !CGPointEqualToPoint(anchorPointInPixels_, CGPointZero) )
703			transform_ = CGAffineTransformTranslate(transform_, anchorPointInPixels_.x, anchorPointInPixels_.y);
704		
705		if( ! CGPointEqualToPoint(position_, CGPointZero) )
706			transform_ = CGAffineTransformTranslate(transform_, position_.x, position_.y);
707		if( rotation_ != 0 )
708			transform_ = CGAffineTransformRotate(transform_, -CC_DEGREES_TO_RADIANS(rotation_));
709		if( ! (scaleX_ == 1 && scaleY_ == 1) ) 
710			transform_ = CGAffineTransformScale(transform_, scaleX_, scaleY_);
711		
712		if( ! CGPointEqualToPoint(anchorPointInPixels_, CGPointZero) )
713			transform_ = CGAffineTransformTranslate(transform_, -anchorPointInPixels_.x, -anchorPointInPixels_.y);
714		
715		isTransformDirty_ = NO;
716	}
717	
718	return transform_;
719}
720
721- (CGAffineTransform)parentToNodeTransform
722{
723	if ( isInverseDirty_ ) {
724		inverse_ = CGAffineTransformInvert([self nodeToParentTransform]);
725		isInverseDirty_ = NO;
726	}
727	
728	return inverse_;
729}
730
731- (CGAffineTransform)nodeToWorldTransform
732{
733	CGAffineTransform t = [self nodeToParentTransform];
734	
735	for (CCNode *p = parent_; p != nil; p = p.parent)
736		t = CGAffineTransformConcat(t, [p nodeToParentTransform]);
737	
738	return t;
739}
740
741- (CGAffineTransform)worldToNodeTransform
742{
743	return CGAffineTransformInvert([self nodeToWorldTransform]);
744}
745
746- (CGPoint)convertToNodeSpace:(CGPoint)worldPoint
747{
748	return CGPointApplyAffineTransform(worldPoint, [self worldToNodeTransform]);
749}
750
751- (CGPoint)convertToWorldSpace:(CGPoint)nodePoint
752{
753	return CGPointApplyAffineTransform(nodePoint, [self nodeToWorldTransform]);
754}
755
756- (CGPoint)convertToNodeSpaceAR:(CGPoint)worldPoint
757{
758	CGPoint nodePoint = [self convertToNodeSpace:worldPoint];
759	return ccpSub(nodePoint, anchorPointInPixels_);
760}
761
762- (CGPoint)convertToWorldSpaceAR:(CGPoint)nodePoint
763{
764	nodePoint = ccpAdd(nodePoint, anchorPointInPixels_);
765	return [self convertToWorldSpace:nodePoint];
766}
767
768- (CGPoint)convertToWindowSpace:(CGPoint)nodePoint
769{
770    CGPoint worldPoint = [self convertToWorldSpace:nodePoint];
771	return [[CCDirector sharedDirector] convertToUI:worldPoint];
772}
773
774// convenience methods which take a UITouch instead of CGPoint
775
776- (CGPoint)convertTouchToNodeSpace:(UITouch *)touch
777{
778	CGPoint point = [touch locationInView: [touch view]];
779	point = [[CCDirector sharedDirector] convertToGL: point];
780	return [self convertToNodeSpace:point];
781}
782
783- (CGPoint)convertTouchToNodeSpaceAR:(UITouch *)touch
784{
785	CGPoint point = [touch locationInView: [touch view]];
786	point = [[CCDirector sharedDirector] convertToGL: point];
787	return [self convertToNodeSpaceAR:point];
788}
789
790@end