IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
Platform.cs
1 using UnityEngine;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.IO;
5 
6 public class Platform : MonoBehaviour {
7 
8  public GameObject rectBase;
9  public GameObject front;
10  public GameObject left;
11  public GameObject right;
12  public GameObject frontLeft;
13  public GameObject frontRight;
14  public GameObject rounded;
15  public GameObject chair;
16  public GameObject footPrints;
17 
18  public GameObject mainCamera;
19  public Camera UICamera;
20 
21  public Material UiMeshMaterial;
22 
23  public static Platform instance { private set; get; }
24 
25  public GameObject UIMesh { private set; get; }
26 
27  float initialBaseWidth;
28  float initialBaseDepth;
29 
30  [Tooltip("Radius of the rounded mesh")]
31  public float UIMeshRoundedRadius = 1.2f;
32  [Tooltip("Opening angle in degrees")]
33  public float UIMeshRoundedAngle = 180f;
34  [Tooltip("Length of the rounded mesh sides")]
35  public float UIMeshRoundedSideLength = 0.3f;
36  [Tooltip("Distance from platform to bottom of the UI")]
37  public float UIMeshRoundedBottom = 0.35f;
38  [Tooltip("Height of the UI")]
39  public float UIMeshRoundedHeight = 2.0f;
40  [Tooltip("Distance from platform to bottom of the UI")]
41  public float UIMeshRectangularBottom = 0.75f;
42  [Tooltip("Height of the UI")]
43  public float UIMeshRectangularHeight = 2.0f;
44  [Tooltip("Radius of corners of rectangular mesh")]
45  public float UIMeshRectangularRadius = 0.425f;
46 
47  public GameObject viveRig;
48 
50  private float ratioRounded;
52  private float ratioSide;
54  private float ratioFront;
55 
57  private float rectWidth;
59  private float rectDepth;
60 
61  private Dictionary<UI.Screen, GameObject> screenCenters = new Dictionary<UI.Screen, GameObject>();
62 
63  public Platform()
64  {
65  instance = this;
66  }
67 
68  void Awake () {
69  resetDimensions ();
70 
71  // Remember the dimensions of the base:
72  initialBaseWidth = rectBase.GetComponent<Renderer>().bounds.size.x;
73  initialBaseDepth = rectBase.GetComponent<Renderer>().bounds.size.z;
74 
75  if (viveRig.activeInHierarchy) {
76  // Default values:
77  float width = 3f;
78  float depth = 2f;
79  // Try to get the room size from the mesh:
80  SteamVR_PlayArea playArea = viveRig.GetComponent<SteamVR_PlayArea>();
81  Debug.Log ("Steam play area: " + playArea);
82  if (playArea != null) {
84  if (SteamVR_PlayArea.GetBounds (playArea.size, ref rect)) {
85  var corners = new Valve.VR.HmdVector3_t[] { rect.vCorners0, rect.vCorners1, rect.vCorners2, rect.vCorners3 };
86 
87  Vector2 min = new Vector2 (float.MaxValue, float.MaxValue);
88  Vector2 max = new Vector2 (float.MinValue, float.MinValue);
89  for (int i = 0; i < corners.Length; i++)
90  {
91  if (corners [i].v0 < min.x)
92  min.x = corners [i].v0;
93  if (corners [i].v2 < min.y)
94  min.y = corners [i].v2;
95 
96  if (corners [i].v0 > max.x)
97  max.x = corners [i].v0;
98  if (corners [i].v2 > max.y)
99  max.y = corners [i].v2;
100  }
101  Debug.Log ("Steam play area bounds: " + min + " - " + max);
102 
103  Vector2 size = max - min;
104  width = size.x;
105  depth = size.y;
106  }
107  }
108  /*Mesh roomMesh = viveRig.GetComponent<MeshFilter>().mesh;
109  if (roomMesh != null) {
110  width = roomMesh.bounds.size.x;
111  depth = roomMesh.bounds.size.z;
112  SteamVR_PlayArea playArea.
113  Debug.Log ("Room mesh found. Setting room size to " + width + "x" + depth + "m.");
114  }*/
115  setRectangular (width, depth);
116  } else {
117  setRounded ();
118  }
119  }
120 
123  void setDimensions( float width, float depth )
124  {
125  float sideWidth = left.GetComponent<Renderer>().bounds.size.x;
126  float frontDepth = front.GetComponent<Renderer>().bounds.size.z;
127 
128  float newBaseWidth = (width - 2f*sideWidth) / initialBaseWidth;
129  float newBaseDepth = (depth - frontDepth) / initialBaseDepth;
130 
131  rectBase.transform.localScale = new Vector3 ( newBaseWidth, newBaseDepth, 1f );
132 
133  // Figure out where to put the front part:
134  Vector3 pos = front.transform.localPosition;
135  pos.z = depth - frontDepth - initialBaseDepth;//front.transform.localPosition.y + (depth - currentY);
136  front.transform.localPosition = pos;
137  // Figure out where to put left and right parts:
138  pos = right.transform.localPosition;
139  pos.x = (width - initialBaseWidth)*0.5f - sideWidth;//front.transform.localPosition.y + (depth - currentY);
140  left.transform.localPosition = -pos;
141  right.transform.localPosition = pos;
142 
143  left.transform.localScale = new Vector3 ( 1f, newBaseDepth, 1f );
144  right.transform.localScale = new Vector3 ( 1f, newBaseDepth, 1f );
145  front.transform.localScale = new Vector3 ( newBaseWidth, 1f, 1f );
146 
147  frontLeft.transform.localPosition = new Vector3 (-pos.x, 0, depth - frontDepth - initialBaseDepth);
148  frontRight.transform.localPosition = new Vector3 (pos.x, 0, depth - frontDepth - initialBaseDepth);
149 
150  mainCamera.transform.localPosition = new Vector3 (0f, 0f, depth * 0.5f);
151 
152  footPrints.transform.localPosition = new Vector3 (0f, 0.01f, depth * 0.5f - 0.15f);
153 
154  rectWidth = width;
155  rectDepth = depth;
156  }
157  void resetDimensions()
158  {
159  Vector3 origScale = new Vector3(1,1,1);
160  rectBase.transform.localScale = origScale;
161  front.transform.localScale = origScale;
162  left.transform.localScale = origScale;
163  right.transform.localScale = origScale;
164  frontLeft.transform.localScale = origScale;
165  frontRight.transform.localScale = origScale;
166  }
167 
169  void setRounded()
170  {
171  // Deactivate all parts of the rectangular platform:
172  front.SetActive (false);
173  left.SetActive (false);
174  right.SetActive (false);
175  frontLeft.SetActive (false);
176  frontRight.SetActive (false);
177  footPrints.SetActive (false);
178 
179  // Activate the rounded platform:
180  rounded.SetActive (true);
181  chair.SetActive (true);
182  chair.transform.localPosition = new Vector3 (0f, 0f, initialBaseDepth * 0.75f);
183  mainCamera.transform.localPosition = new Vector3 (0f, 0f, initialBaseDepth * 0.75f);
184 
185  resetDimensions (); // make sure base platform has the correct size
186  generateUIMeshRounded ();
187  }
188 
190  void setRectangular( float width, float depth )
191  {
192  // Activate all parts of the rectangular platform:
193  front.SetActive (true);
194  left.SetActive (true);
195  right.SetActive (true);
196  frontLeft.SetActive (true);
197  frontRight.SetActive (true);
198  footPrints.SetActive (true);
199 
200  // Deactivate the rounded platform:
201  rounded.SetActive (false);
202  chair.SetActive (false);
203 
204  setDimensions (width, depth);
205  generateUIMeshRectangular (width, depth);
206  }
207 
208 
210  void generateUIMeshRounded()
211  {
212  removeUIMesh ();
213 
214  // First, initialize lists:
215  List<Vector3> newVertices = new List<Vector3> ();
216  List<Vector2> newUV = new List<Vector2> ();
217  List<int> newTriangles = new List<int> ();
218 
219  float fullSize = 2f*UIMeshRoundedSideLength + Mathf.PI*UIMeshRoundedRadius;
220 
221  // what percentage of the whole mesh is rounded (as opposed to straight):
222  ratioRounded = Mathf.PI*UIMeshRoundedRadius / fullSize;
223  ratioSide = UIMeshRoundedSideLength / fullSize;
224 
225  float fullAngle = UIMeshRoundedAngle * Mathf.PI / 180f;
226 
227  // Start with first straight segment:
228  float angle = - fullAngle * 0.5f;
229  float x = UIMeshRoundedRadius * Mathf.Sin (angle);
230  float y = UIMeshRoundedRadius * Mathf.Cos (angle);
231  newVertices.Add (new Vector3 (x, 0, y - UIMeshRoundedSideLength));
232  newUV.Add (new Vector2 (0, 0));
233  newVertices.Add (new Vector3 (x, UIMeshRoundedHeight, y - UIMeshRoundedSideLength));
234  newUV.Add (new Vector2 (0, 1));
235 
236  // Create the rounded part:
237  int numSegments = 50;
238  for (int i = 0; i <= numSegments; i++) {
239  float currentAmount = (float)i / (float)numSegments;
240  angle = fullAngle * currentAmount - fullAngle * 0.5f;
241  x = UIMeshRoundedRadius * Mathf.Sin (angle);
242  y = UIMeshRoundedRadius * Mathf.Cos (angle);
243  newVertices.Add (new Vector3 (x, 0, y));
244  newUV.Add (new Vector2 (ratioSide + currentAmount*ratioRounded, 0));
245  newVertices.Add (new Vector3 (x, UIMeshRoundedHeight, y));
246  newUV.Add (new Vector2 (ratioSide + currentAmount*ratioRounded, 1));
247  }
248 
249  // Add second straight segment:
250  angle = fullAngle * 0.5f;
251  x = UIMeshRoundedRadius * Mathf.Sin (angle);
252  y = UIMeshRoundedRadius * Mathf.Cos (angle);
253  newVertices.Add (new Vector3 (x, 0, y - UIMeshRoundedSideLength));
254  newUV.Add (new Vector2 (1, 0));
255  newVertices.Add (new Vector3 (x, UIMeshRoundedHeight, y - UIMeshRoundedSideLength));
256  newUV.Add (new Vector2 (1, 1));
257 
258  for (int i = 0; i <= numSegments + 1; i++) {
259  newTriangles.Add (i * 2 + 0);
260  newTriangles.Add (i * 2 + 1);
261  newTriangles.Add (i * 2 + 2);
262  newTriangles.Add (i * 2 + 1);
263  newTriangles.Add (i * 2 + 3);
264  newTriangles.Add (i * 2 + 2);
265  }
266 
267  // Generate a mesh from the lists:
268  Mesh mesh = new Mesh();
269  mesh.name = "UIMesh";
270  mesh.vertices = newVertices.ToArray();
271  mesh.uv = newUV.ToArray();
272  mesh.triangles = newTriangles.ToArray();
273  mesh.RecalculateNormals ();
274 
275 
276  // Generate a new game object:
277  GameObject go = new GameObject("UIMesh");
278  go.transform.SetParent( transform, false );
279  go.layer = LayerMask.NameToLayer ("UIMesh");
280  go.AddComponent<MeshFilter> ();
281  go.AddComponent<MeshCollider> ();
282  go.GetComponent<MeshFilter>().mesh = mesh;
283  go.GetComponent<MeshCollider> ().sharedMesh = mesh;
284 
285 
286  // Set up the render texture:
287  float meshWidth = fullSize; // 2*pi*r
288  float meshHeight = UIMeshRoundedHeight;
289  float pixelsPerMeter = UI.Core.instance.pixelsPerMeter;
290  int textureWidth = (int)(meshWidth * pixelsPerMeter);
291  int textureHeight = (int)(meshHeight * pixelsPerMeter);
292  RenderTexture tex = new RenderTexture (textureWidth, textureHeight, 24, RenderTextureFormat.ARGB32 );
293  tex.name = "UI Render Texture";
294  UICamera.targetTexture = tex;
295 
296 
297  // Set up rendering:
298  MeshRenderer renderer = go.AddComponent<MeshRenderer> ();
299  renderer.material = UiMeshMaterial;
300  renderer.material.mainTexture = tex;
301 
302  // Move forward until it reaches the edge of the platform:
303  float yPos = rounded.GetComponent<MeshRenderer>().bounds.size.z - UIMeshRoundedRadius;
304  go.transform.localPosition = new Vector3 (0f, UIMeshRoundedBottom, yPos);
305 
306  UIMesh = go;
307 
308  // Let the layout system know about the new aspect ratio:
309  UI.Core.instance.setCamera( UICamera );
310 
312 
313  // Debug write image to file:
314  /* cUIcamera.GetComponent<Camera> ().Render ();
315  RenderTexture.active = tex;
316  Texture2D virtualPhoto =
317  new Texture2D(textureWidth,textureHeight, TextureFormat.ARGB32, false);
318  virtualPhoto.ReadPixels ( new Rect( 0,0, textureWidth, textureHeight ), 0, 0 );
319  virtualPhoto.Apply ();
320  RenderTexture.active = null;
321 
322  byte[] bytes;
323  bytes = virtualPhoto.EncodeToPNG ();
324  System.IO.File.WriteAllBytes("/home/micha/tmp.png", bytes );*/
325  }
326 
328  void generateUIMeshRectangular( float width, float depth )
329  {
330  removeUIMesh ();
331 
332  // First, initialize lists:
333  List<Vector3> newVertices = new List<Vector3> ();
334  List<Vector2> newUV = new List<Vector2> ();
335  List<int> newTriangles = new List<int> ();
336 
337  float radius = UIMeshRectangularRadius;
338  float centerSize = width - 2*left.GetComponent<Renderer> ().bounds.size.x;
339  float roundedSize = 2f * Mathf.PI * radius * 0.5f;
340  float depthSize = depth - front.GetComponent<Renderer> ().bounds.size.z;
341  float fullSize = centerSize + roundedSize + 2f * depthSize;
342 
343  // what percentage of the whole mesh is rounded (as opposed to straight):
344  ratioRounded = roundedSize / fullSize;
345  ratioSide = depthSize / fullSize;
346  ratioFront = centerSize / fullSize;
347 
348  // Fill the lists with vertices and triangles:
349  int numRoundedSegments = 50;
350  float fullAngle = Mathf.PI;
351 
352  // Add left side mesh:
353  newVertices.Add (new Vector3 (-width*0.5f, 0, -depthSize));
354  newUV.Add (new Vector2 (0, 0));
355  newVertices.Add (new Vector3 (-width*0.5f, UIMeshRectangularHeight, -depthSize));
356  newUV.Add (new Vector2 (0, 1));
357 
358  // Add first rounded corner:
359  for (int i = 0; i <= numRoundedSegments / 2; i++) {
360  float currentAmount = (float)i / (float)numRoundedSegments;
361  float angle = fullAngle * currentAmount - fullAngle * 0.5f;
362  float x = radius * Mathf.Sin (angle) - centerSize*0.5f;
363  float y = radius * Mathf.Cos (angle);
364  newVertices.Add (new Vector3 (x, 0, y));
365  newUV.Add (new Vector2 (currentAmount*ratioRounded + ratioSide, 0));
366  newVertices.Add (new Vector3 (x, UIMeshRectangularHeight, y));
367  newUV.Add (new Vector2 (currentAmount*ratioRounded + ratioSide, 1));
368  }
369  // Add second rounded corner (and automatically add center piece):
370  for (int i = numRoundedSegments / 2; i <= numRoundedSegments; i++) {
371  float currentAmount = (float)i / (float)numRoundedSegments;
372  float angle = fullAngle * currentAmount - fullAngle * 0.5f;
373  float x = radius * Mathf.Sin (angle) + centerSize*0.5f;
374  float y = radius * Mathf.Cos (angle);
375  newVertices.Add (new Vector3 (x, 0, y));
376  newUV.Add (new Vector2 (currentAmount*ratioRounded + ratioSide + ratioFront, 0));
377  newVertices.Add (new Vector3 (x, UIMeshRectangularHeight, y));
378  newUV.Add (new Vector2 (currentAmount*ratioRounded + ratioSide + ratioFront, 1));
379  }
380  // Add right side mesh:
381  newVertices.Add (new Vector3 (width*0.5f, 0, -depthSize));
382  newUV.Add (new Vector2 (1, 0));
383  newVertices.Add (new Vector3 (width*0.5f, UIMeshRectangularHeight, -depthSize));
384  newUV.Add (new Vector2 (1, 1));
385 
386  for (int i = 0; i <= numRoundedSegments + 2; i++) {
387  newTriangles.Add (i * 2 + 0);
388  newTriangles.Add (i * 2 + 1);
389  newTriangles.Add (i * 2 + 2);
390  newTriangles.Add (i * 2 + 1);
391  newTriangles.Add (i * 2 + 3);
392  newTriangles.Add (i * 2 + 2);
393  }
394 
395  // Generate a mesh from the lists:
396  Mesh mesh = new Mesh();
397  mesh.name = "UIMesh";
398  mesh.vertices = newVertices.ToArray();
399  mesh.uv = newUV.ToArray();
400  mesh.triangles = newTriangles.ToArray();
401  mesh.RecalculateNormals ();
402 
403  // Generate a new game object:
404  GameObject go = new GameObject("UIMesh");
405  go.transform.SetParent( transform, false );
406  go.layer = LayerMask.NameToLayer ("UIMesh");
407  go.AddComponent<MeshFilter> ();
408  go.AddComponent<MeshCollider> ();
409  go.GetComponent<MeshFilter>().mesh = mesh;
410  go.GetComponent<MeshCollider> ().sharedMesh = mesh;
411 
412 
413  // Set up the render texture:
414  float meshWidth = fullSize; // 2*pi*r
415  float meshHeight = UIMeshRectangularHeight;
416  float pixelsPerMeter = UI.Core.instance.pixelsPerMeter;
417  int textureWidth = (int)(meshWidth * pixelsPerMeter);
418  int textureHeight = (int)(meshHeight * pixelsPerMeter);
419  RenderTexture tex = new RenderTexture (textureWidth, textureHeight, 24, RenderTextureFormat.ARGB32 );
420  tex.name = "UI Render Texture";
421  UICamera.targetTexture = tex;
422  UICamera.orthographicSize = 1f;
423 
424 
425  // Set up rendering:
426  MeshRenderer renderer = go.AddComponent<MeshRenderer> ();
427  renderer.material = UiMeshMaterial;
428  renderer.material.mainTexture = tex;
429 
430 
431  // Move forward until it reaches the edge of the platform:
432  float yPos = depth - front.GetComponent<Renderer>().bounds.size.z;
433  go.transform.localPosition = new Vector3 (0f, UIMeshRectangularBottom, yPos);
434 
435  UIMesh = go;
436 
437  if( ! Config.instance.skipAnimations )
438  UIMesh.SetActive (false);
439 
440  // Let the layout system know about the new aspect ratio:
441  UI.Core.instance.setCamera( UICamera );
442 
444  }
445 
447  void removeUIMesh()
448  {
449  if( UIMesh != null )
450  {
451  Destroy( UIMesh );
452  }
453  }
454 
455  public void activateUIMesh()
456  {
457  if (UIMesh != null) {
458  UIMesh.SetActive (true);
459  }
460  }
461 
466  public GameObject toolStandPosition( uint number, uint numberOfToolStands )
467  {
468  GameObject go = new GameObject ("ToolStand Anchor");
469 
470  // If the rounded platform is active...
471  if (rounded.activeSelf) {
472  float radius = 0.6f;//1f;
473  float angleStep = 19;
474  float startAngle = (numberOfToolStands-1) * angleStep * 0.5f;
475  float angle = number * angleStep - startAngle;
476  Vector3 center = new Vector3 (0f, 0f, 1.4f);
477  Vector3 offset = Quaternion.AngleAxis( angle, Vector3.up) * new Vector3 (0f, 0f, radius );
478 
479  go.transform.localPosition = offset + center;
480  go.transform.localRotation = Quaternion.AngleAxis ( angle, Vector3.up);
481  } else { // Rectangular platform is active
482  float z = front.GetComponent<Renderer>().bounds.min.z - front.transform.position.z;
483  float distBetweenStands = 0.3f;
484  float startX = (numberOfToolStands-1) * distBetweenStands * 0.5f;
485  float x = number * distBetweenStands - startX;
486 
487  go.transform.localPosition = new Vector3 (x, 0f, z);
488  }
489  go.transform.SetParent (transform, false);
490  return go;
491  }
492 
493  public bool getIsRounded()
494  {
495  if (rounded.activeSelf) {
496  return true;
497  }
498  return false;
499  }
500 
501  public bool getIsRectangular()
502  {
503  return !getIsRounded ();
504  }
505 
506  public Rect getScreenDimensions( UI.Screen screen )
507  {
508  Rect rect = new Rect ();
509  Rect fullScreen = UI.Core.instance.layoutSystem.sizeOfUIScene;
510  int statusBarHeight = UI.Core.instance.layoutSystem.statusBarHeight;
511  Vector2 sBar = new Vector2( 0, statusBarHeight);
512 
513  if (rounded.activeSelf) {
514  if (screen == UI.Screen.left) {
515  rect.min = fullScreen.min + sBar;
516  rect.max = new Vector2 (fullScreen.min.x + fullScreen.width * 0.33f, fullScreen.max.y);
517  } else if (screen == UI.Screen.right) {
518  rect.max = fullScreen.max;
519  rect.min = new Vector2 (fullScreen.max.x - fullScreen.width * 0.33f, fullScreen.min.y) + sBar;
520  } else {
521  rect.min = new Vector2 (fullScreen.center.x - fullScreen.width * 0.25f, fullScreen.min.y) + sBar;
522  rect.max = new Vector2 (fullScreen.center.x + fullScreen.width * 0.25f, fullScreen.max.y);
523  }
524  } else {
525  if (screen == UI.Screen.left) {
526  rect.min = fullScreen.min + sBar;
527  rect.max = new Vector2 (fullScreen.min.x + fullScreen.width * ratioSide, fullScreen.max.y);
528  } else if (screen == UI.Screen.right) {
529  rect.max = fullScreen.max;
530  rect.min = new Vector2 (fullScreen.max.x - fullScreen.width * ratioSide, fullScreen.min.y) + sBar;
531  } else {
532  rect.min = new Vector2 (fullScreen.center.x - fullScreen.width * ratioFront*0.5f, fullScreen.min.y) + sBar;
533  rect.max = new Vector2 (fullScreen.center.x + fullScreen.width * ratioFront*0.5f, fullScreen.max.y);
534  }
535  }
536  return rect;
537  }
538 
539 
546  {
547  // Remove old gameobjects:
548  foreach ( KeyValuePair<UI.Screen, GameObject> entry in screenCenters) {
549  Destroy (entry.Value);
550  }
551  screenCenters.Clear ();
552 
553  // Create new gameobjects:
554  if (getIsRounded ()) {
555  // TODO!
556  } else {
557  GameObject go;
558  float x, y, z;
559 
560  // Create left screen center object:
561  go = new GameObject ();
562  x = -rectWidth * 0.5f;
563  y = UIMeshRectangularBottom + UIMeshRectangularHeight * 0.5f;
564  z = -rectDepth * 0.5f;
565  go.transform.position = new Vector3 (x, y, z);
566  go.transform.SetParent (transform, false);
567  go.transform.rotation = Quaternion.LookRotation (Vector3.right, Vector3.up);
568  screenCenters [UI.Screen.left] = go;
569 
570  // Create center screen center object:
571  go = new GameObject ();
572  x = 0f;
573  y = UIMeshRectangularBottom + UIMeshRectangularHeight * 0.5f;
574  z = -rectDepth;
575  go.transform.position = new Vector3 (x, y, z);
576  go.transform.SetParent (transform, false);
577  go.transform.rotation = Quaternion.LookRotation (Vector3.forward, Vector3.up);
578  screenCenters [UI.Screen.center] = go;
579 
580  // Create right screen center object:
581  go = new GameObject ();
582  x = rectWidth * 0.5f;
583  y = UIMeshRectangularBottom + UIMeshRectangularHeight * 0.5f;
584  z = -rectDepth * 0.5f;
585  go.transform.position = new Vector3 (x, y, z);
586  go.transform.SetParent (transform, false);
587  go.transform.rotation = Quaternion.LookRotation (Vector3.left, Vector3.up);
588  screenCenters [UI.Screen.right] = go;
589  }
590  }
591 
596  public Transform getCenterTransformForScreen( UI.Screen s )
597  {
598  return screenCenters [s].transform;
599  }
600 }
Transform getCenterTransformForScreen(UI.Screen s)
Definition: Platform.cs:596
Definition: Config.cs:4
GameObject toolStandPosition(uint number, uint numberOfToolStands)
Definition: Platform.cs:466
void updateCenterGameObjects()
Definition: Platform.cs:545