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