13#include <OpenGL/CGLMacro.h>
15#include <QuartzCore/CoreImage.h>
17#include <dispatch/dispatch.h>
44@property dispatch_queue_t runnerQueue;
46@property (retain) NSURL *compositionURL;
47@property (retain) NSString *compositionString;
48@property (retain) NSString *compositionSourcePath;
49@property (retain) NSString *compositionProcessName;
54@property set<VuoRunner::Port *> *changedPorts;
58@synthesize runnerQueue;
60@synthesize compositionURL;
61@synthesize compositionString;
62@synthesize compositionSourcePath;
63@synthesize compositionProcessName;
68@synthesize changedPorts;
80+ (void)setGlobalRootContext:(CGLContextObj)context
109+ (BOOL)isComposition:(NSURL *)compositionURL compliantWithProtocol:(
VuoProtocol *)protocol
122+ (BOOL)isCompositionString:(NSString *)compositionString compliantWithProtocol:(
VuoProtocol *)protocol
124 VuoRunnerCocoa *runner = [[
VuoRunnerCocoa alloc] initWithCompositionString:compositionString name:@"" sourcePath:nil protocol:protocol];
135- (id)initWithComposition:(NSURL *)theCompositionURL protocol:(
VuoProtocol *)theProtocol
138 NSString *s = [NSString stringWithContentsOfURL:theCompositionURL encoding:NSUTF8StringEncoding error:&error];
141 NSLog(
@"[VuoRunnerCocoa initWithComposition:protocol:] Error reading composition: %@", error);
146 self = [
self initWithCompositionString:s name:[theCompositionURL lastPathComponent] sourcePath:nil protocol:theProtocol];
150 self.compositionURL = theCompositionURL;
158- (id)initWithCompositionString:(NSString *)theCompositionString name:(NSString *)processName sourcePath:(NSString *)sourcePath protocol:(
VuoProtocol *)theProtocol
160 if (!(
self = [super init]))
163 self.protocol = theProtocol;
165 self.runnerQueue = dispatch_queue_create(
"org.vuo.runner.cocoa", NULL);
168 self.compositionString = theCompositionString;
169 const char *compositionCString = [
self.compositionString UTF8String];
176 self.compositionProcessName = processName;
177 self.compositionSourcePath = sourcePath;
180 self.compositionName = [NSString stringWithUTF8String:metadata.getName().c_str()];
181 self.compositionDescription = [NSString stringWithUTF8String:metadata.getDescription().c_str()];
182 self.compositionCopyright = [NSString stringWithUTF8String:metadata.getCopyright().c_str()];
184 self.changedPorts =
new set<VuoRunner::Port *>();
194 dispatch_sync(
self.runnerQueue, ^{
201 dispatch_release(
self.runnerQueue);
202 [compositionURL release];
203 [compositionString release];
204 [compositionSourcePath release];
205 [compositionName release];
206 [compositionDescription release];
207 [compositionCopyright release];
208 delete self.changedPorts;
216 dispatch_sync(
self.runnerQueue, ^{
218 if (
self.compositionURL)
220 [[
self.compositionURL path] UTF8String],
224 [
self.compositionString UTF8String],
225 [
self.compositionProcessName UTF8String],
226 [
self.compositionSourcePath UTF8String],
234 self.runner->start();
235 self.runner->subscribeToEventTelemetry(
"");
239 vector<VuoRunner::Port *> allInputPorts =
self.runner->getPublishedInputPorts();
240 std::copy_if(allInputPorts.begin(), allInputPorts.end(), std::inserter(*
self.changedPorts,
self.changedPorts->begin()),
257 dispatch_sync(
self.runnerQueue, ^{
258 if (
self.runner && !
self.runner->isStopped())
267- (NSString *)description
269 return [NSString stringWithFormat:@"VuoRunnerCocoa(\"%@\")", compositionName];
281 NSMutableArray *portsArray = [[NSMutableArray new] autorelease];
282 vector<VuoRunner::Port *> ports =
self.runner->getPublishedInputPorts();
283 for (vector<VuoRunner::Port *>::iterator it = ports.begin(); it != ports.end(); ++it)
284 if (
self.protocol && !
self.protocol->
hasInputPort((*it)->getName()))
285 [portsArray addObject:[NSString stringWithUTF8String:(*it)->getName().c_str()]];
298 NSMutableArray *portsArray = [[NSMutableArray new] autorelease];
299 vector<VuoRunner::Port *> ports =
self.runner->getPublishedOutputPorts();
300 for (vector<VuoRunner::Port *>::iterator it = ports.begin(); it != ports.end(); ++it)
301 if (
self.protocol && !
self.protocol->
hasOutputPort((*it)->getName()))
302 [portsArray addObject:[NSString stringWithUTF8String:(*it)->getName().c_str()]];
335- (NSDictionary *)detailsForPort:(NSString *)portName
337 const char *portNameCString = [portName UTF8String];
338 VuoRunner::Port *port =
self.runner->getPublishedInputPortWithName(portNameCString);
341 port =
self.runner->getPublishedOutputPortWithName(portNameCString);
346 NSMutableDictionary *details = [[NSMutableDictionary new] autorelease];
348 details[@"title"] = [NSString stringWithUTF8String:port->getName().c_str()];
350 details[@"type"] = [NSString stringWithUTF8String:port->getType().c_str()];
357 if (json_object_object_get_ex(js,
"default", &o))
361 details[@"default"] = cocoaObject;
364 if (json_object_object_get_ex(js,
"suggestedMin", &o))
368 details[@"suggestedMin"] = cocoaObject;
371 if (json_object_object_get_ex(js,
"suggestedMax", &o))
375 details[@"suggestedMax"] = cocoaObject;
378 if (json_object_object_get_ex(js,
"suggestedStep", &o))
382 details[@"suggestedStep"] = cocoaObject;
385 if (json_object_object_get_ex(js,
"menuItems", &o))
387 NSMutableArray *menuItems = [NSMutableArray new];
389 int itemCount = json_object_array_length(o);
390 for (
int i = 0; i < itemCount; ++i)
392 json_object *item = json_object_array_get_idx(o, i);
395 if (json_object_is_type(item, json_type_object))
398 json_object_object_get_ex(item,
"value", &value);
400 json_object_object_get_ex(item,
"name", &name);
403 if (json_object_is_type(value, json_type_string))
404 valueNS = [NSString stringWithUTF8String:json_object_get_string(value)];
405 else if (json_object_is_type(value, json_type_int))
406 valueNS = [NSNumber numberWithLong:json_object_get_int64(value)];
408 const char *summary = json_object_get_string(name);
411 @"name": [NSString stringWithUTF8String:summary],
414 else if (json_object_is_type(item, json_type_string))
415 menuItem = [NSString stringWithUTF8String:json_object_get_string(item)];
418 [menuItems addObject:menuItem];
421 details[@"menuItems"] = menuItems;
437 NSMutableDictionary *properties = [[NSMutableDictionary new] autorelease];
439 vector<VuoRunner::Port *> ports =
self.runner->getPublishedInputPorts();
440 for (vector<VuoRunner::Port *>::iterator it = ports.begin(); it != ports.end(); ++it)
441 if (
self.protocol && !
self.protocol->
hasInputPort((*it)->getName()))
443 json_object *portValue =
self.runner->getPublishedInputPortValue(*it);
444 const char *valueAsString = json_object_to_json_string_ext(portValue, JSON_C_TO_STRING_PLAIN);
445 properties[[NSString stringWithUTF8String:(*it)->getName().c_str()]] = [NSString stringWithUTF8String:valueAsString];
457- (BOOL)setInputValuesWithPropertyList:(
id)propertyList
462 __block BOOL ok = YES;
463 __block map<VuoRunner::Port *, json_object *> m;
464 [(NSDictionary *)propertyList enumerateKeysAndObjectsUsingBlock:^(NSString *portName, NSString *value, BOOL *stop) {
465 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName([portName UTF8String]);
472 json_object *valueJson = json_tokener_parse([value UTF8String]);
482 runner->setPublishedInputPortValues(m);
486 self.changedPorts->insert(kv.first);
487 json_object_put(kv.second);
508- (BOOL)setInputValues:(NSDictionary *)namesAndValues
514 map<VuoRunner::Port *, json_object *> m;
515 for (NSString *portName in namesAndValues)
517 VuoRunner::Port *port =
self.runner->getPublishedInputPortWithName([portName UTF8String]);
524 id value = namesAndValues[portName];
535 self.runner->setPublishedInputPortValues(m);
539 self.changedPorts->insert(kv.first);
540 json_object_put(kv.second);
553- (BOOL)setInputJSON:(NSDictionary *)namesAndJSON
559 map<VuoRunner::Port *, json_object *> m;
560 for (NSString *portName in namesAndJSON)
562 VuoRunner::Port *port =
self.runner->getPublishedInputPortWithName([portName UTF8String]);
569 id nsValue = namesAndJSON[portName];
573 if (port->
getType() ==
"VuoImage")
575 if (json_object_get_type(value) == json_type_string)
577 char *s = strdup(json_object_get_string(value));
581 NSLog(
@"Error: Couldn't load image '%s'.\n", s);
595 self.runner->setPublishedInputPortValues(m);
598 self.changedPorts->insert(kv.first);
620- (id)valueForOutputPort:(NSString *)portName
625 VuoRunner::Port *port =
self.runner->getPublishedOutputPortWithName([portName UTF8String]);
629 json_object *valueJson =
self.runner->getPublishedOutputPortValue(port);
642- (GLuint)glTextureWithTarget:(GLuint)target forOutputPort:(NSString *)portName outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
647 VuoRunner::Port *port =
self.runner->getPublishedOutputPortWithName([portName UTF8String]);
651 json_object *valueJson =
self.runner->getPublishedOutputPortValue(port);
655 json_object_put(valueJson);
657 if (target == GL_TEXTURE_RECTANGLE_ARB)
662 vuoImage = newVuoImage;
665 if (outputPixelsWide)
666 *outputPixelsWide = vuoImage->pixelsWide;
667 if (outputPixelsHigh)
668 *outputPixelsHigh = vuoImage->pixelsHigh;
672 return vuoImage->glTextureName;
694- (GLuint)glTextureFromProvider:(GLuint (^)(NSUInteger pixelsWide, NSUInteger pixelsHigh))provider forOutputPort:(NSString *)portName outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh ioSurface:(IOSurfaceRef *)outputIOSurface
699 VuoRunner::Port *port =
self.runner->getPublishedOutputPortWithName([portName UTF8String]);
703 json_object *valueJson =
self.runner->getPublishedOutputPortValue(port);
705 GLuint (^provider2)(
unsigned int,
unsigned int) = ^GLuint(
unsigned int pixelsWide,
unsigned int pixelsHigh){
706 return provider(pixelsWide, pixelsHigh);
708 unsigned int outputPixelsWide2, outputPixelsHigh2;
710 *outputPixelsWide = outputPixelsWide2;
711 *outputPixelsHigh = outputPixelsHigh2;
712 return outputTexture;
722+ (BOOL)canOpenComposition:(NSURL *)compositionURL
724 return [
self isComposition:compositionURL compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)];
730+ (BOOL)canOpenCompositionString:(NSString *)compositionString
732 return [
self isCompositionString:compositionString compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)];
741- (id)initWithComposition:(NSURL *)aCompositionURL
746 [
self compileAndRun];
760- (id)initWithCompositionString:(NSString *)aCompositionString name:(NSString *)name sourcePath:(NSString *)sourcePath
765 [
self compileAndRun];
775static void VuoRunnerCocoa_doNothingCallback(
VuoImage imageToFree)
782- (BOOL)executeWithGLTexture:(GLuint)textureName target:(GLuint)target pixelsWide:(
unsigned long)pixelsWide pixelsHigh:(
unsigned long)pixelsHigh atTime:(NSTimeInterval)time
788 VuoRunner::Port *port =
self.runner->getPublishedInputPortWithName(
"image");
790 image->glTextureTarget = target;
794 map<VuoRunner::Port *, json_object *> m;
796 self.runner->setPublishedInputPortValues(m);
797 json_object_put(valueJson);
799 self.changedPorts->insert(port);
802 return [
self executeAtTime:time];
808- (BOOL)executeAtTime:(NSTimeInterval)time
813 VuoRunner::Port *timePort =
self.runner->getPublishedInputPortWithName(
"time");
817 map<VuoRunner::Port *, json_object *> m;
818 m[timePort] = valueJson;
819 self.runner->setPublishedInputPortValues(m);
820 json_object_put(valueJson);
822 self.changedPorts->insert(timePort);
825 self.runner->firePublishedInputPortEvent(*
self.changedPorts);
826 self.changedPorts->clear();
828 self.runner->waitForFiredPublishedInputPortEvent();
845- (NSImage *)filterNSImage:(NSImage *)image atTime:(NSTimeInterval)time
847 [
self setInputValues:@{@"image":image}];
849 if (![
self executeAtTime:time])
852 return [
self valueForOutputPort:@"outputImage"];
869- (GLuint)filterGLTexture:(GLuint)textureName target:(GLuint)target pixelsWide:(NSUInteger)pixelsWide pixelsHigh:(NSUInteger)pixelsHigh atTime:(NSTimeInterval)time outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
871 if (![
self executeWithGLTexture:textureName target:target pixelsWide:pixelsWide pixelsHigh:pixelsHigh atTime:time])
873 return [
self glTextureWithTarget:target forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh];
905- (GLuint)filterGLTexture:(GLuint)textureName target:(GLuint)target pixelsWide:(NSUInteger)pixelsWide pixelsHigh:(NSUInteger)pixelsHigh atTime:(NSTimeInterval)time withTextureProvider:(GLuint (^)(NSUInteger pixelsWide, NSUInteger pixelsHigh))provider outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh ioSurface:(IOSurfaceRef *)outputIOSurface
907 if (![
self executeWithGLTexture:textureName target:target pixelsWide:pixelsWide pixelsHigh:pixelsHigh atTime:time])
910 return [
self glTextureFromProvider:provider forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh ioSurface:outputIOSurface];
921@property NSUInteger previousSuggestedPixelsHigh;
925@synthesize previousSuggestedPixelsWide;
926@synthesize previousSuggestedPixelsHigh;
931+ (BOOL)canOpenComposition:(NSURL *)compositionURL
933 return [
self isComposition:compositionURL compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)];
939+ (BOOL)canOpenCompositionString:(NSString *)compositionString
941 return [
self isCompositionString:compositionString compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)];
950- (id)initWithComposition:(NSURL *)aCompositionURL
955 [
self compileAndRun];
959 self.previousSuggestedPixelsWide = NSUIntegerMax;
960 self.previousSuggestedPixelsHigh = NSUIntegerMax;
972- (id)initWithCompositionString:(NSString *)aCompositionString name:(NSString *)name sourcePath:(NSString *)sourcePath
977 [
self compileAndRun];
987- (BOOL)executeWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
992 VuoRunner::Port *timePort =
self.runner->getPublishedInputPortWithName(
"time");
993 VuoRunner::Port *widthPort =
self.runner->getPublishedInputPortWithName(
"width");
994 VuoRunner::Port *heightPort =
self.runner->getPublishedInputPortWithName(
"height");
996 map<VuoRunner::Port *, json_object *> m;
1000 if (suggestedPixelsWide !=
self.previousSuggestedPixelsWide)
1003 self.previousSuggestedPixelsWide = suggestedPixelsWide;
1005 if (suggestedPixelsHigh !=
self.previousSuggestedPixelsHigh)
1008 self.previousSuggestedPixelsHigh = suggestedPixelsHigh;
1011 self.runner->setPublishedInputPortValues(m);
1014 self.changedPorts->insert(kv.first);
1015 json_object_put(kv.second);
1018 self.runner->firePublishedInputPortEvent(*
self.changedPorts);
1019 self.changedPorts->clear();
1021 self.runner->waitForFiredPublishedInputPortEvent();
1036- (NSImage *)generateNSImageWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
1038 if (![
self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1040 return [
self valueForOutputPort:@"outputImage"];
1053- (GLuint)generateGLTextureWithTarget:(GLuint)target suggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
1055 if (![
self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1057 return [
self glTextureWithTarget:target forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh];
1083- (GLuint)generateGLTextureWithProvider:(GLuint (^)(NSUInteger pixelsWide, NSUInteger pixelsHigh))provider suggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh ioSurface:(IOSurfaceRef *)outputIOSurface
1085 if (![
self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1087 return [
self glTextureFromProvider:provider forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh ioSurface:outputIOSurface];
1098- (
VuoImage)generateVuoImageWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
1100 if (![
self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1104 VuoRunner::Port *port =
self.runner->getPublishedOutputPortWithName(
"outputImage");
1108 json_object *valueJson =
self.runner->getPublishedOutputPortValue(port);
1110 json_object_put(valueJson);