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;
50@property (retain) NSString *compositionName;
51@property (retain) NSString *compositionDescription;
52@property (retain) NSString *compositionCopyright;
54@property set<VuoRunner::Port *> *changedPorts;
58@synthesize runnerQueue;
60@synthesize compositionURL;
61@synthesize compositionString;
62@synthesize compositionSourcePath;
63@synthesize compositionProcessName;
64@synthesize compositionName;
65@synthesize compositionDescription;
66@synthesize compositionCopyright;
68@synthesize changedPorts;
82+ (void)setGlobalRootContext:(CGLContextObj)context
94+ (void)prepareModuleCaches
112+ (
BOOL)isComposition:(NSURL *)compositionURL compliantWithProtocol:(
VuoProtocol *)protocol
127+ (
BOOL)isCompositionString:(NSString *)compositionString compliantWithProtocol:(
VuoProtocol *)protocol
129 VuoRunnerCocoa *runner = [[
VuoRunnerCocoa alloc] initWithCompositionString:compositionString name:@"" sourcePath:nil protocol:protocol];
142- (id)initWithComposition:(NSURL *)theCompositionURL protocol:(
VuoProtocol *)theProtocol
145 NSString *s = [NSString stringWithContentsOfURL:theCompositionURL encoding:NSUTF8StringEncoding error:&error];
148 NSLog(
@"[VuoRunnerCocoa initWithComposition:protocol:] Error reading composition: %@", error);
153 self = [
self initWithCompositionString:s name:[theCompositionURL lastPathComponent] sourcePath:nil protocol:theProtocol];
157 self.compositionURL = theCompositionURL;
167- (id)initWithCompositionString:(NSString *)theCompositionString name:(NSString *)processName sourcePath:(NSString *)sourcePath protocol:(
VuoProtocol *)theProtocol
169 if (!(self = [super init]))
172 self.protocol = theProtocol;
174 self.runnerQueue = dispatch_queue_create(
"org.vuo.runner.cocoa", NULL);
177 self.compositionString = theCompositionString;
178 const char *compositionCString = [
self.compositionString UTF8String];
185 self.compositionProcessName = processName;
186 self.compositionSourcePath = sourcePath;
189 self.compositionName = [NSString stringWithUTF8String:metadata.getName().c_str()];
190 self.compositionDescription = [NSString stringWithUTF8String:metadata.getDescription().c_str()];
191 self.compositionCopyright = [NSString stringWithUTF8String:metadata.getCopyright().c_str()];
193 self.changedPorts =
new set<VuoRunner::Port *>();
205 dispatch_sync(self.runnerQueue, ^{
212 dispatch_release(self.runnerQueue);
213 [compositionURL release];
214 [compositionString release];
215 [compositionSourcePath release];
216 [compositionName release];
217 [compositionDescription release];
218 [compositionCopyright release];
219 delete self.changedPorts;
227 dispatch_sync(self.runnerQueue, ^{
228 VuoCompilerIssues issues;
229 if (self.compositionURL)
230 self.runner = VuoCompiler::newSeparateProcessRunnerFromCompositionFile(
231 [[self.compositionURL path] UTF8String],
234 self.runner = VuoCompiler::newSeparateProcessRunnerFromCompositionString(
235 [self.compositionString UTF8String],
236 [self.compositionProcessName UTF8String],
237 [self.compositionSourcePath UTF8String],
240 if (!issues.isEmpty())
241 VUserLog(
"%s", issues.getLongDescription(false).c_str());
245 self.runner->start();
246 self.runner->subscribeToEventTelemetry(
"");
250 vector<VuoRunner::Port *> allInputPorts = self.runner->getPublishedInputPorts();
251 std::copy_if(allInputPorts.begin(), allInputPorts.end(), std::inserter(*self.changedPorts, self.changedPorts->begin()),
252 [] (VuoRunner::Port *port) { return ! port->getType().empty(); });
254 catch (VuoException &e)
256 VUserLog(
"Error: %s", e.what());
270 dispatch_sync(self.runnerQueue, ^{
271 if (self.runner && !self.runner->isStopped())
282- (NSString *)description
284 return [NSString stringWithFormat:@"VuoRunnerCocoa(%c%@%c)", '"', compositionName, '"'];
293- (NSArray *)inputPorts
298 NSMutableArray *portsArray = [[NSMutableArray new] autorelease];
299 vector<VuoRunner::Port *> ports = self.runner->getPublishedInputPorts();
300 for (vector<VuoRunner::Port *>::iterator it = ports.begin(); it != ports.end(); ++it)
301 if (self.protocol && !self.protocol->hasInputPort((*it)->getName()))
302 [portsArray addObject:[NSString stringWithUTF8String:(*it)->getName().c_str()]];
312- (NSArray *)outputPorts
317 NSMutableArray *portsArray = [[NSMutableArray new] autorelease];
318 vector<VuoRunner::Port *> ports = self.runner->getPublishedOutputPorts();
319 for (vector<VuoRunner::Port *>::iterator it = ports.begin(); it != ports.end(); ++it)
320 if (self.protocol && !self.protocol->hasOutputPort((*it)->getName()))
321 [portsArray addObject:[NSString stringWithUTF8String:(*it)->getName().c_str()]];
356- (NSDictionary *)detailsForPort:(NSString *)portName
358 const char *portNameCString = [portName UTF8String];
359 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName(portNameCString);
362 port = self.runner->getPublishedOutputPortWithName(portNameCString);
367 NSMutableDictionary *details = [[NSMutableDictionary new] autorelease];
369 details[@"title"] = [NSString stringWithUTF8String:port->getName().c_str()];
371 details[@"type"] = [NSString stringWithUTF8String:port->getType().c_str()];
376 json_object *o = NULL;
378 if (json_object_object_get_ex(js,
"default", &o))
380 id cocoaObject = [
VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
382 details[@"default"] = cocoaObject;
385 if (json_object_object_get_ex(js,
"suggestedMin", &o))
387 id cocoaObject = [
VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
389 details[@"suggestedMin"] = cocoaObject;
392 if (json_object_object_get_ex(js,
"suggestedMax", &o))
394 id cocoaObject = [
VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
396 details[@"suggestedMax"] = cocoaObject;
399 if (json_object_object_get_ex(js,
"suggestedStep", &o))
401 id cocoaObject = [
VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
403 details[@"suggestedStep"] = cocoaObject;
406 if (json_object_object_get_ex(js,
"menuItems", &o))
408 NSMutableArray *menuItems = [NSMutableArray new];
410 int itemCount = json_object_array_length(o);
411 for (
int i = 0; i < itemCount; ++i)
413 json_object *item = json_object_array_get_idx(o, i);
416 if (json_object_is_type(item, json_type_object))
419 json_object_object_get_ex(item,
"value", &value);
421 json_object_object_get_ex(item,
"name", &name);
424 if (json_object_is_type(value, json_type_string))
425 valueNS = [NSString stringWithUTF8String:json_object_get_string(value)];
426 else if (json_object_is_type(value, json_type_int))
427 valueNS = [NSNumber numberWithLong:json_object_get_int64(value)];
429 const char *summary = json_object_get_string(name);
432 @"name": [NSString stringWithUTF8String:summary],
435 else if (json_object_is_type(item, json_type_string))
436 menuItem = [NSString stringWithUTF8String:json_object_get_string(item)];
439 [menuItems addObject:menuItem];
442 details[@"menuItems"] = menuItems;
455- (id)propertyListFromInputValues
460 NSMutableDictionary *properties = [[NSMutableDictionary new] autorelease];
462 vector<VuoRunner::Port *> ports = self.runner->getPublishedInputPorts();
463 for (vector<VuoRunner::Port *>::iterator it = ports.begin(); it != ports.end(); ++it)
464 if (self.protocol && !self.protocol->hasInputPort((*it)->getName()))
466 json_object *portValue = self.runner->getPublishedInputPortValue(*it);
467 const char *valueAsString = json_object_to_json_string_ext(portValue, JSON_C_TO_STRING_PLAIN);
468 properties[[NSString stringWithUTF8String:(*it)->getName().c_str()]] = [NSString stringWithUTF8String:valueAsString];
482- (
BOOL)setInputValuesWithPropertyList:(
id)propertyList
487 __block
BOOL ok = YES;
488 __block map<VuoRunner::Port *, json_object *> m;
489 [(NSDictionary *)propertyList enumerateKeysAndObjectsUsingBlock:^(NSString *portName, NSString *value, BOOL *stop) {
490 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName([portName UTF8String]);
497 json_object *valueJson = json_tokener_parse([value UTF8String]);
511 self.changedPorts->insert(kv.first);
512 json_object_put(kv.second);
535- (
BOOL)setInputValues:(NSDictionary *)namesAndValues
541 map<VuoRunner::Port *, json_object *> m;
542 for (NSString *portName in namesAndValues)
544 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName([portName UTF8String]);
551 id value = namesAndValues[portName];
552 json_object *valueJson = [
VuoRunnerCocoa vuoValueWithCocoaObject:value];
562 self.runner->setPublishedInputPortValues(m);
566 self.changedPorts->insert(kv.first);
567 json_object_put(kv.second);
582- (
BOOL)setInputJSON:(NSDictionary *)namesAndJSON
588 map<VuoRunner::Port *, json_object *> m;
589 for (NSString *portName in namesAndJSON)
591 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName([portName UTF8String]);
598 id nsValue = namesAndJSON[portName];
599 json_object *value = (json_object *)[nsValue pointerValue];
602 if (port->
getType() ==
"VuoImage")
604 if (json_object_get_type(value) == json_type_string)
606 char *s = strdup(json_object_get_string(value));
610 NSLog(
@"Error: Couldn't load image '%s'.\n", s);
624 self.runner->setPublishedInputPortValues(m);
627 self.changedPorts->insert(kv.first);
651- (id)valueForOutputPort:(NSString *)portName
656 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName([portName UTF8String]);
660 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
661 return [
VuoRunnerCocoa cocoaObjectWithVuoValue:valueJson ofType:port->getType()];
675- (GLuint)glTextureWithTarget:(GLuint)target forOutputPort:(NSString *)portName outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
680 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName([portName UTF8String]);
684 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
688 json_object_put(valueJson);
690 if (target == GL_TEXTURE_RECTANGLE_ARB)
695 vuoImage = newVuoImage;
698 if (outputPixelsWide)
699 *outputPixelsWide = vuoImage->pixelsWide;
700 if (outputPixelsHigh)
701 *outputPixelsHigh = vuoImage->pixelsHigh;
705 return vuoImage->glTextureName;
729- (GLuint)glTextureFromProvider:(GLuint (^)(NSUInteger pixelsWide, NSUInteger pixelsHigh))provider forOutputPort:(NSString *)portName outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh ioSurface:(IOSurfaceRef *)outputIOSurface
734 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName([portName UTF8String]);
738 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
740 GLuint (^provider2)(
unsigned int,
unsigned int) = ^GLuint(
unsigned int pixelsWide,
unsigned int pixelsHigh){
741 return provider(pixelsWide, pixelsHigh);
743 unsigned int outputPixelsWide2, outputPixelsHigh2;
745 *outputPixelsWide = outputPixelsWide2;
746 *outputPixelsHigh = outputPixelsHigh2;
747 return outputTexture;
759+ (
BOOL)canOpenComposition:(NSURL *)compositionURL
761 return [
self isComposition:compositionURL compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)];
769+ (
BOOL)canOpenCompositionString:(NSString *)compositionString
771 return [
self isCompositionString:compositionString compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)];
782- (id)initWithComposition:(NSURL *)aCompositionURL
784 if (!(self = [super initWithComposition:aCompositionURL protocol:
VuoProtocol::getProtocol(
VuoProtocol::imageFilter)]))
787 [
self compileAndRun];
803- (id)initWithCompositionString:(NSString *)aCompositionString name:(NSString *)name sourcePath:(NSString *)sourcePath
805 if (!(self = [super initWithCompositionString:aCompositionString name:name sourcePath:sourcePath protocol:
VuoProtocol::getProtocol(
VuoProtocol::imageFilter)]))
808 [
self compileAndRun];
818static void VuoRunnerCocoa_doNothingCallback(
VuoImage imageToFree)
827- (
BOOL)executeWithGLTexture:(GLuint)textureName target:(GLuint)target pixelsWide:(
unsigned long)pixelsWide pixelsHigh:(
unsigned long)pixelsHigh atTime:(NSTimeInterval)time
833 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName(
"image");
835 image->glTextureTarget = target;
839 map<VuoRunner::Port *, json_object *> m;
841 self.runner->setPublishedInputPortValues(m);
842 json_object_put(valueJson);
844 self.changedPorts->insert(port);
847 return [
self executeAtTime:time];
855- (
BOOL)executeAtTime:(NSTimeInterval)time
860 VuoRunner::Port *timePort = self.runner->getPublishedInputPortWithName(
"time");
864 map<VuoRunner::Port *, json_object *> m;
865 m[timePort] = valueJson;
866 self.runner->setPublishedInputPortValues(m);
867 json_object_put(valueJson);
869 self.changedPorts->insert(timePort);
872 self.runner->firePublishedInputPortEvent(*self.changedPorts);
873 self.changedPorts->clear();
875 self.runner->waitForFiredPublishedInputPortEvent();
894- (NSImage *)filterNSImage:(NSImage *)image atTime:(NSTimeInterval)time
896 [
self setInputValues:@{@"image":image}];
898 if (![self executeAtTime:time])
901 return [
self valueForOutputPort:@"outputImage"];
920- (GLuint)filterGLTexture:(GLuint)textureName target:(GLuint)target pixelsWide:(NSUInteger)pixelsWide pixelsHigh:(NSUInteger)pixelsHigh atTime:(NSTimeInterval)time outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
922 if (![self executeWithGLTexture:textureName target:target pixelsWide:pixelsWide pixelsHigh:pixelsHigh atTime:time])
924 return [
self glTextureWithTarget:target forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh];
958- (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
960 if (![self executeWithGLTexture:textureName target:target pixelsWide:pixelsWide pixelsHigh:pixelsHigh atTime:time])
963 return [
self glTextureFromProvider:provider forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh ioSurface:outputIOSurface];
978@synthesize previousSuggestedPixelsWide;
979@synthesize previousSuggestedPixelsHigh;
986+ (
BOOL)canOpenComposition:(NSURL *)compositionURL
988 return [
self isComposition:compositionURL compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)];
996+ (
BOOL)canOpenCompositionString:(NSString *)compositionString
998 return [
self isCompositionString:compositionString compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)];
1009- (id)initWithComposition:(NSURL *)aCompositionURL
1011 if (!(self = [super initWithComposition:aCompositionURL protocol:
VuoProtocol::getProtocol(
VuoProtocol::imageGenerator)]))
1014 [
self compileAndRun];
1018 self.previousSuggestedPixelsWide = NSUIntegerMax;
1019 self.previousSuggestedPixelsHigh = NSUIntegerMax;
1033- (id)initWithCompositionString:(NSString *)aCompositionString name:(NSString *)name sourcePath:(NSString *)sourcePath
1035 if (!(self = [super initWithCompositionString:aCompositionString name:name sourcePath:sourcePath protocol:
VuoProtocol::getProtocol(
VuoProtocol::imageGenerator)]))
1038 [
self compileAndRun];
1050- (
BOOL)executeWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
1055 VuoRunner::Port *timePort = self.runner->getPublishedInputPortWithName(
"time");
1056 VuoRunner::Port *widthPort = self.runner->getPublishedInputPortWithName(
"width");
1057 VuoRunner::Port *heightPort = self.runner->getPublishedInputPortWithName(
"height");
1059 map<VuoRunner::Port *, json_object *> m;
1063 if (suggestedPixelsWide != self.previousSuggestedPixelsWide)
1066 self.previousSuggestedPixelsWide = suggestedPixelsWide;
1068 if (suggestedPixelsHigh != self.previousSuggestedPixelsHigh)
1071 self.previousSuggestedPixelsHigh = suggestedPixelsHigh;
1074 self.runner->setPublishedInputPortValues(m);
1077 self.changedPorts->insert(kv.first);
1078 json_object_put(kv.second);
1081 self.runner->firePublishedInputPortEvent(*self.changedPorts);
1082 self.changedPorts->clear();
1084 self.runner->waitForFiredPublishedInputPortEvent();
1101- (NSImage *)generateNSImageWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
1103 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1105 return [
self valueForOutputPort:@"outputImage"];
1120- (GLuint)generateGLTextureWithTarget:(GLuint)target suggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
1122 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1124 return [
self glTextureWithTarget:target forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh];
1152- (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
1154 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1156 return [
self glTextureFromProvider:provider forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh ioSurface:outputIOSurface];
1169- (
VuoImage)generateVuoImageWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
1171 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1175 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName(
"outputImage");
1179 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
1181 json_object_put(valueJson);