Vuo  2.4.0
VuoRenderedLayers.c
Go to the documentation of this file.
1
10#include "type.h"
11#include "VuoRenderedLayers.h"
12#include "VuoImageText.h"
13#include "VuoSceneText.h"
14
16#ifdef VUO_COMPILER
18 "title" : "Window",
19 "description" : "A set of layers, transformed to their final positions for rendering",
20 "keywords" : [ ],
21 "version" : "1.0.0",
22 "dependencies" : [
23 "VuoInteraction",
24 "VuoImageText",
25 "VuoRectangle",
26 "VuoSceneObject",
27 "VuoSceneText",
28 "VuoWindowReference",
29 "VuoList_VuoInteraction",
30 "VuoList_VuoSceneObject"
31 ]
32 });
33#endif
35
39typedef struct
40{
41 VuoList_VuoInteraction interactions;
42
43 VuoSceneObject rootSceneObject;
44
45 unsigned long int pixelsWide;
46 unsigned long int pixelsHigh;
47 float backingScaleFactor;
48 bool hasRenderingDimensions;
49
50 VuoWindowReference window;
51 bool hasWindow;
52} VuoRenderedLayers_internal;
53
57bool VuoRenderedLayers_getTransformedLayer2(VuoRenderedLayers_internal *rl, float localToWorldMatrix[16], VuoSceneObject targetObject, VuoPoint2d *layerCenter, VuoPoint2d layerCorners[4]);
58
64void VuoRenderedLayers_free(void *renderedLayers)
65{
66 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
67
68 VuoSceneObject_release(rl->rootSceneObject);
69 VuoRelease(rl->interactions);
70 VuoRelease(rl->window);
71
72 free(rl);
73}
74
75
82 unsigned long int pixelsWide,
83 unsigned long int pixelsHigh,
84 float backingScaleFactor,
85 VuoList_VuoInteraction interactions)
86{
87 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)VuoRenderedLayers_makeEmpty();
88
89 rl->rootSceneObject = rootSceneObject;
90 VuoSceneObject_retain(rl->rootSceneObject);
91
92 rl->pixelsWide = pixelsWide;
93 rl->pixelsHigh = pixelsHigh;
94 rl->backingScaleFactor = backingScaleFactor;
95 rl->hasRenderingDimensions = true;
96
97 rl->interactions = interactions;
98 VuoRetain(rl->interactions);
99
100 return (VuoRenderedLayers)rl;
101}
102
109 unsigned long int pixelsWide, unsigned long int pixelsHigh,
110 float backingScaleFactor,
111 VuoWindowReference window,
112 VuoList_VuoInteraction interactions)
113{
114 VuoRenderedLayers renderedLayers = VuoRenderedLayers_make(rootSceneObject, pixelsWide, pixelsHigh, backingScaleFactor, interactions);
115 VuoRenderedLayers_setWindow(renderedLayers, window);
116 return renderedLayers;
117}
118
124{
125 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)calloc(1, sizeof(VuoRenderedLayers_internal));
127
128 rl->backingScaleFactor = 1;
129
130 return (VuoRenderedLayers)rl;
131}
132
139{
140 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
141
142 if (rl->interactions)
143 VuoRelease(rl->interactions);
144
145 rl->interactions = interactions;
146 VuoRetain(rl->interactions);
147}
148
151{
152 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
153
154 VuoRelease(rl->rootSceneObject);
155
156 rl->rootSceneObject = rootSceneObject;
157 VuoRetain(rl->rootSceneObject);
158}
159
162{
163 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
164
165 if (rl->window)
166 VuoRelease(rl->window);
167
168 rl->hasWindow = true;
169 rl->window = window;
170 VuoRetain(rl->window);
171}
172
177{
178 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
179 return rl->interactions;
180}
181
186{
187 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
188 return rl->rootSceneObject;
189}
190
195bool VuoRenderedLayers_getRenderingDimensions(const VuoRenderedLayers renderedLayers, unsigned long int *pixelsWide, unsigned long int *pixelsHigh, float *backingScaleFactor)
196{
197 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
198
199 if (rl->hasRenderingDimensions)
200 {
201 *pixelsWide = rl->pixelsWide;
202 *pixelsHigh = rl->pixelsHigh;
203 *backingScaleFactor = rl->backingScaleFactor;
204 return true;
205 }
206
207 return false;
208}
209
213void VuoRenderedLayers_setRenderingDimensions(const VuoRenderedLayers renderedLayers, unsigned long int pixelsWide, unsigned long int pixelsHigh, float backingScaleFactor)
214{
215 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
216
217 rl->hasRenderingDimensions = true;
218 rl->pixelsWide = pixelsWide;
219 rl->pixelsHigh = pixelsHigh;
220 rl->backingScaleFactor = backingScaleFactor;
221}
222
228{
229 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
230
231 if (rl->hasWindow)
232 {
233 *window = rl->window;
234 return true;
235 }
236
237 return false;
238}
239
243bool VuoRenderedLayers_windowChanged(const VuoRenderedLayers accumulatedRenderedLayers, const VuoRenderedLayers newerRenderedLayers)
244{
245 VuoWindowReference window;
246 if (VuoRenderedLayers_getWindow(newerRenderedLayers, &window))
247 {
248 VuoWindowReference oldWindow;
249 bool hasWindow = VuoRenderedLayers_getWindow(accumulatedRenderedLayers, &oldWindow);
250 if (! hasWindow || oldWindow != window)
251 return true;
252 }
253
254 return false;
255}
256
269void VuoRenderedLayers_update(VuoRenderedLayers accumulatedRenderedLayers, const VuoRenderedLayers newerRenderedLayers,
270 bool *renderingDimensionsChanged)
271{
272 VuoRenderedLayers_internal *arl = (VuoRenderedLayers_internal *)accumulatedRenderedLayers;
273 VuoRenderedLayers_internal *nrl = (VuoRenderedLayers_internal *)newerRenderedLayers;
274
275 *renderingDimensionsChanged = false;
276
277 VuoRenderedLayers_setInteractions(accumulatedRenderedLayers, nrl->interactions);
278
279 VuoSceneObject rootSceneObject = VuoRenderedLayers_getRootSceneObject(newerRenderedLayers);
280 if (rootSceneObject)
281 VuoRenderedLayers_setRootSceneObject(accumulatedRenderedLayers, rootSceneObject);
282
283 VuoWindowReference window;
284 if (VuoRenderedLayers_getWindow(newerRenderedLayers, &window))
285 VuoRenderedLayers_setWindow(accumulatedRenderedLayers, window);
286
287 if (VuoRenderedLayers_getWindow(accumulatedRenderedLayers, &window))
288 {
289 VuoInteger pixelsWide;
290 VuoInteger pixelsHigh;
291 float backingScaleFactor;
292 VuoWindowReference_getContentSize(window, &pixelsWide, &pixelsHigh, &backingScaleFactor);
293
294 if (!arl->hasRenderingDimensions ||
295 arl->pixelsWide != pixelsWide || arl->pixelsHigh != pixelsHigh || arl->backingScaleFactor != backingScaleFactor)
296 *renderingDimensionsChanged = true;
297
298 arl->hasRenderingDimensions = true;
299 arl->pixelsWide = pixelsWide;
300 arl->pixelsHigh = pixelsHigh;
301 arl->backingScaleFactor = backingScaleFactor;
302 }
303}
304
308bool VuoRenderedLayers_findLayer(VuoRenderedLayers renderedLayers, VuoText layerName, VuoList_VuoSceneObject ancestorObjects, VuoSceneObject *foundObject)
309{
310 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
311 return VuoSceneObject_find(rl->rootSceneObject, layerName, ancestorObjects, foundObject);
312}
313
317bool VuoRenderedLayers_findLayerId(VuoRenderedLayers renderedLayers, uint64_t layerId, VuoList_VuoSceneObject ancestorObjects, VuoSceneObject *foundObject)
318{
319 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
320 return VuoSceneObject_findById(rl->rootSceneObject, layerId, ancestorObjects, foundObject);
321}
322
329 VuoList_VuoSceneObject ancestorObjects,
330 VuoSceneObject targetObject,
331 VuoPoint3d* layerCenter3d,
332 VuoPoint3d layerCorners3d[4],
333 bool applyTargetTransform)
334{
335 float matrix[16];
336 VuoPoint3d center = *layerCenter3d;
337 bool isText = VuoSceneObject_getType(targetObject) == VuoSceneObjectSubType_Text
338 && VuoSceneObject_getText(targetObject);
339
340 if (VuoSceneObject_isRealSize(targetObject) || (isText && !VuoSceneObject_shouldTextScaleWithScene(targetObject)))
341 {
342 // Real-size layer:
343 // Apply the layer's transformations to the center point.
344 unsigned long ancestorObjectCount = VuoListGetCount_VuoSceneObject(ancestorObjects);
345
346 // apply local transform first
347 if(applyTargetTransform)
348 {
350 center = VuoTransform_transformPoint(matrix, center);
351 }
352
353 for (unsigned long i = ancestorObjectCount; i >= 1; --i)
354 {
355 VuoSceneObject ancestorObject = VuoListGetValue_VuoSceneObject(ancestorObjects, i);
357 center = VuoTransform_transformPoint(matrix, center);
358 }
359 }
360 else
361 {
362 // Scaled layer:
363 // Apply the layer's transformations to each of its corner points.
364 unsigned long ancestorObjectCount = VuoListGetCount_VuoSceneObject(ancestorObjects);
365
366 // local transform first
367 if(applyTargetTransform)
368 {
370
371 for(int i = 0; i < 4; i++)
372 layerCorners3d[i] = VuoTransform_transformPoint(matrix, layerCorners3d[i]);
373
374 center = VuoTransform_transformPoint(matrix, center);
375 }
376
377 for (unsigned long i = ancestorObjectCount; i >= 1; --i)
378 {
379 VuoSceneObject ancestorObject = VuoListGetValue_VuoSceneObject(ancestorObjects, i);
381 if(layerCorners3d != NULL)
382 {
383 for (int i = 0; i < 4; ++i)
384 layerCorners3d[i] = VuoTransform_transformPoint(matrix, layerCorners3d[i]);
385 }
386 center = VuoTransform_transformPoint(matrix, center);
387 }
388 }
389
390 *layerCenter3d = center;
391}
392
398bool VuoRenderedLayers_getLayerCorners(const VuoSceneObject targetObject, VuoPoint3d layerCorners3d[4])
399{
400 VuoMesh mesh = VuoSceneObject_getMesh(targetObject);
401 if (!mesh)
402 return false;
403
404 unsigned int vertexCount;
405 float *positions;
406 VuoMesh_getCPUBuffers(mesh, &vertexCount, &positions, NULL, NULL, NULL, NULL, NULL);
407 if (vertexCount < 3)
408 return false;
409
410 // point3d because transformations are carried out using 3d transform functions
411 for (int i = 0; i < 4; ++i)
412 layerCorners3d[i] = VuoPoint3d_makeFromArray(&positions[i * 3]);
413
414 return true;
415}
416
420VuoPoint3d VuoRenderedLayers_getQuadCenter(VuoPoint3d layerCorners3d[4])
421{
422 VuoPoint3d c = layerCorners3d[0];
423
424 for(int i = 1; i < 4; i++)
425 {
426 c.x += layerCorners3d[i].x;
427 c.y += layerCorners3d[i].y;
428 }
429
430 return VuoPoint3d_multiply(c, .25);
431}
432
436bool VuoRenderedLayers_getRectRecursive(VuoRenderedLayers_internal *rl, float compositeMatrix[16], VuoSceneObject targetObject, VuoRectangle* rect, bool rectIsInitialized)
437{
438 bool foundRect = rectIsInitialized;
439 VuoPoint2d layerCenter;
440 VuoPoint2d layerCorners[4];
441
442 // apply targetObject transform
443 float localToWorldMatrix[16];
444 float modelMatrix[16];
445
446 VuoTransform_getMatrix(VuoSceneObject_getTransform(targetObject), modelMatrix);
447 VuoTransform_multiplyMatrices4x4(modelMatrix, compositeMatrix, localToWorldMatrix);
448
449 if (VuoRenderedLayers_getTransformedLayer2(rl, localToWorldMatrix, targetObject, &layerCenter, layerCorners) )
450 {
451 VuoRectangle thisRect = VuoRenderedLayers_getBoundingBox(layerCorners);
452
453 if(rectIsInitialized)
454 *rect = VuoRectangle_union(*rect, thisRect);
455 else
456 *rect = thisRect;
457
458 foundRect = true;
459 }
460
461 VuoList_VuoSceneObject childObjects = VuoSceneObject_getChildObjects(targetObject);
462 int children = VuoListGetCount_VuoSceneObject(childObjects);
463
464 for(int i = 1; i <= children; i++)
465 {
466 VuoSceneObject child = VuoListGetValue_VuoSceneObject(childObjects, i);
467
468 if( VuoRenderedLayers_getRectRecursive(rl, localToWorldMatrix, child, rect, foundRect) )
469 foundRect = true;
470 }
471
472 return foundRect;
473}
474
479{
480 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
481
482 float identity[16] = {
483 1, 0, 0, 0,
484 0, 1, 0, 0,
485 0, 0, 1, 0,
486 0, 0, 0, 1,
487 };
488
489 return VuoRenderedLayers_getRectRecursive(rl, identity, layer, rect, false);
490}
491
498 VuoRenderedLayers renderedLayers,
499 VuoList_VuoSceneObject ancestorObjects,
500 VuoSceneObject targetObject,
501 VuoPoint2d *layerCenter,
502 VuoPoint2d layerCorners[4],
503 bool includeChildrenInBounds)
504{
505 for (int i = 0; i < 4; ++i)
506 layerCorners[i] = (VuoPoint2d){NAN,NAN};
507
508 // Get the layer's corner points.
509 VuoPoint3d layerCorners3d[4];
510
511 if(includeChildrenInBounds)
512 {
513 VuoRectangle rect;
514
515 if(!VuoRenderedLayers_getRect(renderedLayers, targetObject, &rect))
516 return false;
517
518 VuoPoint2d c = rect.center;
519 VuoPoint2d e = VuoPoint2d_multiply(rect.size, .5);
520
521 layerCorners3d[0] = VuoPoint3d_make( c.x - e.x, c.y - e.y, 0. );
522 layerCorners3d[1] = VuoPoint3d_make( c.x + e.x, c.y - e.y, 0. );
523 layerCorners3d[2] = VuoPoint3d_make( c.x - e.x, c.y + e.y, 0. );
524 layerCorners3d[3] = VuoPoint3d_make( c.x + e.x, c.y + e.y, 0. );
525 }
526 else
527 {
528 if( !VuoRenderedLayers_getLayerCorners(targetObject, layerCorners3d) )
529 return false;
530 }
531
532 bool isText = VuoSceneObject_getType(targetObject) == VuoSceneObjectSubType_Text
533 && VuoSceneObject_getText(targetObject);
534
535 // if includeChildren is true VuoRenderedLayers_getRect will have already applied scale
536 VuoShader shader = VuoSceneObject_getShader(targetObject);
537 if (!includeChildrenInBounds && !isText && shader)
538 {
539 for (int i = 0; i < 4; ++i)
540 {
541 layerCorners3d[i].x *= shader->objectScale;
542 layerCorners3d[i].y *= shader->objectScale;
543 }
544 }
545
546 // Transform the layer to the rendered layers' coordinate space.
547 VuoPoint3d layerCenter3d = VuoRenderedLayers_getQuadCenter(layerCorners3d);
548
549 VuoRenderedLayers_applyTransforms(renderedLayers, ancestorObjects, targetObject, &layerCenter3d, layerCorners3d, !includeChildrenInBounds);
550
551 for (int i = 0; i < 4; ++i)
552 layerCorners[i] = VuoPoint2d_make(layerCorners3d[i].x, layerCorners3d[i].y);
553
554 *layerCenter = VuoPoint2d_make(layerCenter3d.x, layerCenter3d.y);
555
556 return true;
557}
558
562bool VuoRenderedLayers_getTransformedPoint(VuoRenderedLayers renderedLayers, VuoList_VuoSceneObject ancestorObjects, VuoSceneObject targetObject, VuoPoint2d point, VuoPoint2d *transformedPoint)
563{
564 VuoShader shader = VuoSceneObject_getShader(targetObject);
565 if (!shader)
566 return false;
567
568 VuoPoint3d tp = VuoPoint3d_make(point.x, point.y, 0);
569
570 tp.x *= shader->objectScale;
571 tp.y *= shader->objectScale;
572
573 // Transform the layer to the rendered layers' coordinate space.
574 VuoRenderedLayers_applyTransforms(renderedLayers, ancestorObjects, targetObject, &tp, NULL, true);
575
576 *transformedPoint = VuoPoint2d_make(tp.x, tp.y);
577
578 return true;
579}
580
584bool VuoRenderedLayers_getInverseTransformedPointLayer(VuoRenderedLayers renderedLayers, uint64_t targetLayer, VuoPoint2d point, VuoPoint2d* localPoint)
585{
587 VuoLocal(ancestors);
588 VuoSceneObject target;
589
590 if( VuoRenderedLayers_findLayerId(renderedLayers, targetLayer, ancestors, &target) )
591 {
593
594 if(VuoRenderedLayers_getInverseTransformedPoint(renderedLayers, ancestors, dummy, point, localPoint))
595 return true;
596 }
597
598 return false;
599}
603bool VuoRenderedLayers_getInverseTransformedPoint(VuoRenderedLayers renderedLayers, VuoList_VuoSceneObject ancestorObjects, VuoSceneObject targetObject, VuoPoint2d point, VuoPoint2d *inverseTransformedPoint)
604{
605 float localToWorldMatrix[16];
606 float tmp[16];
607 float modelMatrix[16];
608
609 // start off with the targetObject matrix, then work up
610 VuoTransform_getMatrix(VuoSceneObject_getTransform(targetObject), localToWorldMatrix);
611
612 int count = VuoListGetCount_VuoSceneObject(ancestorObjects);
613
614 for(int i = count; i > 0; i--)
615 {
616 // apply targetObject transform
617 VuoSceneObject node = VuoListGetValue_VuoSceneObject(ancestorObjects, i);
618
619 VuoTransform_copyMatrix4x4(localToWorldMatrix, tmp);
621 VuoTransform_multiplyMatrices4x4(modelMatrix, tmp, localToWorldMatrix);
622 }
623
624 float worldToLocalMatrix[16];
625 VuoTransform_invertMatrix4x4(localToWorldMatrix, worldToLocalMatrix);
626
627 VuoPoint3d point3d = VuoPoint3d_make(point.x, point.y, 0);
628 VuoPoint3d invPoint = VuoTransform_transformPoint(worldToLocalMatrix, point3d);
629
630 VuoShader shader = VuoSceneObject_getShader(targetObject);
631 if (shader)
632 {
633 invPoint.x /= shader->objectScale;
634 invPoint.y /= shader->objectScale;
635 }
636
637 *inverseTransformedPoint = VuoPoint2d_make(invPoint.x, invPoint.y);
638
639 return true;
640}
641
645bool VuoRenderedLayers_getTransformedLayer2(VuoRenderedLayers_internal *renderedLayers, float localToWorldMatrix[16], VuoSceneObject targetObject, VuoPoint2d *layerCenter, VuoPoint2d layerCorners[4])
646{
647 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
648
649 // Get the layer's corner points.
650 VuoPoint3d layerCorners3d[4];
651
652 if( !VuoRenderedLayers_getLayerCorners(targetObject, layerCorners3d) )
653 return false;
654
655 bool isText = VuoSceneObject_getType(targetObject) == VuoSceneObjectSubType_Text
656 && VuoSceneObject_getText(targetObject);
657
658 VuoShader shader = VuoSceneObject_getShader(targetObject);
659 if (!shader && !isText)
660 return false;
661
662 if(!isText)
663 {
664 for (int i = 0; i < 4; ++i)
665 {
666 layerCorners3d[i].x *= shader->objectScale;
667 layerCorners3d[i].y *= shader->objectScale;
668 }
669 }
670
671 // Transform the layer to the rendered layers' coordinate space.
672 VuoPoint3d center = VuoPoint3d_make(0,0,0);
673
674 if (VuoSceneObject_isRealSize(targetObject) || isText)
675 {
676 // Real-size layer:
677 // Apply the layer's transformations to the center point.
678 center = VuoTransform_transformPoint(localToWorldMatrix, center);
679
680 float widthScale = 1, heightScale = 1;
681
682 // Scale the layer's corner points to the rendered layers' coordinate space.
683 if(isText)
684 {
685 float verticalScale = 1.;
686 float rotationZ = 0.;
688 {
689 VuoTransform transform = VuoTransform_makeFromMatrix4x4(localToWorldMatrix);
690 widthScale = transform.scale.x;
691 verticalScale = transform.scale.y / transform.scale.x;
692 rotationZ = VuoTransform_getEuler(transform).z;
693 }
694
695 VuoPoint2d size = VuoRenderedLayers_getTextSize((VuoRenderedLayers)renderedLayers, VuoSceneObject_getText(targetObject), VuoSceneObject_getTextFont(targetObject), VuoSceneObject_shouldTextScaleWithScene(targetObject), verticalScale, rotationZ, VuoSceneObject_getTextWrapWidth(targetObject), true);
696
697 center.xy += VuoSceneText_getAnchorOffset(targetObject, verticalScale, rotationZ, VuoSceneObject_getTextWrapWidth(targetObject),
698 VuoSceneObject_shouldTextScaleWithScene(targetObject) ? VuoGraphicsWindowDefaultWidth * rl->backingScaleFactor : rl->pixelsWide,
699 rl->backingScaleFactor);
700
701 widthScale *= size.x;
702 heightScale *= size.y;
703 }
704 else
705 {
706 VuoImage image = VuoShader_getUniform_VuoImage(shader, "texture");
707
708 widthScale = 2. * (float)image->pixelsWide / rl->pixelsWide;
709 heightScale = widthScale * (float)image->pixelsHigh / (float)image->pixelsWide;
710
711 VuoReal combinedScaleFactor = 1;
712
714 combinedScaleFactor = rl->backingScaleFactor / image->scaleFactor;
715
716 widthScale *= combinedScaleFactor;
717 heightScale *= combinedScaleFactor;
718 }
719
720 for (int i = 0; i < 4; ++i)
721 {
722 layerCorners3d[i].x *= widthScale;
723 layerCorners3d[i].y *= heightScale;
724
725 layerCorners3d[i].x += center.x;
726 layerCorners3d[i].y += center.y;
727 }
728 }
729 else
730 {
731 // Scaled layer:
732 // Apply the layer's transformations to each of its corner points.
733 for (int i = 0; i < 4; ++i)
734 layerCorners3d[i] = VuoTransform_transformPoint(localToWorldMatrix, layerCorners3d[i]);
735
736 center = VuoTransform_transformPoint(localToWorldMatrix, center);
737 }
738
739 for (int i = 0; i < 4; ++i)
740 layerCorners[i] = VuoPoint2d_make(layerCorners3d[i].x, layerCorners3d[i].y);
741
742 *layerCenter = VuoPoint2d_make(center.x, center.y);
743
744 return true;
745}
746
750VuoPoint2d VuoRenderedLayers_getTextSize(VuoRenderedLayers renderedLayers, VuoText text, VuoFont font, bool scaleWithScene, float verticalScale, float rotationZ, float wrapWidth, bool includeTrailingWhiteSpace)
751{
752 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
753
754 // If we don't know the size of the render destination,
755 // we can't calculate the size of real-size text.
756 if (!scaleWithScene && (rl->pixelsWide < 1 || rl->pixelsHigh < 1))
757 return VuoPoint2d_make(0, 0);
758
759 VuoRectangle textBounds = VuoImage_getTextRectangle(text, font, rl->backingScaleFactor, verticalScale, rotationZ, wrapWidth, includeTrailingWhiteSpace);
760
761 float w = textBounds.size.x;
762 float h = textBounds.size.y;
763
764 VuoPoint2d size;
765 if (scaleWithScene)
766 size.x = (w / (float)(VuoGraphicsWindowDefaultWidth * rl->backingScaleFactor)) * 2;
767 else
768 size.x = (w / (float)rl->pixelsWide) * 2;
769 size.y = size.x * (h / w);
770
771 return size;
772}
773
778{
779 VuoPoint2d min = VuoPoint2d_make( INFINITY, INFINITY);
780 VuoPoint2d max = VuoPoint2d_make(-INFINITY, -INFINITY);
781 for (int i = 0; i < 4; ++i)
782 {
783 if (isnan(layerCorners[i].x) || isnan(layerCorners[i].y))
784 goto nan;
785
786 if (layerCorners[i].x < min.x)
787 min.x = layerCorners[i].x;
788 if (layerCorners[i].x > max.x)
789 max.x = layerCorners[i].x;
790 if (layerCorners[i].y < min.y)
791 min.y = layerCorners[i].y;
792 if (layerCorners[i].y > max.y)
793 max.y = layerCorners[i].y;
794 }
795 return VuoRectangle_make(
796 min.x + (max.x-min.x)/2.,
797 min.y + (max.y-min.y)/2.,
798 max.x-min.x,
799 max.y-min.y);
800nan:
801 return (VuoRectangle){
802 (VuoPoint2d){NAN,NAN},
803 (VuoPoint2d){NAN,NAN}
804 };
805}
806
810bool VuoRenderedLayers_isPointInQuad(VuoPoint2d corners[4], VuoPoint2d point)
811{
812 // Split the quad into two triangles with points specified counter-clockwise, and check each triangle.
813 // https://stackoverflow.com/questions/2049582/how-to-determine-a-point-in-a-triangle
814 VuoPoint2d triangles[] = { corners[0], corners[1], corners[2],
815 corners[3], corners[2], corners[1] };
816 for (int i = 0; i < 2; ++i)
817 {
818 VuoPoint2d p0 = triangles[3*i];
819 VuoPoint2d p1 = triangles[3*i+1];
820 VuoPoint2d p2 = triangles[3*i+2];
821 float area = 1./2.*(-p1.y*p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);
822 float s = 1./(2.*area)*(p0.y*p2.x - p0.x*p2.y + (p2.y - p0.y)*point.x + (p0.x - p2.x)*point.y);
823 float t = 1./(2.*area)*(p0.x*p1.y - p0.y*p1.x + (p0.y - p1.y)*point.x + (p1.x - p0.x)*point.y);
824 if (s >= 0 && t >= 0 && s + t <= 1)
825 return true;
826 }
827
828 return false;
829}
830
834bool VuoRenderedLayers_isPointInLayerRecursive(VuoRenderedLayers_internal *rl, float compositeMatrix[16], VuoSceneObject targetObject, VuoPoint2d point)
835{
836 VuoPoint2d layerCenter;
837 VuoPoint2d layerCorners[4];
838
839 // apply targetObject transform
840 float localToWorldMatrix[16];
841 float modelMatrix[16];
842
843 VuoTransform_getMatrix(VuoSceneObject_getTransform(targetObject), modelMatrix);
844 VuoTransform_multiplyMatrices4x4(modelMatrix, compositeMatrix, localToWorldMatrix);
845
846 if (VuoRenderedLayers_getTransformedLayer2(rl, localToWorldMatrix, targetObject, &layerCenter, layerCorners))
847 {
848 if( VuoRenderedLayers_isPointInQuad(layerCorners, point) )
849 return true;
850 }
851
852 VuoList_VuoSceneObject childObjects = VuoSceneObject_getChildObjects(targetObject);
853 int children = VuoListGetCount_VuoSceneObject(childObjects);
854
855 for(int i = 1; i <= children; i++)
856 {
857 VuoSceneObject child = VuoListGetValue_VuoSceneObject(childObjects, i);
858 if( VuoRenderedLayers_isPointInLayerRecursive(rl, localToWorldMatrix, child, point) )
859 return true;
860 }
861
862 return false;
863}
864
870bool VuoRenderedLayers_isPointInLayer(VuoRenderedLayers renderedLayers, VuoText layerName, VuoPoint2d point)
871{
872 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
873
874 float aspect = (double)rl->pixelsHigh / rl->pixelsWide;
875
876 if( point.x < -1 || point.x > 1 || point.y < -aspect || point.y > aspect )
877 return false;
878
879 VuoSceneObject layer;
881 VuoLocal(ancestors);
882
883 if(!VuoRenderedLayers_findLayer(renderedLayers, layerName, ancestors, &layer))
884 return false;
885
886 float modelMatrix[16], tmp[16];
887 float composite[16] = {
888 1, 0, 0, 0,
889 0, 1, 0, 0,
890 0, 0, 1, 0,
891 0, 0, 0, 1,
892 };
893
894 for(int i = 1; i <= VuoListGetCount_VuoSceneObject(ancestors); i++)
895 {
898 VuoTransform_multiplyMatrices4x4(modelMatrix, composite, tmp);
899 VuoTransform_copyMatrix4x4(tmp, composite);
900 }
901
902 return VuoRenderedLayers_isPointInLayerRecursive(rl, composite, layer, point);
903}
904
910bool VuoRenderedLayers_isPointInLayerId(VuoRenderedLayers renderedLayers, uint64_t layerId, VuoPoint2d point)
911{
912 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
913
914 float aspect = (double)rl->pixelsHigh / rl->pixelsWide;
915
916 if( point.x < -1 || point.x > 1 || point.y < -aspect || point.y > aspect )
917 return false;
918
919 VuoSceneObject layer;
921 VuoLocal(ancestors);
922
923 if (!VuoSceneObject_findById(rl->rootSceneObject, layerId, ancestors, &layer))
924 return false;
925
926 float modelMatrix[16], tmp[16];
927 float composite[16] = {
928 1, 0, 0, 0,
929 0, 1, 0, 0,
930 0, 0, 1, 0,
931 0, 0, 0, 1,
932 };
933
934 for(int i = 1; i <= VuoListGetCount_VuoSceneObject(ancestors); i++)
935 {
938 VuoTransform_multiplyMatrices4x4(modelMatrix, composite, tmp);
939 VuoTransform_copyMatrix4x4(tmp, composite);
940 }
941
942 return VuoRenderedLayers_isPointInLayerRecursive(rl, composite, layer, point);
943}
944
949 uint64_t id,
950 bool *anyHover,
951 bool *anyPressed,
952 bool *anyReleased,
953 bool *anyClicked)
954{
955 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
956
957 *anyHover = false;
958 *anyPressed = false;
959 *anyReleased = false;
960 *anyClicked = false;
961
962 if (rl->interactions == NULL || VuoListGetCount_VuoInteraction(rl->interactions) < 1)
963 return;
964
965 for (int i = 1; i <= VuoListGetCount_VuoInteraction(rl->interactions); i++)
966 {
967 VuoInteraction it = VuoListGetValue_VuoInteraction(rl->interactions, i);
968
969 if( VuoRenderedLayers_isPointInLayerId(renderedLayers, id, it.position) )
970 {
971 *anyHover = true;
972
973 if(it.isPressed)
974 *anyPressed = true;
975
976 if( it.type == VuoInteractionType_Click )
977 *anyClicked = true;
978
979 if( it.type == VuoInteractionType_Release )
980 *anyReleased = true;
981 }
982 }
983}
984
990{
991 json_object *o = NULL;
992
993 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)VuoRenderedLayers_makeEmpty();
994
995 if (json_object_object_get_ex(js, "rootSceneObject", &o))
996 {
997 rl->rootSceneObject = VuoSceneObject_makeFromJson(o);
998 VuoSceneObject_retain(rl->rootSceneObject);
999 }
1000
1001 if (json_object_object_get_ex(js, "pixelsWide", &o))
1002 rl->pixelsWide = json_object_get_int64(o);
1003
1004 if (json_object_object_get_ex(js, "pixelsHigh", &o))
1005 rl->pixelsHigh = json_object_get_int64(o);
1006
1007 if (rl->pixelsWide && rl->pixelsHigh)
1008 rl->hasRenderingDimensions = true;
1009
1010 if (json_object_object_get_ex(js, "backingScaleFactor", &o))
1011 rl->backingScaleFactor = VuoReal_makeFromJson(o);
1012
1013 if (json_object_object_get_ex(js, "interactions", &o))
1014 {
1015 rl->interactions = VuoList_VuoInteraction_makeFromJson(o);
1016 VuoRetain(rl->interactions);
1017 }
1018
1019 if (json_object_object_get_ex(js, "window", &o))
1020 {
1021 rl->hasWindow = true;
1022 rl->window = VuoWindowReference_makeFromJson(o);
1023 VuoRetain(rl->window);
1024 }
1025
1026 return (VuoRenderedLayers)rl;
1027}
1028
1034{
1035 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
1036
1037 json_object *js = json_object_new_object();
1038
1039 if (VuoSceneObject_isPopulated(rl->rootSceneObject))
1040 {
1041 json_object *rootSceneObjectObject = VuoSceneObject_getJson(rl->rootSceneObject);
1042 json_object_object_add(js, "rootSceneObject", rootSceneObjectObject);
1043 }
1044
1045 if (rl->hasRenderingDimensions)
1046 {
1047 json_object *pixelsWideObject = json_object_new_int64(rl->pixelsWide);
1048 json_object_object_add(js, "pixelsWide", pixelsWideObject);
1049
1050 json_object *pixelsHighObject = json_object_new_int64(rl->pixelsHigh);
1051 json_object_object_add(js, "pixelsHigh", pixelsHighObject);
1052
1053 json_object *bsfObject = VuoReal_getJson(rl->backingScaleFactor);
1054 json_object_object_add(js, "backingScaleFactor", bsfObject);
1055 }
1056
1057 if (rl->hasWindow)
1058 {
1059 json_object *windowObject = VuoWindowReference_getJson(rl->window);
1060 json_object_object_add(js, "window", windowObject);
1061 }
1062
1063 if (rl->interactions)
1064 {
1065 json_object *interactionObj = VuoList_VuoInteraction_getJson(rl->interactions);
1066 json_object_object_add(js, "interactions", interactionObj);
1067 }
1068
1069 return js;
1070}
1071
1077{
1078 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
1079
1080 char *windowSummary = NULL;
1081 if (rl->hasWindow)
1082 windowSummary = VuoText_format("<p>%s</p>", VuoWindowReference_getSummary(rl->window));
1083
1084 char *sizeSummary = NULL;
1085 if (rl->hasRenderingDimensions)
1086 sizeSummary = VuoText_format("<p>Size: %luĂ—%lu @ %gx</p>", rl->pixelsWide, rl->pixelsHigh, rl->backingScaleFactor);
1087
1088 char *layersSummary = NULL;
1089 if (VuoSceneObject_isPopulated(rl->rootSceneObject))
1090 layersSummary = VuoText_format("<p>%s</p>", VuoSceneObject_getSummary(rl->rootSceneObject));
1091
1092 char *summary = VuoText_format("%s%s%s",
1093 windowSummary ? windowSummary : "",
1094 sizeSummary ? sizeSummary : "",
1095 layersSummary ? layersSummary : "");
1096
1097 free(windowSummary);
1098 free(sizeSummary);
1099 free(layersSummary);
1100
1101 return summary;
1102}