1#import <QuartzCore/QuartzCore.h> 2#import <Social/Social.h> 3 4#import "ModelViewController.h" 5#import "Utils.h" 6#import "drawContext.h" 7#import "iosUtils.h" 8 9#import "AppDelegate.h" 10 11@interface ModelViewController () 12- (void)configureView; 13@end 14 15@implementation ModelViewController 16 17#pragma mark - Managing the detail item 18@synthesize glView; 19 20- (void)setDetailItem:(id)newDetailItem 21{ 22 if(_detailItem != newDetailItem) { 23 _detailItem = newDetailItem; 24 // Update the view. 25 [self configureView]; 26 } 27} 28 29- (void)configureView 30{ 31 // Update the user interface for the detail item. 32 if(self.detailItem) { 33 self.detailDescriptionLabel.text = [self.detailItem description]; 34 } 35} 36 37- (void)viewDidAppear:(BOOL)animated 38{ 39 _progressLabel.frame = CGRectMake(50, self.view.frame.size.height - 25, 40 _progressLabel.frame.size.width, 41 _progressLabel.frame.size.height); 42 _progressIndicator.frame = CGRectMake(20, self.view.frame.size.height - 25, 43 _progressIndicator.frame.size.width, 44 _progressIndicator.frame.size.height); 45 [_progressIndicator 46 addGestureRecognizer:[[UITapGestureRecognizer alloc] 47 initWithTarget:self 48 action:@selector 49 (handleProgressIndicatorTap:)]]; 50 [_progressLabel setHidden:YES]; 51 [_progressIndicator setHidden:YES]; 52 [self.navigationController setToolbarHidden:YES animated:NO]; 53 if(self.initialModel != nil) { 54 [self.glView load:self.initialModel]; 55 [[NSNotificationCenter defaultCenter] 56 postNotificationName:@"refreshParameters" 57 object:nil]; 58 //[self.initialModel release]; 59 self.initialModel = nil; 60 } 61} 62 63- (void)viewDidLoad 64{ 65 [super viewDidLoad]; 66 // Do any additional setup after loading the view, typically from a nib. 67 [self configureView]; 68 [_singleTap requireGestureRecognizerToFail:_doubleTap]; 69 scaleFactor = 1.; 70 setObjCBridge((__bridge void *)self); 71 [[NSNotificationCenter defaultCenter] addObserver:self 72 selector:@selector(requestRender) 73 name:@"requestRender" 74 object:nil]; 75 76 _runStopButton = 77 [[UIBarButtonItem alloc] initWithTitle:@"Run" 78 style:UIBarButtonItemStylePlain 79 target:self 80 action:@selector(compute)]; 81 if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || 82 [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]) { 83 UIBarButtonItem *model = 84 [[UIBarButtonItem alloc] initWithTitle:@"Model list" 85 style:UIBarButtonItemStylePlain 86 target:self 87 action:@selector(showModelsList)]; 88 [self.navigationItem 89 setRightBarButtonItems:[NSArray 90 arrayWithObjects:_runStopButton, model, nil]]; 91 } 92 else { 93 UIBarButtonItem *settings = 94 [[UIBarButtonItem alloc] initWithTitle:@"Parameters" 95 style:UIBarButtonItemStylePlain 96 target:self 97 action:@selector(showSettings)]; 98 [self.navigationItem 99 setRightBarButtonItems:[NSArray 100 arrayWithObjects:_runStopButton, settings, nil]]; 101 } 102 103 UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] 104 initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace 105 target:nil 106 action:nil]; 107 UIBarButtonItem *prevButton = [[UIBarButtonItem alloc] 108 initWithBarButtonSystemItem:UIBarButtonSystemItemRewind 109 target:self 110 action:@selector(prevAnimation)]; 111 _stopButton = [[UIBarButtonItem alloc] 112 initWithBarButtonSystemItem:UIBarButtonSystemItemPause 113 target:self 114 action:@selector(stopAnimation:)]; 115 [_stopButton setEnabled:NO]; 116 _playButton = [[UIBarButtonItem alloc] 117 initWithBarButtonSystemItem:UIBarButtonSystemItemPlay 118 target:self 119 action:@selector(playAnimation:)]; 120 UIBarButtonItem *nextButton = [[UIBarButtonItem alloc] 121 initWithBarButtonSystemItem:UIBarButtonSystemItemFastForward 122 target:self 123 action:@selector(nextAnimation)]; 124 self.toolbarItems = [[NSArray alloc] 125 initWithObjects:flexibleSpace, prevButton, _stopButton, _playButton, 126 nextButton, flexibleSpace, nil]; 127} 128 129- (void)viewWillTransitionToSize:(CGSize)size 130 withTransitionCoordinator: 131 (id<UIViewControllerTransitionCoordinator>)coordinator 132{ 133 [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; 134 _progressLabel.frame = CGRectMake(50, self.view.frame.size.height - 25, 135 _progressLabel.frame.size.width, 136 _progressLabel.frame.size.height); 137 _progressIndicator.frame = CGRectMake(20, self.view.frame.size.height - 25, 138 _progressIndicator.frame.size.width, 139 _progressIndicator.frame.size.height); 140} 141 142- (void)compute 143{ 144 AppDelegate *appDelegate = 145 (AppDelegate *)[UIApplication sharedApplication].delegate; 146 appDelegate->compute = YES; 147 [_runStopButton setAction:@selector(stop)]; 148 [_runStopButton setTitle:@"Stop"]; 149 [_progressLabel setText:@""]; 150 [_progressLabel setHidden:NO]; 151 [_progressIndicator setHidden:NO]; 152 [_progressIndicator startAnimating]; 153 self.navigationItem.hidesBackButton = YES; 154 155 [[UIApplication sharedApplication] cancelAllLocalNotifications]; 156 dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{ 157 onelab_cb("compute"); 158 dispatch_async(dispatch_get_main_queue(), ^{ 159 AppDelegate *appDelegate = 160 (AppDelegate *)[UIApplication sharedApplication].delegate; 161 appDelegate->compute = NO; 162 [[NSNotificationCenter defaultCenter] 163 postNotificationName:@"refreshParameters" 164 object:nil]; 165 [self->_runStopButton setAction:@selector(compute)]; 166 [self->_runStopButton setTitle:@"Run"]; 167 [self->_progressLabel setHidden:YES]; 168 [self->_progressIndicator stopAnimating]; 169 [self->_progressIndicator setHidden:YES]; 170 self.navigationItem.hidesBackButton = NO; 171 }); 172 }); 173} 174 175- (void)stop 176{ 177 onelab_cb("stop"); 178} 179 180- (void)playAnimation:(UIBarButtonItem *)sender 181{ 182 [_playButton setEnabled:NO]; 183 [_stopButton setEnabled:YES]; 184 _animation = [NSTimer scheduledTimerWithTimeInterval:0.5 185 target:self 186 selector:@selector(nextAnimation) 187 userInfo:nil 188 repeats:YES]; 189} 190 191- (void)stopAnimation:(UIBarButtonItem *)sender 192{ 193 [_animation invalidate]; 194 _animation = nil; 195 [_playButton setEnabled:YES]; 196 [_stopButton setEnabled:NO]; 197} 198 199- (void)nextAnimation 200{ 201 animation_next(); 202 [self requestRender]; 203} 204 205- (void)prevAnimation 206{ 207 animation_prev(); 208 [self requestRender]; 209} 210 211- (IBAction)pinch:(UIPinchGestureRecognizer *)sender 212{ 213 if([sender numberOfTouches] <= 2) { 214 float mScale = scaleFactor; 215 if(sender.state == UIGestureRecognizerStateBegan) 216 mScale = scaleFactor; 217 else if(sender.state == UIGestureRecognizerStateChanged) 218 mScale = scaleFactor * [sender scale]; 219 else if(sender.state == UIGestureRecognizerStateEnded) { 220 scaleFactor *= [sender scale]; 221 mScale = scaleFactor; 222 } 223 else if(sender.state == UIGestureRecognizerStateCancelled) { 224 mScale = scaleFactor; 225 } 226 mScale = MAX(0.1, mScale); 227 glView->mContext->eventHandler(2, mScale); 228 } 229 [glView drawView]; 230} 231 232- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 233{ 234 UITouch *touch = [[event allTouches] anyObject]; 235 CGPoint touchPoint = [touch locationInView:self.view]; 236 glView->mContext->eventHandler(0, touchPoint.x, touchPoint.y); 237} 238 239- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 240{ 241 [self touchesEnded:touches withEvent:event]; 242} 243 244- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 245{ 246 UITouch *touch = [[event allTouches] anyObject]; 247 CGPoint touchPoint = [touch locationInView:self.view]; 248 glView->mContext->eventHandler(4, touchPoint.x, touchPoint.y); 249} 250 251- (IBAction)singleTap:(UITapGestureRecognizer *)sender 252{ 253 [self.navigationController 254 setToolbarHidden:(!(self.navigationController.toolbarHidden && 255 !((AppDelegate *)[UIApplication sharedApplication] 256 .delegate) 257 ->compute && 258 number_of_animation() > 0)) 259 animated:YES]; 260} 261 262- (IBAction)doubleTap:(UITapGestureRecognizer *)sender 263{ 264 scaleFactor = 1; 265 glView->mContext->eventHandler(10); 266 [glView drawView]; 267} 268 269- (void)showModelsList 270{ 271 AppDelegate *appDelegate = 272 (AppDelegate *)[UIApplication sharedApplication].delegate; 273 if(appDelegate->compute) { 274 UIAlertController *alert = [UIAlertController 275 alertControllerWithTitle:@"Cannot show model list" 276 message:@"Computation has to complete before a new " 277 @"model can be selected" 278 preferredStyle:UIAlertControllerStyleAlert]; 279 UIAlertAction *dismissButton = 280 [UIAlertAction actionWithTitle:@"Dismiss" 281 style:UIAlertActionStyleDefault 282 handler:^(UIAlertAction *action){}]; 283 [alert addAction:dismissButton]; 284 [self presentViewController:alert animated:YES completion:nil]; 285 return; 286 } 287 if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || 288 [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]) { 289 [UIView transitionWithView:appDelegate.window 290 duration:0.5 291 options:UIViewAnimationOptionTransitionFlipFromRight 292 animations:^{ 293 appDelegate.window.rootViewController = 294 appDelegate.modelListController; 295 } 296 completion:nil]; 297 } 298 [self.navigationController popToRootViewControllerAnimated:YES]; 299} 300 301- (void)showSettings 302{ 303 [self performSegueWithIdentifier:@"showSettingsSegue" sender:self]; 304} 305 306- (void)requestRender 307{ 308 if([[UIApplication sharedApplication] applicationState] == 309 UIApplicationStateActive) 310 [glView drawView]; 311} 312 313#pragma mark - Split view 314 315void messageFromCpp(void *self, std::string level, std::string msg) 316{ 317 if(level == "RequestRender") { 318 [(__bridge id)self performSelectorOnMainThread:@selector(requestRender) 319 withObject:nil 320 waitUntilDone:YES]; 321 [[NSNotificationCenter defaultCenter] 322 postNotificationName:@"refreshParameters" 323 object:nil]; 324 } 325 else if(level == "Progress") { 326 [(__bridge id)self 327 performSelectorOnMainThread:@selector(setProgress:) 328 withObject:[Utils getStringFromCString:msg.c_str()] 329 waitUntilDone:YES]; 330 } 331 else if(level == "Error") { 332 [(__bridge id)self 333 performSelectorOnMainThread:@selector(showError:) 334 withObject:[Utils getStringFromCString:msg.c_str()] 335 waitUntilDone:YES]; 336 } 337} 338 339- (void)setProgress:(NSString *)progress 340{ 341 [_progressLabel setText:progress]; 342} 343 344- (void)showError:(NSString *)msg 345{ 346 // remove document path from error message 347 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 348 NSUserDomainMask, YES); 349 NSString *docPath = [[paths objectAtIndex:0] stringByAppendingString:@"/"]; 350 NSString *str = [msg stringByReplacingOccurrencesOfString:docPath 351 withString:@""]; 352 UIAlertController *alert = 353 [UIAlertController alertControllerWithTitle:@"Error" 354 message:str 355 preferredStyle:UIAlertControllerStyleAlert]; 356 UIAlertAction *dismissButton = 357 [UIAlertAction actionWithTitle:@"Dismiss" 358 style:UIAlertActionStyleDefault 359 handler:^(UIAlertAction *action){}]; 360 [alert addAction:dismissButton]; 361 [self presentViewController:alert animated:YES completion:nil]; 362} 363 364- (void)handleProgressIndicatorTap:(id)sender 365{ 366 [_progressLabel setHidden:!_progressLabel.hidden]; 367} 368 369void getBitmap(void *self, const char *text, int textsize, unsigned char **map, 370 int *height, int *width, int *realWidth) 371{ 372 [(__bridge id)self getBitmapFromStringObjC:text 373 withTextSize:textsize 374 inMap:map 375 inHeight:height 376 inWidth:width 377 inRealWidth:realWidth]; 378} 379 380- (void)getBitmapFromStringObjC:(const char *)text 381 withTextSize:(int)textsize 382 inMap:(unsigned char **)map 383 inHeight:(int *)height 384 inWidth:(int *)width 385 inRealWidth:(int *)realWidth 386{ 387 UILabel *lbl = 388 [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 1024, 7 * textsize / 6)]; 389 lbl.font = [UIFont systemFontOfSize:textsize]; 390 [lbl setText:[Utils getStringFromCString:text]]; 391 [lbl setBackgroundColor:[UIColor clearColor]]; 392 CGSize lblSize = 393 [[lbl text] sizeWithAttributes:@{NSFontAttributeName : [lbl font]}]; 394 *realWidth = lblSize.width; 395 int i = 2; 396 while(i < *realWidth) i *= 2; 397 *width = i; 398 *height = lblSize.height; 399 i = 2; 400 while(i < *height) i *= 2; 401 *height = i; 402 403 UIGraphicsBeginImageContextWithOptions(CGSizeMake(*width, *height), NO, 0.0); 404 [lbl.layer renderInContext:UIGraphicsGetCurrentContext()]; 405 UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); 406 UIGraphicsEndImageContext(); 407 CGImageRef bitmap = [img CGImage]; 408 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 409 unsigned char *rawData = 410 (unsigned char *)calloc(*height * *width * 4, sizeof(unsigned char)); 411 *map = (unsigned char *)calloc(*height * *width, sizeof(unsigned char)); 412 NSUInteger bytesPerPixel = 4; 413 NSUInteger bytesPerRow = bytesPerPixel * *width; 414 NSUInteger bitsPerComponent = 8; 415 CGContextRef context = CGBitmapContextCreate( 416 rawData, *width, *height, bitsPerComponent, bytesPerRow, colorSpace, 417 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 418 CGColorSpaceRelease(colorSpace); 419 420 CGContextDrawImage(context, CGRectMake(0, 0, *width, *height), bitmap); 421 CGContextRelease(context); 422 423 // rawData contains the image data in the RGBA8888 pixel format. 424 for(int byteIndex = 0; byteIndex < *width * *height * 4; byteIndex += 4) 425 *(*map + byteIndex / 4) = rawData[byteIndex + 3]; 426 free(rawData); 427} 428 429- (IBAction)startRotation:(UIButton *)sender 430{ 431 glView->rotate = !glView->rotate; 432 if(glView->rotate) 433 [sender setImage:[UIImage imageNamed:@"icon_translate.png"] 434 forState:UIControlStateNormal]; 435 else 436 [sender setImage:[UIImage imageNamed:@"icon_rotate.png"] 437 forState:UIControlStateNormal]; 438} 439 440@end 441