RSS

(root)/iphone/common : 60 : tappity/source/TappityServer.m

To get this branch, use:
bzr branch /browse/iphone/common

« back to all changes in this revision

Viewing changes to tappity/source/TappityServer.m

Dömötör Gulyás
2010-01-18 09:02:59
Revision ID: dognotdog@gmail.com-20100118080259-1633mzyepdhdacy0
made tappity a nested tree

Show diffs side-by-side

added added

removed removed

1
 
//
2
 
//  TappityServer.m
3
 
//  Jigs
4
 
//
5
 
//  Created by döme on 25.10.2009.
6
 
//
7
 
 
8
 
/*
9
 
 * Copyright (c) 2009 Doemoetoer Gulyas.
10
 
 * All rights reserved.
11
 
 *
12
 
 * Redistribution and use in source and binary forms, with or without
13
 
 * modification, are permitted provided that the following conditions
14
 
 * are met:
15
 
 * 1. Redistributions of source code must retain the above copyright
16
 
 *    notice, this list of conditions and the following disclaimer.
17
 
 * 2. Redistributions in binary form must reproduce the above copyright
18
 
 *    notice, this list of conditions and the following disclaimer in the
19
 
 *    documentation and/or other materials provided with the distribution.
20
 
 * 3. The name of the author may not be used to endorse or promote products
21
 
 *    derived from this software without specific prior written permission.
22
 
 *
23
 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24
 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25
 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26
 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27
 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28
 
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29
 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30
 
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31
 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32
 
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
 
 */
34
 
 
35
 
 
36
 
#import "TappityServer.h"
37
 
#import "Tappity.h"
38
 
#import <QuartzCore/QuartzCore.h>
39
 
#import <OpenGLES/ES1/gl.h>
40
 
#import <OpenGLES/EAGL.h>
41
 
#import <CoreLocation/CoreLocation.h>
42
 
#import <objc/runtime.h>
43
 
 
44
 
 
45
 
@interface CLLocationManager (TappityServer)
46
 
 
47
 
- (void) setDelegate_tappity: (id) delegate;
48
 
- (void) startUpdatingLocation_tappity;
49
 
- (void) stopUpdatingLocation_tappity;
50
 
- (void) startUpdatingHeading_tappity;
51
 
- (void) stopUpdatingHeading_tappity;
52
 
 
53
 
@end
54
 
 
55
 
@interface UIAccelerometer (TappityServer)
56
 
 
57
 
- (void) setUpdateInterval_tappity: (NSTimeInterval) dt;
58
 
 
59
 
@end
60
 
 
61
 
@interface EAGLContext (TappityServer)
62
 
 
63
 
- (BOOL)presentRenderbuffer_tappity:(NSUInteger)target;
64
 
 
65
 
 
66
 
@end
67
 
 
68
 
 
69
 
@implementation CLLocationManager (TappityServer)
70
 
 
71
 
- (void) setDelegate_tappity: (id) obj
72
 
{
73
 
        if ([obj respondsToSelector: @selector(locationManager:didUpdateToLocation:fromLocation:)])
74
 
        {
75
 
                [[TappityServer sharedServer] setLocationDelegate: obj];
76
 
        }
77
 
        if ([obj respondsToSelector: @selector(locationManager:didUpdateHeading:)])
78
 
        {
79
 
                [[TappityServer sharedServer] setHeadingDelegate: obj];
80
 
        }
81
 
        [self setDelegate_tappity: obj];
82
 
 
83
 
}
84
 
 
85
 
- (void) startUpdatingLocation_tappity
86
 
{
87
 
        [[TappityServer sharedServer] sendData: [NSData data] withIdentifier: kTapStartUpdatingLocation];
88
 
        [self startUpdatingLocation_tappity];
89
 
}
90
 
 
91
 
- (void) stopUpdatingLocation_tappity
92
 
{
93
 
        [[TappityServer sharedServer] sendData: [NSData data] withIdentifier: kTapStopUpdatingLocation];
94
 
        [self stopUpdatingLocation_tappity];
95
 
}
96
 
 
97
 
- (void) startUpdatingHeading_tappity
98
 
{
99
 
        [[TappityServer sharedServer] sendData: [NSData data] withIdentifier: kTapStartUpdatingHeading];
100
 
        [self startUpdatingHeading_tappity];
101
 
}
102
 
 
103
 
- (void) stopUpdatingHeading_tappity
104
 
{
105
 
        [[TappityServer sharedServer] sendData: [NSData data] withIdentifier: kTapStopUpdatingHeading];
106
 
        [self stopUpdatingHeading_tappity];
107
 
}
108
 
 
109
 
 
110
 
@end
111
 
 
112
 
@implementation UIAccelerometer (TappityServer)
113
 
 
114
 
- (void) setUpdateInterval_tappity: (NSTimeInterval) dt
115
 
{
116
 
        [[TappityServer sharedServer] setAccelerometerUpdateInterval: dt];
117
 
        
118
 
        [self setUpdateInterval_tappity: dt];
119
 
}
120
 
 
121
 
@end
122
 
 
123
 
@implementation EAGLContext (TappityServer)
124
 
 
125
 
- (BOOL)presentRenderbuffer_tappity:(NSUInteger)target
126
 
{
127
 
        [TappityServer glGrabPoint];
128
 
        return [self presentRenderbuffer_tappity: target];
129
 
}
130
 
 
131
 
 
132
 
@end
133
 
 
134
 
static void swapMethods(Class c, SEL sela, SEL selb)
135
 
{
136
 
        Method ma = class_getInstanceMethod(c, sela);
137
 
        Method mb = class_getInstanceMethod(c, selb);
138
 
        method_exchangeImplementations(ma, mb);
139
 
        
140
 
}
141
 
 
142
 
static void catch_pipe(int sig_num)
143
 
{
144
 
    signal(SIGPIPE, catch_pipe);
145
 
}
146
 
 
147
 
__attribute__((constructor)) void initTappityServer(void)
148
 
{
149
 
//      __builtin_printf("MOOOOOOOOOOOOOOO\n");
150
 
        /* TODO:
151
 
                1. intercept UIAccelerometer
152
 
                2. intercept CLLocationManager
153
 
                class_getInstanceMethod(), method_setImplementation()
154
 
        */
155
 
 
156
 
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
157
 
        
158
 
        NSString* name = [[NSBundle mainBundle] bundleIdentifier];
159
 
        
160
 
        [[TappityServer sharedServer] startBonjourServerWithName: name protocol: @"_tappity._tcp" port: 1234];
161
 
        
162
 
        Class lmc = NSClassFromString(@"CLLocationManager");
163
 
        if (lmc)
164
 
        {
165
 
                swapMethods(lmc, @selector(setDelegate:), @selector(setDelegate_tappity:));
166
 
                swapMethods(lmc, @selector(startUpdatingHeading:), @selector(startUpdatingHeading_tappity:));
167
 
                swapMethods(lmc, @selector(startUpdatingLocation:), @selector(startUpdatingLocation_tappity:));
168
 
        }
169
 
 
170
 
        Class accc = [UIAccelerometer class];
171
 
        swapMethods(accc, @selector(setUpdateInterval:), @selector(setUpdateInterval_tappity:));
172
 
 
173
 
        Class glc = NSClassFromString(@"EAGLContext");
174
 
        if (glc)
175
 
                swapMethods(glc, @selector(presentRenderbuffer:), @selector(presentRenderbuffer_tappity:));
176
 
 
177
 
        
178
 
        [pool drain];
179
 
        
180
 
        signal(SIGPIPE, catch_pipe);
181
 
 
182
 
}
183
 
 
184
 
 
185
 
 
186
 
 
187
 
@implementation TappityServer
188
 
 
189
 
+ (void) initialize
190
 
{
191
 
        
192
 
}
193
 
 
194
 
- (id) init
195
 
{
196
 
        if (!(self = [super init]))
197
 
                return nil;
198
 
 
199
 
        desiredFrameInterval = 0.333;
200
 
        
201
 
        messenger = [[SocketMessenger alloc] init];
202
 
        [messenger setReceiveDataOnMainThread: YES];
203
 
        [messenger setDelegate: self];
204
 
        
205
 
        return self;
206
 
}
207
 
 
208
 
- (void) sendData: (NSData*) data withIdentifier: (NSInteger) messageId
209
 
{
210
 
        [messenger sendData: data withIdentifier: messageId];
211
 
}
212
 
 
213
 
- (void) startBonjourServerWithName: (NSString*) name protocol: (NSString*) protocol port: (int) port
214
 
{
215
 
        [messenger startBonjourServerWithName: name protocol: protocol port: port];
216
 
}
217
 
 
218
 
- (void) connectionWasEstablished: (SocketMessenger*) theMessenger
219
 
{
220
 
        if (locationDelegate)
221
 
                [messenger sendData: [NSData data] withIdentifier: kTapStartUpdatingLocation];
222
 
        if (headingDelegate)
223
 
                [messenger sendData: [NSData data] withIdentifier: kTapStartUpdatingHeading];
224
 
 
225
 
        [self performSelectorOnMainThread: @selector(startScreenieTimer) withObject: nil waitUntilDone: NO];
226
 
}
227
 
 
228
 
- (void) startScreenieTimer
229
 
{
230
 
        [captureTimer invalidate];
231
 
        captureTimer = [NSTimer scheduledTimerWithTimeInterval: desiredFrameInterval target: self selector: @selector(captureScreen) userInfo: nil repeats: YES];
232
 
        
233
 
        
234
 
        if (!capturedImagesCondition)
235
 
                capturedImagesCondition = [[NSCondition alloc] init];
236
 
 
237
 
        [messenger runThreadWithTarget: self selector: @selector(imageConversionThread:)];
238
 
}
239
 
 
240
 
/*
241
 
static size_t _read_i8(const void* buf, uint8_t* p)
242
 
{
243
 
        uint8_t v = 0;
244
 
        memcpy(&v, buf, 1);
245
 
        *p = v;
246
 
        return 1;
247
 
}
248
 
static size_t _read_i16(const void* buf, uint16_t* p)
249
 
{
250
 
        uint16_t v = 0;
251
 
        memcpy(&v, buf, 2);
252
 
        *p = CFSwapInt16BigToHost(v);
253
 
        return 2;
254
 
}
255
 
static size_t _read_i32(const void* buf, uint32_t* p)
256
 
{
257
 
        uint32_t v = 0;
258
 
        memcpy(&v, buf, 4);
259
 
        *p = CFSwapInt32BigToHost(v);
260
 
        return 4;
261
 
}
262
 
static size_t _read_i64(const void* buf, uint64_t* p)
263
 
{
264
 
        uint64_t v = 0;
265
 
        memcpy(&v, buf, 8);
266
 
        *p = CFSwapInt64BigToHost(v);
267
 
        return 8;
268
 
}
269
 
static size_t _read_float(const void* buf, float* p)
270
 
{
271
 
        CFSwappedFloat32 v;
272
 
        memcpy(&v, buf, 4);
273
 
        *p = CFConvertFloat32SwappedToHost(v);
274
 
        return 4;
275
 
}
276
 
 
277
 
static size_t _read_gspoint(const void* buf, GSTouchPointRef p)
278
 
{
279
 
        size_t bc = 0;
280
 
 
281
 
        bc += _read_i32(buf+bc, &p->unk0);
282
 
        bc += _read_float(buf+bc, &p->unk1);
283
 
        bc += _read_float(buf+bc, &p->touchSize);
284
 
        bc += _read_float(buf+bc, &p->x);
285
 
        bc += _read_float(buf+bc, &p->y);
286
 
        bc += _read_i32(buf+bc, (uint32_t*)&p->window);
287
 
        
288
 
        return bc;
289
 
}
290
 
 
291
 
- (GSEvent*) gsEventWithData: (NSData*) data
292
 
{
293
 
        GSEvent* gse = [[[GSEvent alloc] init] autorelease];
294
 
        
295
 
        size_t bc = 0;
296
 
        const void* buf = [data bytes];
297
 
        
298
 
        bc += _read_i32(buf+bc, &gse->type0);
299
 
        bc += _read_i32(buf+bc, &gse->type1);
300
 
        bc += _read_i32(buf+bc, &gse->r3);
301
 
        bc += _read_float(buf+bc, &gse->avgX0);
302
 
        bc += _read_float(buf+bc, &gse->avgY0);
303
 
        bc += _read_float(buf+bc, &gse->avgX1);
304
 
        bc += _read_float(buf+bc, &gse->avgY1);
305
 
        bc += _read_i32(buf+bc, &gse->processId);
306
 
        bc += _read_i64(buf+bc, &gse->timestamp);
307
 
        bc += _read_i32(buf+bc, (uint32_t*)&gse->window);
308
 
        bc += _read_i32(buf+bc, &gse->r11);
309
 
        bc += _read_i32(buf+bc, &gse->type12);
310
 
        bc += _read_i32(buf+bc, &gse->gesture13);
311
 
        bc += _read_i32(buf+bc, &gse->gesture14);
312
 
        bc += _read_i16(buf+bc, &gse->numInitialTouches);
313
 
        bc += _read_i16(buf+bc, &gse->numCurrentTouches);
314
 
        bc += _read_i32(buf+bc, &gse->r16);
315
 
        bc += _read_i32(buf+bc, &gse->r17);
316
 
        bc += _read_i32(buf+bc, &gse->r18);
317
 
        bc += _read_i32(buf+bc, &gse->r19);
318
 
        bc += _read_i32(buf+bc, &gse->r20);
319
 
        bc += _read_i32(buf+bc, &gse->r21);
320
 
        bc += _read_i8(buf+bc, &gse->r22_0);
321
 
        bc += _read_i8(buf+bc, &gse->numPoints);
322
 
        bc += _read_i16(buf+bc, &gse->r22_2);
323
 
        for (size_t i = 0; i < gse->numPoints; ++i)
324
 
                bc += _read_gspoint(buf+bc, gse->points + i);
325
 
 
326
 
        return gse;
327
 
}
328
 
*/
329
 
 
330
 
- (void) doEventPlayback
331
 
{
332
 
        [[UIApplication sharedApplication] _playbackEvents: queuedEvents atPlaybackRate: 1.0f messageWhenDone: self withSelector: @selector(eventPlaybackDone:)];
333
 
        
334
 
        [queuedEvents autorelease];
335
 
        queuedEvents = nil;
336
 
        eventPlaybackBusy = YES;
337
 
}
338
 
- (void) eventPlaybackDone:(NSDictionary*)detail
339
 
{
340
 
        if ([queuedEvents count])
341
 
        {
342
 
                [self doEventPlayback];
343
 
        }
344
 
        else
345
 
                eventPlaybackBusy = NO;
346
 
}
347
 
 
348
 
- (void) dataReceived: (NSDictionary*) dataDict
349
 
{
350
 
        uint32_t messageId = [[dataDict objectForKey: SocketMessageIdKey] intValue];
351
 
        
352
 
//      NSLog(@"received messageid %d", messageId);
353
 
 
354
 
        NSData* tapData = [dataDict objectForKey: SocketMessageDataKey];
355
 
        
356
 
//      NSDictionary* tapDict = [NSPropertyListSerialization propertyListFromData: tapData mutabilityOption:NSPropertyListImmutable format: NULL errorDescription: NULL];
357
 
        assert(tapData);
358
 
        switch(messageId)
359
 
        {
360
 
/*
361
 
                case kTapTouchEvent:
362
 
                {
363
 
                        NSLog(@"TOUCH EVENT");
364
 
                        
365
 
                        GSEvent* gse = [self gsEventWithData: [tapDict objectForKey: TapGSEventKey]];
366
 
                        UIWindow* window = [[UIApplication sharedApplication] keyWindow];
367
 
                        gse->window = window;
368
 
                        for (size_t i = 0; i < gse->numPoints; ++i)
369
 
                                gse->points[i].window = window;
370
 
                        
371
 
                        int phase = [[tapDict objectForKey: TapTouchPhaseKey] intValue];
372
 
                        NSSet* touches = [UITouch _createTouchesWithGSEvent: gse phase: phase view: [[UIApplication sharedApplication] keyWindow]];
373
 
                        
374
 
                        assert([[UIApplication sharedApplication] keyWindow]);
375
 
                        
376
 
                        NSLog(@"%@", touches);
377
 
 
378
 
                        UIEvent* event = [UIEvent alloc];
379
 
                        
380
 
                        Class touchesEventClass = objc_getClass("UITouchesEvent");
381
 
                        if (touchesEventClass && ![[event class] isEqual: touchesEventClass])
382
 
                        {
383
 
                                event = [touchesEventClass alloc];
384
 
                        }
385
 
                        
386
 
                        [event _initWithEvent: gse touches: touches];
387
 
                        
388
 
                        assert(event);
389
 
                        
390
 
                        [[UIApplication sharedApplication] sendEvent: event];
391
 
                                                
392
 
                        
393
 
                        break;
394
 
                }
395
 
*/
396
 
                case kTapRecordedEvent:
397
 
                {                       
398
 
                        NSDictionary* eventDict = [NSPropertyListSerialization propertyListFromData: tapData mutabilityOption:NSPropertyListImmutable format: NULL errorDescription: NULL];
399
 
                        
400
 
                        if (!queuedEvents)
401
 
                                queuedEvents = [[NSMutableArray alloc] init];
402
 
 
403
 
                        [queuedEvents addObject: eventDict];
404
 
                        
405
 
                        if (!eventPlaybackBusy)
406
 
                        {
407
 
                                [self doEventPlayback];
408
 
                        }
409
 
                        break;
410
 
                }
411
 
                case kTapAcceleration:
412
 
                {                       
413
 
                        NSArray* accel = [NSPropertyListSerialization propertyListFromData: tapData mutabilityOption:NSPropertyListImmutable format: NULL errorDescription: NULL];
414
 
                        
415
 
                        UIAccelerometer* accm = [UIAccelerometer sharedAccelerometer];
416
 
                        float x = [[accel objectAtIndex: 0] floatValue];
417
 
                        float y = [[accel objectAtIndex: 1] floatValue];
418
 
                        float z = [[accel objectAtIndex: 2] floatValue];
419
 
                        [accm _acceleratedInX: x y: y z: z timestamp: [[accel objectAtIndex: 3] doubleValue]];
420
 
                        
421
 
                        break;
422
 
                }
423
 
                case kTapLocation:
424
 
                {
425
 
                        static CLLocation* oldLoc = nil;
426
 
                        CLLocation* loc = [NSKeyedUnarchiver unarchiveObjectWithData: tapData];
427
 
                        if ([locationDelegate respondsToSelector: @selector(locationManager:didUpdateToLocation:fromLocation:)])
428
 
                        {
429
 
                                [locationDelegate locationManager: (id)self didUpdateToLocation: loc fromLocation: oldLoc];
430
 
                        }
431
 
                        oldLoc = loc;
432
 
                        break;
433
 
                }
434
 
                case kTapCompass:
435
 
                {
436
 
                        CLHeading* hdg = [NSKeyedUnarchiver unarchiveObjectWithData: tapData];
437
 
                        if ([headingDelegate respondsToSelector: @selector(locationManager:didUpdateHeading:)])
438
 
                        {
439
 
                                [headingDelegate locationManager: (id)self didUpdateHeading: hdg];
440
 
                        }
441
 
                        break;
442
 
                }
443
 
                case kTapStartSendingVisualFeedback:
444
 
                {
445
 
                        NSLog(@"enabling visual uplink");
446
 
                        enableVisualFeedback = YES;
447
 
                        break;
448
 
                }
449
 
        }
450
 
        
451
 
        [tapData release];
452
 
        
453
 
}
454
 
 
455
 
- (UIImage *) imageFromView: (UIView *) theView
456
 
{
457
 
        UIGraphicsBeginImageContext(theView.frame.size);
458
 
        CGContextRef context = UIGraphicsGetCurrentContext();
459
 
//      [theView.layer drawInContext:context];
460
 
        [theView.layer renderInContext:context];
461
 
        UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
462
 
        UIGraphicsEndImageContext();
463
 
        return theImage;
464
 
}
465
 
 
466
 
- (void) convertAndSendImage: (UIImage*) img
467
 
{               
468
 
        [capturedImagesCondition lock];
469
 
 
470
 
        if (!capturedImagesQueue)
471
 
                capturedImagesQueue = [[NSMutableArray alloc] init];
472
 
 
473
 
        [capturedImagesQueue addObject: img];
474
 
        
475
 
        [capturedImagesCondition signal];
476
 
        [capturedImagesCondition unlock];
477
 
                
478
 
}
479
 
 
480
 
- (void) captureScreen
481
 
{
482
 
        NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
483
 
        
484
 
        if ((now < lastGlUpdate + 2.0*desiredFrameInterval))
485
 
                return;
486
 
                
487
 
        // return if any gl has been updated at all
488
 
        if (lastGlUpdate || !enableVisualFeedback)
489
 
                return;
490
 
        
491
 
        [self performSelectorOnMainThread: @selector(getWindowToCapture) withObject: nil waitUntilDone: NO];
492
 
 
493
 
        UIWindow* window = windowToCapture;
494
 
        
495
 
        UIImage* img = [self imageFromView: window];
496
 
        
497
 
        lastQuartzUpdate = now;
498
 
        
499
 
        if (img)
500
 
                [self convertAndSendImage: img];
501
 
}
502
 
 
503
 
- (void) imageConversionThread: (id) info
504
 
{
505
 
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
506
 
 
507
 
        @synchronized(self)
508
 
        {
509
 
                [self retain];
510
 
        }
511
 
 
512
 
        while ([messenger threadActive: info])
513
 
        {
514
 
                NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
515
 
 
516
 
                [capturedImagesCondition lock];
517
 
                        while (![capturedImagesQueue count])
518
 
                                [capturedImagesCondition wait];
519
 
                                
520
 
                //NSLog(@"sending");
521
 
                
522
 
                UIImage* img = [[[capturedImagesQueue objectAtIndex: 0] retain] autorelease];
523
 
                [capturedImagesQueue removeObjectAtIndex: 0];
524
 
                
525
 
                [capturedImagesCondition unlock];
526
 
 
527
 
                NSData* imgData = UIImagePNGRepresentation(img);
528
 
        
529
 
                if (imgData)
530
 
                        [messenger sendData: imgData withIdentifier: kTapRawScreenshot];
531
 
 
532
 
                
533
 
                [pool drain];
534
 
 
535
 
        }
536
 
        
537
 
 
538
 
        [messenger threadWillExit: info];
539
 
 
540
 
        @synchronized(self)
541
 
        {
542
 
                [self release];
543
 
        }
544
 
 
545
 
        [info release];
546
 
        [pool drain];
547
 
}
548
 
 
549
 
 
550
 
 
551
 
 
552
 
- (void) getWindowToCapture
553
 
{
554
 
        @synchronized(self)
555
 
        {
556
 
                [windowToCapture release];
557
 
                windowToCapture = [[[UIApplication sharedApplication] keyWindow] retain];
558
 
        }
559
 
}
560
 
- (void) screenieThread: (id) info
561
 
{
562
 
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
563
 
 
564
 
        @synchronized(self)
565
 
        {
566
 
                [self retain];
567
 
        }
568
 
 
569
 
 
570
 
        while ([messenger threadActive: info])
571
 
        {
572
 
                [self captureScreen];
573
 
                usleep(200);
574
 
        }
575
 
 
576
 
        [messenger threadWillExit: info];
577
 
 
578
 
        @synchronized(self)
579
 
        {
580
 
                [self release];
581
 
        }
582
 
 
583
 
        [info release];
584
 
        [pool drain];
585
 
}
586
 
 
587
 
 
588
 
- (void) setAccelerometerUpdateInterval: (NSTimeInterval) dt
589
 
{
590
 
        CFSwappedFloat64 sdt = CFConvertFloat64HostToSwapped(dt);
591
 
        NSData* data = [NSData dataWithBytes: &sdt length: sizeof(CFSwappedFloat64)];
592
 
        [messenger sendData: data withIdentifier: kTapAccelerometerUpdateInterval];
593
 
}
594
 
 
595
 
/*
596
 
- (void)performTouches: (NSSet*) touches inView: (UIView *)view
597
 
{
598
 
    UITouch *touch = [[UITouch alloc] initInView:view];
599
 
    UIEvent *eventDown = [[UIEvent alloc] initWithTouch:touch];
600
 
    
601
 
    [touch.view touchesBegan:[eventDown allTouches] withEvent:eventDown];
602
 
    
603
 
    [touch setPhase:UITouchPhaseEnded];
604
 
    UIEvent *eventUp = [[UIEvent alloc] initWithTouch:touch];
605
 
    
606
 
    [touch.view touchesEnded:[eventUp allTouches] withEvent:eventUp];
607
 
    
608
 
    [eventDown release];
609
 
    [eventUp release];
610
 
    [touch release];
611
 
}
612
 
*/
613
 
 
614
 
static UIImage* imageFromGLData(NSData* data)
615
 
{
616
 
    // make data provider with data.
617
 
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, [data bytes], [data length], NULL);
618
 
   
619
 
    // prep the ingredients
620
 
    int bitsPerComponent = 8;
621
 
    int bitsPerPixel = 32;
622
 
    int bytesPerRow = 4 * 320;
623
 
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
624
 
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
625
 
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
626
 
   
627
 
    // make the cgimage
628
 
    CGImageRef imageRef = CGImageCreate(320, 480, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
629
 
   
630
 
    // then make the uiimage from that
631
 
    UIImage *myImage = [UIImage imageWithCGImage:imageRef];
632
 
    return myImage;
633
 
}
634
 
 
635
 
static NSData* dataFromGL(void)
636
 
{
637
 
    NSInteger myDataLength = 320 * 480 * 4;
638
 
        
639
 
        NSMutableData* data = [NSMutableData dataWithLength: myDataLength];
640
 
   
641
 
    // allocate array and read pixels into it.
642
 
    void* buffer = [data mutableBytes];
643
 
    glReadPixels(0, 0, 320, 480, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
644
 
        
645
 
        size_t bpr = 4*320;
646
 
        void* rowbuf = calloc(1, bpr);
647
 
        
648
 
        // swap image in Y
649
 
        for (size_t i = 0; i < 480/2; ++i)
650
 
        {
651
 
                memcpy(rowbuf, buffer + i*bpr, bpr);
652
 
                memcpy(buffer + i*bpr, buffer + (480-i-1)*bpr, bpr);
653
 
                memcpy(buffer + (480-i-1)*bpr, rowbuf, bpr);
654
 
        }
655
 
        
656
 
        free(rowbuf);
657
 
 
658
 
        return data;
659
 
}
660
 
 
661
 
- (void) glGrabPoint
662
 
{
663
 
        if (!enableVisualFeedback)
664
 
                return;
665
 
 
666
 
        NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
667
 
        if (lastGlUpdate + desiredFrameInterval < now)
668
 
        {
669
 
                NSData* rawData = dataFromGL();
670
 
                UIImage* image = imageFromGLData(rawData);
671
 
                
672
 
                NSData* data = UIImagePNGRepresentation(image);
673
 
                
674
 
                [messenger sendData: data withIdentifier: kTapRawScreenshot];
675
 
                
676
 
                lastGlUpdate = now;
677
 
        }
678
 
}
679
 
 
680
 
+ (void) glGrabPoint
681
 
{
682
 
        [[self sharedServer] glGrabPoint];
683
 
}
684
 
 
685
 
+ (id) sharedServer
686
 
{
687
 
        static id sharedInstance = nil;
688
 
        if (!sharedInstance)
689
 
                sharedInstance = [[TappityServer alloc] init];
690
 
        
691
 
        
692
 
        return sharedInstance;
693
 
}
694
 
 
695
 
- (void) dealloc
696
 
{
697
 
 
698
 
        [captureTimer invalidate];
699
 
        
700
 
        [messenger terminateConnection];
701
 
        [messenger release];
702
 
        
703
 
        [capturedImagesCondition release];
704
 
        [capturedImagesQueue release];
705
 
 
706
 
        [super dealloc];
707
 
}
708
 
 
709
 
@synthesize locationDelegate, headingDelegate;
710
 
 
711
 
@end

Loggerhead 1.17 is a web-based interface for Bazaar branches