Vuo 2.4.2
Loading...
Searching...
No Matches
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, bool includeChildrenInBounds, 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 if (includeChildrenInBounds)
462 {
463 VuoList_VuoSceneObject childObjects = VuoSceneObject_getChildObjects(targetObject);
464 int children = VuoListGetCount_VuoSceneObject(childObjects);
465
466 for(int i = 1; i <= children; i++)
467 {
468 VuoSceneObject child = VuoListGetValue_VuoSceneObject(childObjects, i);
469
470 if (VuoRenderedLayers_getRectRecursive(rl, localToWorldMatrix, child, true, rect, foundRect))
471 foundRect = true;
472 }
473 }
474
475 return foundRect;
476}
477
481bool VuoRenderedLayers_getRect(VuoRenderedLayers renderedLayers, VuoSceneObject layer, bool includeChildrenInBounds, VuoRectangle *rect)
482{
483 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
484
485 float identity[16] = {
486 1, 0, 0, 0,
487 0, 1, 0, 0,
488 0, 0, 1, 0,
489 0, 0, 0, 1,
490 };
491
492 return VuoRenderedLayers_getRectRecursive(rl, identity, layer, includeChildrenInBounds, rect, false);
493}
494
501 VuoRenderedLayers renderedLayers,
502 VuoList_VuoSceneObject ancestorObjects,
503 VuoSceneObject targetObject,
504 VuoPoint2d *layerCenter,
505 VuoPoint2d layerCorners[4],
506 bool includeChildrenInBounds)
507{
508 for (int i = 0; i < 4; ++i)
509 layerCorners[i] = (VuoPoint2d){NAN,NAN};
510
511 // Get the layer's corner points.
512 VuoPoint3d layerCorners3d[4];
513
514 VuoRectangle rect;
515
516 if(!VuoRenderedLayers_getRect(renderedLayers, targetObject, includeChildrenInBounds, &rect))
517 return false;
518
519 VuoPoint2d c = rect.center;
520 VuoPoint2d e = VuoPoint2d_multiply(rect.size, .5);
521
522 layerCorners3d[0] = VuoPoint3d_make( c.x - e.x, c.y - e.y, 0. );
523 layerCorners3d[1] = VuoPoint3d_make( c.x + e.x, c.y - e.y, 0. );
524 layerCorners3d[2] = VuoPoint3d_make( c.x - e.x, c.y + e.y, 0. );
525 layerCorners3d[3] = VuoPoint3d_make( c.x + e.x, c.y + e.y, 0. );
526
527 // Transform the layer to the rendered layers' coordinate space.
528 VuoPoint3d layerCenter3d = VuoRenderedLayers_getQuadCenter(layerCorners3d);
529
530 VuoRenderedLayers_applyTransforms(renderedLayers, ancestorObjects, targetObject, &layerCenter3d, layerCorners3d, false);
531
532 for (int i = 0; i < 4; ++i)
533 layerCorners[i] = VuoPoint2d_make(layerCorners3d[i].x, layerCorners3d[i].y);
534
535 *layerCenter = VuoPoint2d_make(layerCenter3d.x, layerCenter3d.y);
536
537 return true;
538}
539
543bool VuoRenderedLayers_getTransformedPoint(VuoRenderedLayers renderedLayers, VuoList_VuoSceneObject ancestorObjects, VuoSceneObject targetObject, VuoPoint2d point, VuoPoint2d *transformedPoint)
544{
545 VuoShader shader = VuoSceneObject_getShader(targetObject);
546 if (!shader)
547 return false;
548
549 VuoPoint3d tp = VuoPoint3d_make(point.x, point.y, 0);
550
551 tp.x *= shader->objectScale;
552 tp.y *= shader->objectScale;
553
554 // Transform the layer to the rendered layers' coordinate space.
555 VuoRenderedLayers_applyTransforms(renderedLayers, ancestorObjects, targetObject, &tp, NULL, true);
556
557 *transformedPoint = VuoPoint2d_make(tp.x, tp.y);
558
559 return true;
560}
561
565bool VuoRenderedLayers_getInverseTransformedPointLayer(VuoRenderedLayers renderedLayers, uint64_t targetLayer, VuoPoint2d point, VuoPoint2d* localPoint)
566{
568 VuoLocal(ancestors);
569 VuoSceneObject target;
570
571 if( VuoRenderedLayers_findLayerId(renderedLayers, targetLayer, ancestors, &target) )
572 {
574
575 if(VuoRenderedLayers_getInverseTransformedPoint(renderedLayers, ancestors, dummy, point, localPoint))
576 return true;
577 }
578
579 return false;
580}
584bool VuoRenderedLayers_getInverseTransformedPoint(VuoRenderedLayers renderedLayers, VuoList_VuoSceneObject ancestorObjects, VuoSceneObject targetObject, VuoPoint2d point, VuoPoint2d *inverseTransformedPoint)
585{
586 float localToWorldMatrix[16];
587 float tmp[16];
588 float modelMatrix[16];
589
590 // start off with the targetObject matrix, then work up
591 VuoTransform_getMatrix(VuoSceneObject_getTransform(targetObject), localToWorldMatrix);
592
593 int count = VuoListGetCount_VuoSceneObject(ancestorObjects);
594
595 for(int i = count; i > 0; i--)
596 {
597 // apply targetObject transform
598 VuoSceneObject node = VuoListGetValue_VuoSceneObject(ancestorObjects, i);
599
600 VuoTransform_copyMatrix4x4(localToWorldMatrix, tmp);
602 VuoTransform_multiplyMatrices4x4(modelMatrix, tmp, localToWorldMatrix);
603 }
604
605 float worldToLocalMatrix[16];
606 VuoTransform_invertMatrix4x4(localToWorldMatrix, worldToLocalMatrix);
607
608 VuoPoint3d point3d = VuoPoint3d_make(point.x, point.y, 0);
609 VuoPoint3d invPoint = VuoTransform_transformPoint(worldToLocalMatrix, point3d);
610
611 VuoShader shader = VuoSceneObject_getShader(targetObject);
612 if (shader)
613 {
614 invPoint.x /= shader->objectScale;
615 invPoint.y /= shader->objectScale;
616 }
617
618 *inverseTransformedPoint = VuoPoint2d_make(invPoint.x, invPoint.y);
619
620 return true;
621}
622
626bool VuoRenderedLayers_getTransformedLayer2(VuoRenderedLayers_internal *renderedLayers, float localToWorldMatrix[16], VuoSceneObject targetObject, VuoPoint2d *layerCenter, VuoPoint2d layerCorners[4])
627{
628 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
629
630 // Get the layer's corner points.
631 VuoPoint3d layerCorners3d[4];
632
633 if( !VuoRenderedLayers_getLayerCorners(targetObject, layerCorners3d) )
634 return false;
635
636 bool isText = VuoSceneObject_getType(targetObject) == VuoSceneObjectSubType_Text
637 && VuoSceneObject_getText(targetObject);
638
639 VuoShader shader = VuoSceneObject_getShader(targetObject);
640 if (!shader && !isText)
641 return false;
642
643 if(!isText)
644 {
645 for (int i = 0; i < 4; ++i)
646 {
647 layerCorners3d[i].x *= shader->objectScale;
648 layerCorners3d[i].y *= shader->objectScale;
649 }
650 }
651
652 // Transform the layer to the rendered layers' coordinate space.
653 VuoPoint3d center = VuoPoint3d_make(0,0,0);
654
655 if (VuoSceneObject_isRealSize(targetObject) || isText)
656 {
657 // Real-size layer:
658 // Apply the layer's transformations to the center point.
659 center = VuoTransform_transformPoint(localToWorldMatrix, center);
660
661 float widthScale = 1, heightScale = 1;
662
663 // Scale the layer's corner points to the rendered layers' coordinate space.
664 if(isText)
665 {
666 float verticalScale = 1.;
667 float rotationZ = 0.;
669 {
670 VuoTransform transform = VuoTransform_makeFromMatrix4x4(localToWorldMatrix);
671 widthScale = transform.scale.x;
672 verticalScale = transform.scale.y / transform.scale.x;
673 rotationZ = VuoTransform_getEuler(transform).z;
674 }
675
676 VuoPoint2d size = VuoRenderedLayers_getTextSize((VuoRenderedLayers)renderedLayers, VuoSceneObject_getText(targetObject), VuoSceneObject_getTextFont(targetObject), VuoSceneObject_shouldTextScaleWithScene(targetObject), verticalScale, rotationZ, VuoSceneObject_getTextWrapWidth(targetObject), true);
677
678 center.xy += VuoSceneText_getAnchorOffset(targetObject, verticalScale, rotationZ, VuoSceneObject_getTextWrapWidth(targetObject),
679 VuoSceneObject_shouldTextScaleWithScene(targetObject) ? VuoGraphicsWindowDefaultWidth * rl->backingScaleFactor : rl->pixelsWide,
680 rl->backingScaleFactor);
681
682 widthScale *= size.x;
683 heightScale *= size.y;
684 }
685 else
686 {
687 VuoImage image = VuoShader_getUniform_VuoImage(shader, "texture");
688
689 widthScale = 2. * (float)image->pixelsWide / rl->pixelsWide;
690 heightScale = widthScale * (float)image->pixelsHigh / (float)image->pixelsWide;
691
692 VuoReal combinedScaleFactor = 1;
693
695 combinedScaleFactor = rl->backingScaleFactor / image->scaleFactor;
696
697 widthScale *= combinedScaleFactor;
698 heightScale *= combinedScaleFactor;
699 }
700
701 for (int i = 0; i < 4; ++i)
702 {
703 layerCorners3d[i].x *= widthScale;
704 layerCorners3d[i].y *= heightScale;
705
706 layerCorners3d[i].x += center.x;
707 layerCorners3d[i].y += center.y;
708 }
709 }
710 else
711 {
712 // Scaled layer:
713 // Apply the layer's transformations to each of its corner points.
714 for (int i = 0; i < 4; ++i)
715 layerCorners3d[i] = VuoTransform_transformPoint(localToWorldMatrix, layerCorners3d[i]);
716
717 center = VuoTransform_transformPoint(localToWorldMatrix, center);
718 }
719
720 for (int i = 0; i < 4; ++i)
721 layerCorners[i] = VuoPoint2d_make(layerCorners3d[i].x, layerCorners3d[i].y);
722
723 *layerCenter = VuoPoint2d_make(center.x, center.y);
724
725 return true;
726}
727
731VuoPoint2d VuoRenderedLayers_getTextSize(VuoRenderedLayers renderedLayers, VuoText text, VuoFont font, bool scaleWithScene, float verticalScale, float rotationZ, float wrapWidth, bool includeTrailingWhiteSpace)
732{
733 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
734
735 // If we don't know the size of the render destination,
736 // we can't calculate the size of real-size text.
737 if (!scaleWithScene && (rl->pixelsWide < 1 || rl->pixelsHigh < 1))
738 return VuoPoint2d_make(0, 0);
739
740 VuoRectangle textBounds = VuoImage_getTextRectangle(text, font, rl->backingScaleFactor, verticalScale, rotationZ, wrapWidth, includeTrailingWhiteSpace);
741
742 float w = textBounds.size.x;
743 float h = textBounds.size.y;
744
745 VuoPoint2d size;
746 if (scaleWithScene)
747 size.x = (w / (float)(VuoGraphicsWindowDefaultWidth * rl->backingScaleFactor)) * 2;
748 else
749 size.x = (w / (float)rl->pixelsWide) * 2;
750 size.y = size.x * (h / w);
751
752 return size;
753}
754
759{
760 VuoPoint2d min = VuoPoint2d_make( INFINITY, INFINITY);
761 VuoPoint2d max = VuoPoint2d_make(-INFINITY, -INFINITY);
762 for (int i = 0; i < 4; ++i)
763 {
764 if (isnan(layerCorners[i].x) || isnan(layerCorners[i].y))
765 goto nan;
766
767 if (layerCorners[i].x < min.x)
768 min.x = layerCorners[i].x;
769 if (layerCorners[i].x > max.x)
770 max.x = layerCorners[i].x;
771 if (layerCorners[i].y < min.y)
772 min.y = layerCorners[i].y;
773 if (layerCorners[i].y > max.y)
774 max.y = layerCorners[i].y;
775 }
776 return VuoRectangle_make(
777 min.x + (max.x-min.x)/2.,
778 min.y + (max.y-min.y)/2.,
779 max.x-min.x,
780 max.y-min.y);
781nan:
782 return (VuoRectangle){
783 (VuoPoint2d){NAN,NAN},
784 (VuoPoint2d){NAN,NAN}
785 };
786}
787
791bool VuoRenderedLayers_isPointInQuad(VuoPoint2d corners[4], VuoPoint2d point)
792{
793 // Split the quad into two triangles with points specified counter-clockwise, and check each triangle.
794 // https://stackoverflow.com/questions/2049582/how-to-determine-a-point-in-a-triangle
795 VuoPoint2d triangles[] = { corners[0], corners[1], corners[2],
796 corners[3], corners[2], corners[1] };
797 for (int i = 0; i < 2; ++i)
798 {
799 VuoPoint2d p0 = triangles[3*i];
800 VuoPoint2d p1 = triangles[3*i+1];
801 VuoPoint2d p2 = triangles[3*i+2];
802 float area = 1./2.*(-p1.y*p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);
803 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);
804 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);
805 if (s >= 0 && t >= 0 && s + t <= 1)
806 return true;
807 }
808
809 return false;
810}
811
815bool VuoRenderedLayers_isPointInLayerRecursive(VuoRenderedLayers_internal *rl, float compositeMatrix[16], VuoSceneObject targetObject, VuoPoint2d point)
816{
817 VuoPoint2d layerCenter;
818 VuoPoint2d layerCorners[4];
819
820 // apply targetObject transform
821 float localToWorldMatrix[16];
822 float modelMatrix[16];
823
824 VuoTransform_getMatrix(VuoSceneObject_getTransform(targetObject), modelMatrix);
825 VuoTransform_multiplyMatrices4x4(modelMatrix, compositeMatrix, localToWorldMatrix);
826
827 if (VuoRenderedLayers_getTransformedLayer2(rl, localToWorldMatrix, targetObject, &layerCenter, layerCorners))
828 {
829 if( VuoRenderedLayers_isPointInQuad(layerCorners, point) )
830 return true;
831 }
832
833 VuoList_VuoSceneObject childObjects = VuoSceneObject_getChildObjects(targetObject);
834 int children = VuoListGetCount_VuoSceneObject(childObjects);
835
836 for(int i = 1; i <= children; i++)
837 {
838 VuoSceneObject child = VuoListGetValue_VuoSceneObject(childObjects, i);
839 if( VuoRenderedLayers_isPointInLayerRecursive(rl, localToWorldMatrix, child, point) )
840 return true;
841 }
842
843 return false;
844}
845
851bool VuoRenderedLayers_isPointInLayer(VuoRenderedLayers renderedLayers, VuoText layerName, VuoPoint2d point)
852{
853 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
854
855 float aspect = (double)rl->pixelsHigh / rl->pixelsWide;
856
857 if( point.x < -1 || point.x > 1 || point.y < -aspect || point.y > aspect )
858 return false;
859
860 VuoSceneObject layer;
862 VuoLocal(ancestors);
863
864 if(!VuoRenderedLayers_findLayer(renderedLayers, layerName, ancestors, &layer))
865 return false;
866
867 float modelMatrix[16], tmp[16];
868 float composite[16] = {
869 1, 0, 0, 0,
870 0, 1, 0, 0,
871 0, 0, 1, 0,
872 0, 0, 0, 1,
873 };
874
875 for(int i = 1; i <= VuoListGetCount_VuoSceneObject(ancestors); i++)
876 {
879 VuoTransform_multiplyMatrices4x4(modelMatrix, composite, tmp);
880 VuoTransform_copyMatrix4x4(tmp, composite);
881 }
882
883 return VuoRenderedLayers_isPointInLayerRecursive(rl, composite, layer, point);
884}
885
891bool VuoRenderedLayers_isPointInLayerId(VuoRenderedLayers renderedLayers, uint64_t layerId, VuoPoint2d point)
892{
893 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
894
895 float aspect = (double)rl->pixelsHigh / rl->pixelsWide;
896
897 if( point.x < -1 || point.x > 1 || point.y < -aspect || point.y > aspect )
898 return false;
899
900 VuoSceneObject layer;
902 VuoLocal(ancestors);
903
904 if (!VuoSceneObject_findById(rl->rootSceneObject, layerId, ancestors, &layer))
905 return false;
906
907 float modelMatrix[16], tmp[16];
908 float composite[16] = {
909 1, 0, 0, 0,
910 0, 1, 0, 0,
911 0, 0, 1, 0,
912 0, 0, 0, 1,
913 };
914
915 for(int i = 1; i <= VuoListGetCount_VuoSceneObject(ancestors); i++)
916 {
919 VuoTransform_multiplyMatrices4x4(modelMatrix, composite, tmp);
920 VuoTransform_copyMatrix4x4(tmp, composite);
921 }
922
923 return VuoRenderedLayers_isPointInLayerRecursive(rl, composite, layer, point);
924}
925
930 uint64_t id,
931 bool *anyHover,
932 bool *anyPressed,
933 bool *anyReleased,
934 bool *anyClicked)
935{
936 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
937
938 *anyHover = false;
939 *anyPressed = false;
940 *anyReleased = false;
941 *anyClicked = false;
942
943 if (rl->interactions == NULL || VuoListGetCount_VuoInteraction(rl->interactions) < 1)
944 return;
945
946 for (int i = 1; i <= VuoListGetCount_VuoInteraction(rl->interactions); i++)
947 {
948 VuoInteraction it = VuoListGetValue_VuoInteraction(rl->interactions, i);
949
950 if( VuoRenderedLayers_isPointInLayerId(renderedLayers, id, it.position) )
951 {
952 *anyHover = true;
953
954 if(it.isPressed)
955 *anyPressed = true;
956
957 if( it.type == VuoInteractionType_Click )
958 *anyClicked = true;
959
960 if( it.type == VuoInteractionType_Release )
961 *anyReleased = true;
962 }
963 }
964}
965
971{
972 json_object *o = NULL;
973
974 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)VuoRenderedLayers_makeEmpty();
975
976 if (json_object_object_get_ex(js, "rootSceneObject", &o))
977 {
978 rl->rootSceneObject = VuoSceneObject_makeFromJson(o);
979 VuoSceneObject_retain(rl->rootSceneObject);
980 }
981
982 if (json_object_object_get_ex(js, "pixelsWide", &o))
983 rl->pixelsWide = json_object_get_int64(o);
984
985 if (json_object_object_get_ex(js, "pixelsHigh", &o))
986 rl->pixelsHigh = json_object_get_int64(o);
987
988 if (rl->pixelsWide && rl->pixelsHigh)
989 rl->hasRenderingDimensions = true;
990
991 if (json_object_object_get_ex(js, "backingScaleFactor", &o))
992 rl->backingScaleFactor = VuoReal_makeFromJson(o);
993
994 if (json_object_object_get_ex(js, "interactions", &o))
995 {
996 rl->interactions = VuoList_VuoInteraction_makeFromJson(o);
997 VuoRetain(rl->interactions);
998 }
999
1000 if (json_object_object_get_ex(js, "window", &o))
1001 {
1002 rl->hasWindow = true;
1003 rl->window = VuoWindowReference_makeFromJson(o);
1004 VuoRetain(rl->window);
1005 }
1006
1007 return (VuoRenderedLayers)rl;
1008}
1009
1015{
1016 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
1017
1018 json_object *js = json_object_new_object();
1019
1020 if (VuoSceneObject_isPopulated(rl->rootSceneObject))
1021 {
1022 json_object *rootSceneObjectObject = VuoSceneObject_getJson(rl->rootSceneObject);
1023 json_object_object_add(js, "rootSceneObject", rootSceneObjectObject);
1024 }
1025
1026 if (rl->hasRenderingDimensions)
1027 {
1028 json_object *pixelsWideObject = json_object_new_int64(rl->pixelsWide);
1029 json_object_object_add(js, "pixelsWide", pixelsWideObject);
1030
1031 json_object *pixelsHighObject = json_object_new_int64(rl->pixelsHigh);
1032 json_object_object_add(js, "pixelsHigh", pixelsHighObject);
1033
1034 json_object *bsfObject = VuoReal_getJson(rl->backingScaleFactor);
1035 json_object_object_add(js, "backingScaleFactor", bsfObject);
1036 }
1037
1038 if (rl->hasWindow)
1039 {
1040 json_object *windowObject = VuoWindowReference_getJson(rl->window);
1041 json_object_object_add(js, "window", windowObject);
1042 }
1043
1044 if (rl->interactions)
1045 {
1046 json_object *interactionObj = VuoList_VuoInteraction_getJson(rl->interactions);
1047 json_object_object_add(js, "interactions", interactionObj);
1048 }
1049
1050 return js;
1051}
1052
1058{
1059 VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
1060
1061 char *windowSummary = NULL;
1062 if (rl->hasWindow)
1063 windowSummary = VuoText_format("<p>%s</p>", VuoWindowReference_getSummary(rl->window));
1064
1065 char *sizeSummary = NULL;
1066 if (rl->hasRenderingDimensions)
1067 sizeSummary = VuoText_format("<p>Size: %luĂ—%lu @ %gx</p>", rl->pixelsWide, rl->pixelsHigh, rl->backingScaleFactor);
1068
1069 char *layersSummary = NULL;
1070 if (VuoSceneObject_isPopulated(rl->rootSceneObject))
1071 layersSummary = VuoText_format("<p>%s</p>", VuoSceneObject_getSummary(rl->rootSceneObject));
1072
1073 char *summary = VuoText_format("%s%s%s",
1074 windowSummary ? windowSummary : "",
1075 sizeSummary ? sizeSummary : "",
1076 layersSummary ? layersSummary : "");
1077
1078 free(windowSummary);
1079 free(sizeSummary);
1080 free(layersSummary);
1081
1082 return summary;
1083}