// // TouchPanel.m // XNI // // Created by Matej Jan on 29.9.10. // Copyright 2010 Retronator. All rights reserved. // #import "TouchPanel.h" #import "TouchPanel+Internal.h" #import "Retronator.Xni.Framework.h" #import "Retronator.Xni.Framework.Input.Touch.h" #import "GameView.h" @interface XniTouchLocation : NSObject { @public int identifier; Vector2 *position; Vector2 *previousPosition; TouchLocationState state; int age; } - (id) initWithPosition:(Vector2*)thePosition; - (void) update; - (void) moveToPosition:(Vector2*)newPosition; - (TouchLocation*) createTouchLocation; @end @implementation XniTouchLocation static int nextID = 0; - (id) initWithPosition:(Vector2*)thePosition { self = [super init]; if (self != nil) { identifier = nextID++; position = [[Vector2 alloc] initWithVector2:thePosition]; previousPosition = nil; state = TouchLocationStatePressed; } return self; } - (void) update { [self moveToPosition:position]; age++; } - (void) moveToPosition:(Vector2*)newPosition { if (!previousPosition) { previousPosition = [[Vector2 alloc] init]; } [previousPosition set:position]; [position set:newPosition]; state = TouchLocationStateMoved; } - (TouchLocation *) createTouchLocation { return [[[TouchLocation alloc] initWithIdentifier:identifier position:[Vector2 vectorWithVector:position] previousPosition:previousPosition ? [Vector2 vectorWithVector:previousPosition] : nil state:state] autorelease]; } - (void) dealloc { [position release]; [previousPosition release]; [super dealloc]; } @end @implementation TouchPanel static TouchPanel *instance; - (id) init { self = [super init]; if (self != nil) { addTouches = [[NSMutableSet alloc] init]; removeTouches = [[NSMutableSet alloc] init]; releaseTouches = [[NSMutableSet alloc] init]; lateReleaseTouches = [[NSMutableSet alloc] init]; touchLocations = (NSMutableDictionary*)CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); uiTouchesForLocations = (NSMutableDictionary*)CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } return self; } + (void) initialize { instance = [[TouchPanel alloc] init]; } @synthesize displayWidth; @synthesize displayHeight; @synthesize displayOrientation; @synthesize enabledGestures; + (TouchCollection*) getState { return [instance getState]; } + (GestureSample*) readGesture { return [instance readGesture]; } + (TouchPanel*) getInstance { return instance; } - (void) setView:(GameView *)theView { view = theView; } - (BOOL) isGestureAvailable{ return NO; } - (TouchCollection*) getState{ TouchCollection *collection = [[[TouchCollection alloc] init] autorelease]; for (XniTouchLocation *touch in [touchLocations allValues]) { [collection addObject:[touch createTouchLocation]]; // After get state is done, all pressed touches should be moved. [touch update]; if (touch->age > 200) { UITouch *key = [uiTouchesForLocations objectForKey:touch]; [removeTouches addObject:key]; } } return collection; } - (GestureSample*) readGesture{ return nil; } // Internal methods - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [addTouches unionSet:touches]; } - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { float scale = view.scale; for (UITouch *touch in touches) { XniTouchLocation *location = [touchLocations objectForKey:touch]; if (location) { location->age = 0; CGPoint position = [touch locationInView:view]; [location moveToPosition:[Vector2 vectorWithX:position.x * scale y:position.y * scale]]; } } } - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { if ([addTouches containsObject:touch]) { [lateReleaseTouches addObject:touch]; } else { [releaseTouches addObject:touch]; } } } - (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { // Just remove the touch locations so they dissapear from the state (without released happening). for (UITouch *touch in touches) { [touchLocations removeObjectForKey:touch]; } } - (void) update { // Remove all previously released touches. for (UITouch *touch in removeTouches) { XniTouchLocation *location = [[touchLocations objectForKey:touch] retain]; [touchLocations removeObjectForKey:touch]; if (location) { [uiTouchesForLocations removeObjectForKey:location]; [location release]; } } [removeTouches removeAllObjects]; // Set released touches. for (UITouch *touch in releaseTouches) { XniTouchLocation *location = [touchLocations objectForKey:touch]; if (location) { location->state = TouchLocationStateReleased; } } // Shift the pools. NSMutableSet *temp = removeTouches; removeTouches = releaseTouches; releaseTouches = lateReleaseTouches; lateReleaseTouches = temp; // Add new touches float scale = view.scale; for (UITouch *touch in addTouches) { CGPoint position = [touch locationInView:view]; XniTouchLocation *location = [[[XniTouchLocation alloc] initWithPosition:[Vector2 vectorWithX:position.x * scale y:position.y * scale]] autorelease]; CFDictionaryAddValue((CFMutableDictionaryRef)touchLocations, touch, location); CFDictionaryAddValue((CFMutableDictionaryRef)uiTouchesForLocations, location, touch); } [addTouches removeAllObjects]; } - (void) dealloc { [addTouches release]; [removeTouches release]; [releaseTouches release]; [lateReleaseTouches release]; [touchLocations release]; [uiTouchesForLocations release]; [super dealloc]; } @end