Vuo 2.4.4
Loading...
Searching...
No Matches
VuoRunnerCocoa.mm
Go to the documentation of this file.
1
10#include "VuoRunnerCocoa.h"
12
13#include <OpenGL/CGLMacro.h>
15#include <QuartzCore/CoreImage.h>
16
17#include <dispatch/dispatch.h>
18
19#include <zmq/zmq.h>
20#include <vector>
21#include <set>
22#include "VuoRunner.hh"
23#include "VuoCompiler.hh"
24#include "VuoCompilerIssue.hh"
25#include "VuoComposition.hh"
27#include "VuoException.hh"
28#include "VuoProtocol.hh"
29#include "VuoHeap.h"
30#include "VuoGlContext.h"
31#include "VuoGlPool.h"
32
33extern "C" {
34#include "VuoInteger.h"
35#include "VuoImageGet.h"
36}
37
39
43@interface VuoRunnerCocoa ()
44@property dispatch_queue_t runnerQueue;
45@property VuoRunner *runner;
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;
53@property VuoProtocol *protocol;
54@property set<VuoRunner::Port *> *changedPorts;
55@end
56
57@implementation VuoRunnerCocoa
58@synthesize runnerQueue;
59@synthesize runner;
60@synthesize compositionURL;
61@synthesize compositionString;
62@synthesize compositionSourcePath;
63@synthesize compositionProcessName;
64@synthesize compositionName;
65@synthesize compositionDescription;
66@synthesize compositionCopyright;
67@synthesize protocol;
68@synthesize changedPorts;
69
82+ (void)setGlobalRootContext:(CGLContextObj)context
83{
85}
86
94+ (void)prepareModuleCaches
95{
96 @synchronized(self)
97 {
99 {
100 VuoCompiler c;
103 }
104 }
105}
106
112+ (BOOL)isComposition:(NSURL *)compositionURL compliantWithProtocol:(VuoProtocol *)protocol
113{
114 VuoRunnerCocoa *runner = [[VuoRunnerCocoa alloc] initWithComposition:compositionURL protocol:protocol];
115 if (!runner)
116 return NO;
117
118 [runner release];
119 return YES;
120}
121
127+ (BOOL)isCompositionString:(NSString *)compositionString compliantWithProtocol:(VuoProtocol *)protocol
128{
129 VuoRunnerCocoa *runner = [[VuoRunnerCocoa alloc] initWithCompositionString:compositionString name:@"" sourcePath:nil protocol:protocol];
130 if (!runner)
131 return NO;
132
133 [runner release];
134 return YES;
135}
136
142- (id)initWithComposition:(NSURL *)theCompositionURL protocol:(VuoProtocol *)theProtocol
143{
144 NSError *error;
145 NSString *s = [NSString stringWithContentsOfURL:theCompositionURL encoding:NSUTF8StringEncoding error:&error];
146 if (!s)
147 {
148 NSLog(@"[VuoRunnerCocoa initWithComposition:protocol:] Error reading composition: %@", error);
149 [self release];
150 return nil;
151 }
152
153 self = [self initWithCompositionString:s name:[theCompositionURL lastPathComponent] sourcePath:nil protocol:theProtocol];
154 if (!self)
155 return nil;
156
157 self.compositionURL = theCompositionURL;
158
159 return self;
160}
161
167- (id)initWithCompositionString:(NSString *)theCompositionString name:(NSString *)processName sourcePath:(NSString *)sourcePath protocol:(VuoProtocol *)theProtocol
168{
169 if (!(self = [super init]))
170 return nil;
171
172 self.protocol = theProtocol;
173
174 self.runnerQueue = dispatch_queue_create("org.vuo.runner.cocoa", NULL);
175 self.runner = NULL;
176
177 self.compositionString = theCompositionString;
178 const char *compositionCString = [self.compositionString UTF8String];
179 if (!theProtocol->isCompositionCompliant(compositionCString))
180 {
181 [self release];
182 return nil;
183 }
184
185 self.compositionProcessName = processName;
186 self.compositionSourcePath = sourcePath;
187
188 VuoCompositionMetadata metadata(compositionCString);
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()];
192
193 self.changedPorts = new set<VuoRunner::Port *>();
194
195 return self;
196}
197
203- (void)dealloc
204{
205 dispatch_sync(self.runnerQueue, ^{
206 if (self.runner)
207 {
208 self.runner->stop();
209 delete self.runner;
210 }
211 });
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;
220 [super dealloc];
221}
222
223- (void)compileAndRun
224{
225 [VuoRunnerCocoa prepareModuleCaches];
226
227 dispatch_sync(self.runnerQueue, ^{
228 VuoCompilerIssues issues;
229 if (self.compositionURL)
230 self.runner = VuoCompiler::newSeparateProcessRunnerFromCompositionFile(
231 [[self.compositionURL path] UTF8String],
232 &issues);
233 else
234 self.runner = VuoCompiler::newSeparateProcessRunnerFromCompositionString(
235 [self.compositionString UTF8String],
236 [self.compositionProcessName UTF8String],
237 [self.compositionSourcePath UTF8String],
238 &issues);
239
240 if (!issues.isEmpty())
241 VUserLog("%s", issues.getLongDescription(false).c_str());
242
243 if (self.runner)
244 {
245 self.runner->start();
246 self.runner->subscribeToEventTelemetry("");
247
248 try
249 {
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(); });
253 }
254 catch (VuoException &e)
255 {
256 VUserLog("Error: %s", e.what());
257 }
258 }
259 });
260}
261
268{
269 __block BOOL isStopped = YES;
270 dispatch_sync(self.runnerQueue, ^{
271 if (self.runner && !self.runner->isStopped())
272 isStopped = NO;
273 });
274 return isStopped;
275}
276
282- (NSString *)description
283{
284 return [NSString stringWithFormat:@"VuoRunnerCocoa(%c%@%c)", '"', compositionName, '"'];
285}
286
293- (NSArray *)inputPorts
294{
295 if ([self isStopped])
296 return nil;
297
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()]];
303 return portsArray;
304}
305
312- (NSArray *)outputPorts
313{
314 if ([self isStopped])
315 return nil;
316
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()]];
322 return portsArray;
323}
324
356- (NSDictionary *)detailsForPort:(NSString *)portName
357{
358 const char *portNameCString = [portName UTF8String];
359 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName(portNameCString);
360 if (!port)
361 {
362 port = self.runner->getPublishedOutputPortWithName(portNameCString);
363 if (!port)
364 return nil;
365 }
366
367 NSMutableDictionary *details = [[NSMutableDictionary new] autorelease];
368
369 details[@"title"] = [NSString stringWithUTF8String:port->getName().c_str()];
370
371 details[@"type"] = [NSString stringWithUTF8String:port->getType().c_str()];
372
373 json_object *js = port->getDetails();
374 if (js)
375 {
376 json_object *o = NULL;
377
378 if (json_object_object_get_ex(js, "default", &o))
379 {
380 id cocoaObject = [VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
381 if (cocoaObject)
382 details[@"default"] = cocoaObject;
383 }
384
385 if (json_object_object_get_ex(js, "suggestedMin", &o))
386 {
387 id cocoaObject = [VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
388 if (cocoaObject)
389 details[@"suggestedMin"] = cocoaObject;
390 }
391
392 if (json_object_object_get_ex(js, "suggestedMax", &o))
393 {
394 id cocoaObject = [VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
395 if (cocoaObject)
396 details[@"suggestedMax"] = cocoaObject;
397 }
398
399 if (json_object_object_get_ex(js, "suggestedStep", &o))
400 {
401 id cocoaObject = [VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
402 if (cocoaObject)
403 details[@"suggestedStep"] = cocoaObject;
404 }
405
406 if (json_object_object_get_ex(js, "menuItems", &o))
407 {
408 NSMutableArray *menuItems = [NSMutableArray new];
409
410 int itemCount = json_object_array_length(o);
411 for (int i = 0; i < itemCount; ++i)
412 {
413 json_object *item = json_object_array_get_idx(o, i);
414 id menuItem = nil;
415
416 if (json_object_is_type(item, json_type_object))
417 {
418 json_object *value;
419 json_object_object_get_ex(item, "value", &value);
420 json_object *name;
421 json_object_object_get_ex(item, "name", &name);
422
423 id valueNS = nil;
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)];
428
429 const char *summary = json_object_get_string(name);
430 menuItem = @{
431 @"value": valueNS,
432 @"name": [NSString stringWithUTF8String:summary],
433 };
434 }
435 else if (json_object_is_type(item, json_type_string))
436 menuItem = [NSString stringWithUTF8String:json_object_get_string(item)];
437
438 if (menuItem)
439 [menuItems addObject:menuItem];
440 }
441
442 details[@"menuItems"] = menuItems;
443 [menuItems release];
444 }
445 }
446
447 return details;
448}
449
455- (id)propertyListFromInputValues
456{
457 if ([self isStopped])
458 return nil;
459
460 NSMutableDictionary *properties = [[NSMutableDictionary new] autorelease];
461
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()))
465 {
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];
469 }
470
471 return properties;
472}
473
482- (BOOL)setInputValuesWithPropertyList:(id)propertyList
483{
484 if ([self isStopped])
485 return NO;
486
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]);
491 if (!port)
492 {
493 ok = NO;
494 return;
495 }
496
497 json_object *valueJson = json_tokener_parse([value UTF8String]);
498 if (!valueJson)
499 {
500 ok = NO;
501 return;
502 }
503
504 m[port] = valueJson;
505 }];
506
508
509 for (auto &kv : m)
510 {
511 self.changedPorts->insert(kv.first);
512 json_object_put(kv.second);
513 }
514
515 return ok;
516}
517
535- (BOOL)setInputValues:(NSDictionary *)namesAndValues
536{
537 if ([self isStopped])
538 return NO;
539
540 BOOL ok = YES;
541 map<VuoRunner::Port *, json_object *> m;
542 for (NSString *portName in namesAndValues)
543 {
544 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName([portName UTF8String]);
545 if (!port)
546 {
547 ok = NO;
548 continue;
549 }
550
551 id value = namesAndValues[portName];
552 json_object *valueJson = [VuoRunnerCocoa vuoValueWithCocoaObject:value];
553 if (!valueJson)
554 {
555 ok = NO;
556 continue;
557 }
558
559 m[port] = valueJson;
560 }
561
562 self.runner->setPublishedInputPortValues(m);
563
564 for (auto &kv : m)
565 {
566 self.changedPorts->insert(kv.first);
567 json_object_put(kv.second);
568 }
569
570 return ok;
571}
572
582- (BOOL)setInputJSON:(NSDictionary *)namesAndJSON
583{
584 if ([self isStopped])
585 return NO;
586
587 BOOL ok = YES;
588 map<VuoRunner::Port *, json_object *> m;
589 for (NSString *portName in namesAndJSON)
590 {
591 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName([portName UTF8String]);
592 if (!port)
593 {
594 ok = NO;
595 continue;
596 }
597
598 id nsValue = namesAndJSON[portName];
599 json_object *value = (json_object *)[nsValue pointerValue];
600
601 // If we're feeding a string to a VuoImage port, assume it's an image URL, and try to load it.
602 if (port->getType() == "VuoImage")
603 {
604 if (json_object_get_type(value) == json_type_string)
605 {
606 char *s = strdup(json_object_get_string(value));
607 VuoImage image = VuoImage_get(s);
608 if (!image)
609 {
610 NSLog(@"Error: Couldn't load image '%s'.\n", s);
611 free(s);
612 ok = NO;
613 continue;
614 }
615 free(s);
616
617 m[port] = VuoImage_getInterprocessJson(image);
618 }
619 }
620 else
621 m[port] = value;
622 }
623
624 self.runner->setPublishedInputPortValues(m);
625
626 for (auto &kv : m)
627 self.changedPorts->insert(kv.first);
628
629 return ok;
630}
631
651- (id)valueForOutputPort:(NSString *)portName
652{
653 if ([self isStopped])
654 return nil;
655
656 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName([portName UTF8String]);
657 if (!port)
658 return nil;
659
660 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
661 return [VuoRunnerCocoa cocoaObjectWithVuoValue:valueJson ofType:port->getType()];
662}
663
675- (GLuint)glTextureWithTarget:(GLuint)target forOutputPort:(NSString *)portName outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
676{
677 if ([self isStopped])
678 return 0;
679
680 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName([portName UTF8String]);
681 if (!port)
682 return 0;
683
684 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
685 VuoImage vuoImage = VuoImage_makeFromJson(valueJson);
686 if (!vuoImage)
687 return 0;
688 json_object_put(valueJson);
689
690 if (target == GL_TEXTURE_RECTANGLE_ARB)
691 {
692 VuoRetain(vuoImage);
693 VuoImage newVuoImage = VuoImage_makeGlTextureRectangleCopy(vuoImage);
694 VuoRelease(vuoImage);
695 vuoImage = newVuoImage;
696 }
697
698 if (outputPixelsWide)
699 *outputPixelsWide = vuoImage->pixelsWide;
700 if (outputPixelsHigh)
701 *outputPixelsHigh = vuoImage->pixelsHigh;
702
703 VuoGlTexture_disown(vuoImage->glTextureName);
704
705 return vuoImage->glTextureName;
706}
707
729- (GLuint)glTextureFromProvider:(GLuint (^)(NSUInteger pixelsWide, NSUInteger pixelsHigh))provider forOutputPort:(NSString *)portName outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh ioSurface:(IOSurfaceRef *)outputIOSurface
730{
731 if ([self isStopped])
732 return 0;
733
734 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName([portName UTF8String]);
735 if (!port)
736 return 0;
737
738 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
739
740 GLuint (^provider2)(unsigned int, unsigned int) = ^GLuint(unsigned int pixelsWide, unsigned int pixelsHigh){
741 return provider(pixelsWide, pixelsHigh);
742 };
743 unsigned int outputPixelsWide2, outputPixelsHigh2;
744 GLuint outputTexture = VuoImage_resolveInterprocessJsonUsingTextureProvider(valueJson, provider2, &outputPixelsWide2, &outputPixelsHigh2, outputIOSurface);
745 *outputPixelsWide = outputPixelsWide2;
746 *outputPixelsHigh = outputPixelsHigh2;
747 return outputTexture;
748}
749
750@end
751
752
753@implementation VuoImageFilter
759+ (BOOL)canOpenComposition:(NSURL *)compositionURL
760{
761 return [self isComposition:compositionURL compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)];
762}
763
769+ (BOOL)canOpenCompositionString:(NSString *)compositionString
770{
771 return [self isCompositionString:compositionString compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)];
772}
773
782- (id)initWithComposition:(NSURL *)aCompositionURL
783{
784 if (!(self = [super initWithComposition:aCompositionURL protocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)]))
785 return nil;
786
787 [self compileAndRun];
788 if (! self.runner)
789 return nil;
790
791 return self;
792}
793
803- (id)initWithCompositionString:(NSString *)aCompositionString name:(NSString *)name sourcePath:(NSString *)sourcePath
804{
805 if (!(self = [super initWithCompositionString:aCompositionString name:name sourcePath:sourcePath protocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)]))
806 return nil;
807
808 [self compileAndRun];
809 if (! self.runner)
810 return nil;
811
812 return self;
813}
814
818static void VuoRunnerCocoa_doNothingCallback(VuoImage imageToFree)
819{
820}
821
827- (BOOL)executeWithGLTexture:(GLuint)textureName target:(GLuint)target pixelsWide:(unsigned long)pixelsWide pixelsHigh:(unsigned long)pixelsHigh atTime:(NSTimeInterval)time
828{
829 if ([self isStopped])
830 return NO;
831
832 {
833 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName("image");
834 VuoImage image = VuoImage_makeClientOwned(textureName, GL_RGBA, pixelsWide, pixelsHigh, VuoRunnerCocoa_doNothingCallback, NULL);
835 image->glTextureTarget = target;
836 VuoRetain(image);
837 json_object *valueJson = VuoImage_getInterprocessJson(image);
838 VuoRelease(image);
839 map<VuoRunner::Port *, json_object *> m;
840 m[port] = valueJson;
841 self.runner->setPublishedInputPortValues(m);
842 json_object_put(valueJson);
843
844 self.changedPorts->insert(port);
845 }
846
847 return [self executeAtTime:time];
848}
849
855- (BOOL)executeAtTime:(NSTimeInterval)time
856{
857 if ([self isStopped])
858 return NO;
859
860 VuoRunner::Port *timePort = self.runner->getPublishedInputPortWithName("time");
861
862 {
863 json_object *valueJson = VuoReal_getJson(time);
864 map<VuoRunner::Port *, json_object *> m;
865 m[timePort] = valueJson;
866 self.runner->setPublishedInputPortValues(m);
867 json_object_put(valueJson);
868
869 self.changedPorts->insert(timePort);
870 }
871
872 self.runner->firePublishedInputPortEvent(*self.changedPorts);
873 self.changedPorts->clear();
874
875 self.runner->waitForFiredPublishedInputPortEvent();
876 return YES;
877}
878
894- (NSImage *)filterNSImage:(NSImage *)image atTime:(NSTimeInterval)time
895{
896 [self setInputValues:@{@"image":image}];
897
898 if (![self executeAtTime:time])
899 return nil;
900
901 return [self valueForOutputPort:@"outputImage"];
902}
903
920- (GLuint)filterGLTexture:(GLuint)textureName target:(GLuint)target pixelsWide:(NSUInteger)pixelsWide pixelsHigh:(NSUInteger)pixelsHigh atTime:(NSTimeInterval)time outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
921{
922 if (![self executeWithGLTexture:textureName target:target pixelsWide:pixelsWide pixelsHigh:pixelsHigh atTime:time])
923 return 0;
924 return [self glTextureWithTarget:target forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh];
925}
926
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
959{
960 if (![self executeWithGLTexture:textureName target:target pixelsWide:pixelsWide pixelsHigh:pixelsHigh atTime:time])
961 return 0;
962
963 return [self glTextureFromProvider:provider forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh ioSurface:outputIOSurface];
964}
965
966@end
967
968
972@interface VuoImageGenerator ()
973@property NSUInteger previousSuggestedPixelsWide;
974@property NSUInteger previousSuggestedPixelsHigh;
975@end
976
977@implementation VuoImageGenerator
978@synthesize previousSuggestedPixelsWide;
979@synthesize previousSuggestedPixelsHigh;
980
986+ (BOOL)canOpenComposition:(NSURL *)compositionURL
987{
988 return [self isComposition:compositionURL compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)];
989}
990
996+ (BOOL)canOpenCompositionString:(NSString *)compositionString
997{
998 return [self isCompositionString:compositionString compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)];
999}
1000
1009- (id)initWithComposition:(NSURL *)aCompositionURL
1010{
1011 if (!(self = [super initWithComposition:aCompositionURL protocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)]))
1012 return nil;
1013
1014 [self compileAndRun];
1015 if (! self.runner)
1016 return nil;
1017
1018 self.previousSuggestedPixelsWide = NSUIntegerMax;
1019 self.previousSuggestedPixelsHigh = NSUIntegerMax;
1020
1021 return self;
1022}
1023
1033- (id)initWithCompositionString:(NSString *)aCompositionString name:(NSString *)name sourcePath:(NSString *)sourcePath
1034{
1035 if (!(self = [super initWithCompositionString:aCompositionString name:name sourcePath:sourcePath protocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)]))
1036 return nil;
1037
1038 [self compileAndRun];
1039 if (! self.runner)
1040 return nil;
1041
1042 return self;
1043}
1044
1050- (BOOL)executeWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
1051{
1052 if ([self isStopped])
1053 return NO;
1054
1055 VuoRunner::Port *timePort = self.runner->getPublishedInputPortWithName("time");
1056 VuoRunner::Port *widthPort = self.runner->getPublishedInputPortWithName("width");
1057 VuoRunner::Port *heightPort = self.runner->getPublishedInputPortWithName("height");
1058
1059 map<VuoRunner::Port *, json_object *> m;
1060
1061 m[timePort] = VuoReal_getJson(time);
1062
1063 if (suggestedPixelsWide != self.previousSuggestedPixelsWide)
1064 {
1065 m[widthPort] = VuoInteger_getJson(suggestedPixelsWide);
1066 self.previousSuggestedPixelsWide = suggestedPixelsWide;
1067 }
1068 if (suggestedPixelsHigh != self.previousSuggestedPixelsHigh)
1069 {
1070 m[heightPort] = VuoInteger_getJson(suggestedPixelsHigh);
1071 self.previousSuggestedPixelsHigh = suggestedPixelsHigh;
1072 }
1073
1074 self.runner->setPublishedInputPortValues(m);
1075 for (auto &kv : m)
1076 {
1077 self.changedPorts->insert(kv.first);
1078 json_object_put(kv.second);
1079 }
1080
1081 self.runner->firePublishedInputPortEvent(*self.changedPorts);
1082 self.changedPorts->clear();
1083
1084 self.runner->waitForFiredPublishedInputPortEvent();
1085 return YES;
1086}
1087
1101- (NSImage *)generateNSImageWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
1102{
1103 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1104 return nil;
1105 return [self valueForOutputPort:@"outputImage"];
1106}
1107
1120- (GLuint)generateGLTextureWithTarget:(GLuint)target suggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
1121{
1122 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1123 return 0;
1124 return [self glTextureWithTarget:target forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh];
1125}
1126
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
1153{
1154 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1155 return 0;
1156 return [self glTextureFromProvider:provider forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh ioSurface:outputIOSurface];
1157}
1158
1169- (VuoImage)generateVuoImageWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
1170{
1171 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1172 return NULL;
1173
1174
1175 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName("outputImage");
1176 if (!port)
1177 return NULL;
1178
1179 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
1180 VuoImage image = VuoImage_makeFromJson(valueJson);
1181 json_object_put(valueJson);
1182
1183 return image;
1184}
1185
1186@end