Vuo  2.0.2
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 State",
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
34 
39 typedef 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 
57 bool VuoRenderedLayers_getTransformedLayer2(VuoRenderedLayers_internal *rl, float localToWorldMatrix[16], VuoSceneObject targetObject, VuoPoint2d *layerCenter, VuoPoint2d layerCorners[4]);
58 
64 void 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 
195 bool 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 
213 void 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 
243 bool 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 
269 void 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 
308 bool 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 
317 bool 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);
356  VuoTransform_getMatrix(VuoSceneObject_getTransform(ancestorObject), matrix);
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);
380  VuoTransform_getMatrix(VuoSceneObject_getTransform(ancestorObject), matrix);
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 
398 bool 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 
420 VuoPoint3d 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 
436 bool 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 
562 bool 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 
584 bool 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 }
603 bool 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 
645 bool 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.;
687  if (VuoSceneObject_shouldTextScaleWithScene(targetObject))
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 
750 VuoPoint2d 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);
800 nan:
801  return (VuoRectangle){
802  (VuoPoint2d){NAN,NAN},
803  (VuoPoint2d){NAN,NAN}
804  };
805 }
806 
810 bool 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 
834 bool 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 
870 bool 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 
910 bool 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  VuoSceneObject rootSceneObject;
994  if (json_object_object_get_ex(js, "rootSceneObject", &o))
995  rootSceneObject = VuoSceneObject_makeFromJson(o);
996  else
997  rootSceneObject = NULL;
998 
999  VuoInteger pixelsWide = 0;
1000  if (json_object_object_get_ex(js, "pixelsWide", &o))
1001  pixelsWide = json_object_get_int64(o);
1002 
1003  VuoInteger pixelsHigh = 0;
1004  if (json_object_object_get_ex(js, "pixelsHigh", &o))
1005  pixelsHigh = json_object_get_int64(o);
1006 
1007  float backingScaleFactor = 1;
1008  if (json_object_object_get_ex(js, "backingScaleFactor", &o))
1009  backingScaleFactor = VuoReal_makeFromJson(o);
1010 
1011  VuoList_VuoInteraction interactions = NULL;
1012  if (json_object_object_get_ex(js, "interactions", &o))
1013  interactions = VuoList_VuoInteraction_makeFromJson(o);
1014 
1015  VuoRenderedLayers rl = VuoRenderedLayers_make(rootSceneObject, pixelsWide, pixelsHigh, backingScaleFactor, interactions);
1016 
1017  if (json_object_object_get_ex(js, "window", &o))
1019 
1020  return rl;
1021 }
1022 
1028 {
1029  VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
1030 
1031  json_object *js = json_object_new_object();
1032 
1033  json_object *rootSceneObjectObject = VuoSceneObject_getJson(rl->rootSceneObject);
1034  json_object_object_add(js, "rootSceneObject", rootSceneObjectObject);
1035 
1036  json_object *pixelsWideObject = json_object_new_int64(rl->pixelsWide);
1037  json_object_object_add(js, "pixelsWide", pixelsWideObject);
1038 
1039  json_object *pixelsHighObject = json_object_new_int64(rl->pixelsHigh);
1040  json_object_object_add(js, "pixelsHigh", pixelsHighObject);
1041 
1042  if (rl->hasWindow)
1043  {
1044  json_object *windowObject = VuoWindowReference_getJson(rl->window);
1045  json_object_object_add(js, "window", windowObject);
1046  }
1047 
1048  json_object *bsfObject = VuoReal_getJson(rl->backingScaleFactor);
1049  json_object_object_add(js, "backingScaleFactor", bsfObject);
1050 
1051  json_object *interactionObj = VuoList_VuoInteraction_getJson(rl->interactions);
1052  json_object_object_add(js, "interactions", interactionObj);
1053 
1054  return js;
1055 }
1056 
1062 {
1063  VuoRenderedLayers_internal *rl = (VuoRenderedLayers_internal *)renderedLayers;
1064 
1065  char *rootSummary = VuoSceneObject_getSummary(rl->rootSceneObject);
1066  char *windowSummary = VuoWindowReference_getSummary(rl->window);
1067 
1068  char *summary = VuoText_format("%lux%lu<br>%s<br>%s", rl->pixelsWide, rl->pixelsHigh, windowSummary, rootSummary);
1069 
1070  free(windowSummary);
1071  free(rootSummary);
1072 
1073  return summary;
1074 }