예제 #1
0
파일: img.cs 프로젝트: HippoAR/DemoPowerUI
        public override void OnComputeBox(Renderman renderer, Css.LayoutBox box, ref bool widthUndefined, ref bool heightUndefined)
        {
            // Replaced:
            box.OrdinaryInline = false;

            if (widthUndefined)
            {
                if (heightUndefined)
                {
                    // Both undefined - use the base:
                    box.InnerWidth  = RawWidth;
                    box.InnerHeight = RawHeight;
                }
                else
                {
                    // Apply width from the height:
                    box.InnerWidth = box.InnerHeight * AspectRatio;
                }
            }
            else if (heightUndefined)
            {
                // Apply height from the width:
                box.InnerHeight = box.InnerWidth * InverseAspectRatio;
            }

            // They're always defined by the end of this:
            widthUndefined  = false;
            heightUndefined = false;
        }
예제 #2
0
 public override void OnComputeBox(Renderman renderer, Css.LayoutBox box, ref bool widthUndefined, ref bool heightUndefined)
 {
     if (Context2D != null)
     {
         Context2D.UpdateDimensions(box);
     }
 }
예제 #3
0
    /// <summary>Clears all content from the UI and all WorldUI's.
    /// Please note that it is safer to set innerHTML to a blank string for a particular UI than calling this.</summary>
    public static void ClearAll()
    {
        content = null;

        if (Renderer != null)
        {
            Renderer.Destroy();
            Renderer = null;
            document = null;
        }

        Fonts.Clear();
        AtlasStacks.Clear();
        Web.Clear();
        Spa.SPA.Clear();
        UIAnimation.Clear();
        ScreenInfo.Clear();
        WorldUI currentWorldUI = FirstWorldUI;

        while (currentWorldUI != null)
        {
            currentWorldUI.Destroy();
            currentWorldUI = currentWorldUI.UIAfter;
        }

        LastWorldUI  = null;
        FirstWorldUI = null;
    }
예제 #4
0
    /// <summary>Clears all content from the UI and all WorldUI's.
    /// Please note that it is safer to set innerHTML to a blank string for a particular UI than calling this.</summary>
    public static void ClearAll()
    {
        content = null;

        if (Renderer != null)
        {
            Renderer.Destroy();
            Renderer = null;
            document = null;
        }

        Fonts.Clear();
        AtlasStacks.Clear();
        Http.Clear();
        SPA.Clear();
        UIAnimation.Clear();
        DynamicTexture.RemoveAll();
        PowerUI.Input.Clear();
        ScreenInfo.Clear();
        WorldUI currentWorldUI = FirstWorldUI;

        while (currentWorldUI != null)
        {
            currentWorldUI.Destroy();
            currentWorldUI = currentWorldUI.UIAfter;
        }

        LastWorldUI  = null;
        FirstWorldUI = null;
    }
예제 #5
0
        /// <summary>Creates a new document which will be rendered with the given renderer.</summary>
        /// <param name="renderer">The renderer to use when rendering this document.</param>
        /// <param name="parentWindow">The window that will become the parent window. Used in e.g. iframes.</param>
        /// <param name="aot">True if this is a Nitro AOT document (used in the Editor only).</param>
        public HtmlDocument(Renderman renderer, Window parentWindow, bool aot) : base(renderer == null?null:renderer.InWorldUI)
        {
            AotDocument = aot;

            if (renderer == null)
            {
                renderer = new Renderman(this);
            }

            Renderer = renderer;

            // Set the XHTML namespace:
            Namespace = Dom.HtmlLexer.XHTMLNamespace;

            window = new Window();
            window.SetDocument(this);
            window.parent = parentWindow;
            if (parentWindow != null)
            {
                window.top = parentWindow.top;
            }
            else
            {
                window.top = window;
            }

            // Clear style; this loads in the default stylesheet:
            ClearStyle();
        }
예제 #6
0
        /// <summary>Creates a new World UI with the given pixels of space and a given name.
        /// The gameobjects origin sits at the middle of the UI by default. See <see cref="PowerUI.WorldUI.SetOrigin"/>.
        /// By default, 100 pixels are 1 world unit. See <see cref="PowerUI.WorldUI.SetResolution"/>.</summary>
        /// <param name="name">The name for the UI's gameobject.</param>
        /// <param name="widthPX">The width in pixels of this UI.</param>
        /// <param name="heightPX">The height in pixels of this UI.</param>
        public WorldUI(string name, int widthPX, int heightPX)
        {
            // Start the UI:
            UI.Start();

            // Create the gameobject:
            gameObject      = new GameObject();
            gameObject.name = name;

            // Grab the name:
            Name = name;

            transform = gameObject.transform;
            Renderer  = new Renderman(this);
            SetDepthResolution(1f);

            // Apply the default scale:
            transform.localScale = new Vector3(1 / 100f, 1 / 100f, 1 / 100f);

            document = Renderer.RootDocument as HtmlDocument;

            // Add it to the UI update linked list:
            if (UI.FirstWorldUI == null)
            {
                UI.FirstWorldUI = UI.LastWorldUI = this;
            }
            else
            {
                UIBefore       = UI.LastWorldUI;
                UI.LastWorldUI = UI.LastWorldUI.UIAfter = this;
            }

            SetDimensions(widthPX, heightPX);
        }
예제 #7
0
        public override void OnComputeBox(Renderman renderer, Css.LayoutBox box, ref bool widthUndefined, ref bool heightUndefined)
        {
            if (document is SVGDocument)
            {
                return;
            }

            // Occurs on inline SVG's.

            // Set the size:
            Context.SetSize((int)box.InnerWidth, (int)box.InnerHeight);

            UnityEngine.Texture tex = Context.Texture;

            if (tex == null)
            {
                return;
            }

            // Update the background raw image:
            BackgroundImage img = RenderData.BGImage;

            if (img == null)
            {
                img = new Css.BackgroundImage(RenderData);
                RenderData.BGImage = img;
            }

            // Update the bg image:
            img.UpdateImage(tex);
        }
예제 #8
0
        /// <summary>Called when the renderer for this batch has changed.</summary>
        public void ChangeRenderer(Renderman renderer)
        {
            Renderer = renderer;

            RenderWithCamera(renderer.RenderLayer);

            // Let the mesh know that the parent changed:
            Mesh.ChangeParent();

            InputMode mode;

            if (Renderer.RenderingInWorld)
            {
                mode = PowerUI.Input.WorldInputMode;
            }
            else
            {
                mode = PowerUI.Input.Mode;
            }

            bool isPhysics = (mode == InputMode.Physics);

            if (isPhysics == PhysicsMode)
            {
                return;
            }

            Mesh.SetPhysicsMode(isPhysics);
        }
예제 #9
0
        protected override void Layout()
        {
            Renderman     renderer = Element.Document.Renderer;
            ComputedStyle computed = Element.Style.Computed;
            // Get the top left inner corner (inside margin and border):
            int width  = computed.PaddedWidth;
            int height = computed.PaddedHeight;
            int top    = computed.OffsetTop + computed.BorderTop;
            int left   = computed.OffsetLeft + computed.BorderLeft;

            // Is it clipped?
            if (renderer.IsInvisible(left, top, width, height))
            {
                // Totally not visible.
                return;
            }

            // Ensure we have a batch (doesn't change graphics or font thus both nulls):
            SetupBatch(null, null);

            Add();

            // Using firstblock as our block here.
            // Set the UV to that of the solid block colour pixel:
            FirstBlock.SetSolidColourUV();
            // Set the (overlay) colour:
            FirstBlock.SetColour(BackingColour);

            // And finally sort out the verts:
            FirstBlock.SetClipped(renderer.ClippingBoundary, new BoxRegion(left, top, width, height), renderer, computed.ZIndex - 0.006f);
        }
        /// <summary>Calculates where the transformation origin should go in screen space.</summary>
        /// <param name="relativeTo">The computed style of the element that the origin will be
        /// relative to if the origin position is 'Relative'</param>
        private void CalculateOrigin(ComputedStyle relativeTo)
        {
            // We need to figure out where the origin is and then apply the parent transformation to it.
            _Origin = _OriginOffset;

            if (_OriginOffsetPercX)
            {
                _Origin.x *= relativeTo.PixelWidth;
            }

            if (_OriginOffsetPercY)
            {
                _Origin.y *= relativeTo.PixelHeight;
            }

            if (_OriginPosition == PositionType.Relative)
            {
                _Origin.x += relativeTo.OffsetLeft;
                _Origin.y += relativeTo.OffsetTop;
            }

            // Map origin to world space:
            Renderman renderer = relativeTo.Element.Document.Renderer;

            _Origin = renderer.PixelToWorldUnit(_Origin.x, _Origin.y, relativeTo.ZIndex);

            if (Parent != null)
            {
                _Origin = Parent.Apply(_Origin);
            }
        }
예제 #11
0
 /// <summary>Sets the vertices of this box to that specified by the given block
 /// but clipped to fit within a boundary.</summary>
 /// <param name="boundary">The clipping boundary. The vertices will be clipped to within this.</param>
 /// <param name="block">The position of the vertices.</param>
 /// <param name="zIndex">The depth of the vertices.</param>
 public void SetClipped(BoxRegion boundary, BoxRegion block, Renderman renderer, float zIndex)
 {
     // Clipping with no image/ affect on UVs:
     block.ClipBy(boundary);
     // And just apply the result:
     ApplyVertices(block, renderer, zIndex);
 }
예제 #12
0
        /// <summary>Gets a batch from the pool. Null if the pool is empty.</summary>
        public static UIBatch Get(Renderman renderer)
        {
            if (First == null)
            {
                return(null);
            }

            UIBatch result = First;

            First             = result.BatchAfter;
            result.BatchAfter = null;
            result.Setup      = false;

            // Show it:
                        #if PRE_UNITY4
            result.Mesh.OutputGameObject.active = true;
                        #else
            result.Mesh.OutputGameObject.SetActive(true);
                        #endif

            if (result.Renderer != renderer)
            {
                result.ChangeRenderer(renderer);
            }

            return(result);
        }
예제 #13
0
        public override void OnRender(Renderman renderer)
        {
            // Get the target:
            HtmlElement target = ScrollBar.scrollTarget;

            if (target == null)
            {
                return;
            }

            ComputedStyle computed = target.style.Computed;
            LayoutBox     box      = computed.FirstBox;

            if (box == null)
            {
                // Not visible or hasn't been drawn yet.
                return;
            }

            int   overflowMode = IsVertical?box.OverflowY : box.OverflowX;
            float visible      = IsVertical?box.VisiblePercentageY() : box.VisiblePercentageX();

            if (visible > 1f)
            {
                visible = 1f;
            }
            else if (visible < 0f)
            {
                visible = 0f;
            }

            // Handle auto next:
            if (overflowMode == VisibilityMode.Auto && visible == 1f)
            {
                // Hide it:
                ScrollBar.Style.display = "none";

                // Make sure it's not scrolled:
                if (IsVertical && box.Scroll.Top != 0f)
                {
                    if (box.Scroll.Top != 0f)
                    {
                        // Clear it:
                        computed.ChangeTagProperty("scroll-top", new Css.Units.DecimalUnit(0f));
                    }
                }
                else if (box.Scroll.Left != 0f)
                {
                    computed.ChangeTagProperty("scroll-left", new Css.Units.DecimalUnit(0f));
                }

                // Mark as hidden so the informer can watch out for it:
                ScrollBar.Hidden = true;

                return;
            }

            ApplyTabSize(visible, Style.Computed.FirstBox);
        }
예제 #14
0
        public SVGDocument() : base(null)
        {
            // Apply the namespace:
            Namespace = SVGNamespace;
            Renderer  = new Renderman(this);

            // Clear style; this loads in the default stylesheet:
            ClearStyle();
        }
예제 #15
0
        /// <summary>Called when the renderer for this batch has changed.</summary>
        public void ChangeRenderer(Renderman renderer)
        {
            Renderer = renderer;

            RenderWithCamera(renderer.RenderLayer);

            // Let the mesh know that the parent changed:
            Mesh.ChangeParent();
        }
예제 #16
0
        public override void OnComputeBox(Renderman renderer, Css.LayoutBox box, ref bool widthUndefined, ref bool heightUndefined)
        {
            // Update viewport:
            if (ContentDocument == null)
            {
                return;
            }

            ContentDocument.Viewport.Height = box.InnerHeight;
            ContentDocument.Viewport.Width  = box.InnerWidth;
        }
예제 #17
0
        /// <summary>This locates the vertices of this block in world space to the position defined by the given box.</summary>
        /// <param name="block">The position of the vertices in screen coordinates.</param>
        /// <param name="renderer">The renderer used when rendering this block.</param>
        /// <param name="zIndex">The depth of the vertices.</param>
        internal void ApplyVertices(BoxRegion block, Renderman renderer, float zIndex)
        {
            // Compute the min/max pixels:
            Vector3 min = renderer.PixelToWorldUnit(block.X, block.Y, zIndex);
            Vector3 max = renderer.PixelToWorldUnit(block.MaxX, block.MaxY, zIndex);

            // Get the 4 corners:
            VertexTopLeft     = min;
            VertexBottomRight = max;
            VertexTopRight    = new Vector3(max.x, min.y, min.z);
            VertexBottomLeft  = new Vector3(min.x, max.y, min.z);
        }
		public RoundedCorners(BorderProperty border){
			Border=border;
			
			// Grab the renderer:
			Renderer=Border.Element.Document.Renderer;
			
			// Grab the computed style:
			Computed=border.Element.style.Computed;
			
			// Create the inverse border set:
			InverseBorder=new RoundBorderInverseProperty(border.Element);
		}
        public RoundedCorners(BorderProperty border)
        {
            Border = border;

            // Grab the renderer:
            Renderer = Border.Element.Document.Renderer;

            // Grab the computed style:
            Computed = border.Element.style.Computed;

            // Create the inverse border set:
            InverseBorder = new RoundBorderInverseProperty(border.Element);
        }
예제 #20
0
        /// <summary>Creates a new document which will be rendered with the given renderer.</summary>
        /// <param name="renderer">The renderer to use when rendering this document.</param>
        /// <param name="parentWindow">The window that will become the parent window. Used in e.g. iframes.</param>
        /// <param name="aot">True if this is a Nitro AOT document (used in the Editor only).</param>
        public Document(Renderman renderer, Window parentWindow, bool aot) : base()
        {
            AotDocument = aot;

            if (!aot && DefaultStyleSheet == null)
            {
                // No default styles loaded yet. Load them now.
                string styleText = ((TextAsset)Resources.Load("style")).text;
                // Have they applied any overrides?
                TextAsset extraStyle = Resources.Load("customStyle") as TextAsset;
                if (extraStyle != null && extraStyle.text != null)
                {
                    styleText += "\n\n" + extraStyle.text;
                }
                DefaultStyleSheet = new Css.StyleSheet(this);
                DefaultStyleSheet.ParseCss(styleText);
            }

                        #if !NoNitroRuntime
            // Get the default security domain:
            SecurityDomain = UI.DefaultSecurityDomain;
                        #endif

            Renderer = renderer;

            window          = new Window();
            window.document = this;
            window.parent   = parentWindow;
            if (parentWindow != null)
            {
                window.top = parentWindow.top;
            }
            else
            {
                window.top = window;
            }

            ActiveFonts = new Dictionary <string, DynamicFont>();
            Style       = new Css.StyleSheet(this);
            html        = new Element(this, null);
            html.SetTag("html");
            string ddbox = "";

            if (parentWindow == null)
            {
                // Dropdown box belongs to the top window only:
                ddbox = "<ddbox></ddbox>";
            }

            html.innerHTML = "<body></body>" + ddbox;
        }
예제 #21
0
        public override void OnComputeBox(Renderman renderer, Css.LayoutBox box, ref bool widthUndefined, ref bool heightUndefined)
        {
            RectangleProvider rect = Rectangle;

            // Check to see if w/h was updated via CSS:
            Css.Value newWidth  = Width;
            Css.Value newHeight = Height;

            if (rect.Width != newWidth || rect.Height != newHeight)
            {
                rect.Width  = newWidth;
                rect.Height = newHeight;
                RebuildPath();
            }
        }
예제 #22
0
        public override void OnComputeBox(Renderman renderer, Css.LayoutBox box, ref bool widthUndefined, ref bool heightUndefined)
        {
            // Replaced:
            box.OrdinaryInline = false;

            if (widthUndefined)
            {
                if (heightUndefined)
                {
                    // Both undefined - establish which we'll be primarily clipping by.

                    if (Style.Computed.ShouldClipHeight())
                    {
                        // Height priority. Clip by min/max-height:
                        box.InnerHeight = Style.Computed.ClipHeight(
                            box.DisplayMode, RawHeight * Style.Computed.RenderData.ValueScale
                            );

                        // Derive height from the aspect ratio:
                        box.InnerWidth = box.InnerHeight * AspectRatio;
                    }
                    else
                    {
                        // Width priority. Clip by min/max-width:
                        box.InnerWidth = Style.Computed.ClipWidth(
                            box.DisplayMode, RawWidth * Style.Computed.RenderData.ValueScale
                            );

                        // Derive height from the aspect ratio:
                        box.InnerHeight = box.InnerWidth * InverseAspectRatio;
                    }
                }
                else
                {
                    // Apply width from the height:
                    box.InnerWidth = box.InnerHeight * AspectRatio;
                }
            }
            else if (heightUndefined)
            {
                // Apply height from the width:
                box.InnerHeight = box.InnerWidth * InverseAspectRatio;
            }

            // They're always defined by the end of this:
            widthUndefined  = false;
            heightUndefined = false;
        }
예제 #23
0
        public override void OnComputeBox(Renderman renderer, Css.LayoutBox box, ref bool widthUndefined, ref bool heightUndefined)
        {
            // Get meta:
            LineBoxMeta lbm = renderer.TopOfStackSafe;

            // If the line is empty, set some height:
            if (lbm.FirstOnLine == null)
            {
                heightUndefined = false;
                box.InnerHeight = Style.Computed.FontSizeX;
                box.Height      = box.InnerHeight;
            }

            // Implicit line break:
            lbm.CompleteLine(LineBreakMode.Normal | LineBreakMode.Last);
        }
예제 #24
0
 public override void OnComputeBox(Renderman renderer, Css.LayoutBox thumbBox, ref bool widthUndefined, ref bool heightUndefined)
 {
     if (IsVertical)
     {
         if (thumbBox.Position.Top == float.MaxValue)
         {
             // Initial push over the first arrow:
             thumbBox.Position.Top = StartArrowSize;
         }
     }
     else if (thumbBox.Position.Left == float.MaxValue)
     {
         // Initial push over the first arrow:
         thumbBox.Position.Left = StartArrowSize;
     }
 }
예제 #25
0
        /// <summary>Destroys this UI. Note that this also occurs if the gameobject is destroyed;
        /// Just destroying the gameobject or a parent gameObject is all that is required.</summary>
        public virtual void Destroy()
        {
            if (Renderer == null)
            {
                return;
            }

            // Remove from the physics lookup if needed:
            if (PhysicsLookup != null && transform != null)
            {
                PhysicsLookup.Remove(transform);

                if (PhysicsLookup.Count == 0)
                {
                    PhysicsLookup = null;
                }
            }

            Renderer.Destroy();
            Renderer = null;

            if (gameObject != null)
            {
                GameObject.Destroy(gameObject);
                gameObject = null;
                transform  = null;
            }

            // Remove it from the UI update linked list:
            if (UIBefore == null)
            {
                UI.FirstWorldUI = UIAfter;
            }
            else
            {
                UIBefore.UIAfter = UIAfter;
            }

            if (UIAfter == null)
            {
                UI.LastWorldUI = UIBefore;
            }
            else
            {
                UIAfter.UIBefore = UIBefore;
            }
        }
예제 #26
0
        /// <summary>Attempts to find the element from the set WorldUI; if there is no WorldUI, the main UI is used.
        /// This search uses the triangle of the hit to figure out exactly which element was clicked.</summary>
        /// <param name="hit">The hit in 3D that must be resolved to an element.</param>
        public void FindElement(RaycastHit hit)
        {
            // Which triangle was hit, and as a result, which element did it come from?
            // If the element is found, apply it to our result; otherwise assume unsuccessful hit.
            Renderman renderer = null;

            if (OnWorldUI != null)
            {
                renderer = OnWorldUI.Renderer;
            }
            else
            {
                renderer = UI.GetRenderer();
            }

            if (renderer == null)
            {
                return;
            }

            Transform transform = hit.transform;

            // Which batch? Will only be from the non-pooled ones:
            UIBatch current = renderer.FirstBatch;

            while (current != null)
            {
                if (current.Mesh.OutputTransform == transform)
                {
                    // Got it!
                    break;
                }
                current = current.BatchAfter;
            }

            if (current == null)
            {
                return;
            }

            // Current is the batch the hit was on. Next, resolve to the MeshBlock and finally to the element that made it.
        }
예제 #27
0
        /// <summary>Allocates a block from this mesh. Note that the block object is actually shared. The block can then have
        /// its vertices/triangles edited. Changes will be outputted visually when MeshBlock.Done is called.</summary>
        public MeshBlock Allocate(Renderman renderer)
        {
            MeshBlock block = renderer.Block;

            block.Colour  = Color.white;
            block.TextUV  = null;
            block.ImageUV = null;

            if (FirstBuffer == null || CurrentBufferBlocks == MeshDataBufferPool.BlockCount)
            {
                NextBuffer();
            }

            // Apply buffer and block index:
            block.Buffer     = LastBuffer;
            block.BlockIndex = CurrentBufferBlocks;

            // Bump up the index:
            CurrentBufferBlocks++;

            return(block);
        }
예제 #28
0
        public override void OnComputeBox(Renderman renderer, Css.LayoutBox box, ref bool widthUndefined, ref bool heightUndefined)
        {
            // Locate the caret if we need to:
            if (Locate)
            {
                Locate = false;

                RenderableTextNode htn = TextHolder;
                Vector2            position;

                if (htn == null)
                {
                    // Just at 0,0:
                    position = Vector2.zero;
                }
                else
                {
                    // Clip:
                    if (Index >= htn.length)
                    {
                        Index = htn.length;
                    }

                    // Get the position of the given letter:
                    position = htn.GetPosition(Index);
                }

                // Scroll it if position is out of range:
                ScrollIfBeyond(ref position);

                // Set it in for this pass:
                box.Position.Top  = position.y;
                box.Position.Left = position.x;

                // Write it out:
                Style.Computed.ChangeTagProperty("left", new Css.Units.DecimalUnit(position.x), false);
                Style.Computed.ChangeTagProperty("top", new Css.Units.DecimalUnit(position.y), false);
            }
        }
예제 #29
0
        /// <summary>Permanently destroys this UI batch.</summary>
        public void Destroy()
        {
            if (Renderer == null)
            {
                return;
            }

            if (IsolatedProperty != null)
            {
                IsolatedProperty.Isolated = false;
                IsolatedProperty.OnBatchDestroy();
                IsolatedProperty = null;
            }

            if (Mesh != null)
            {
                Mesh.Destroy();
                Mesh = null;
            }

            Renderer = null;
        }
예제 #30
0
        /// <summary>Called during the layout pass.</summary>
        public override void OnRender(Renderman renderer)
        {
            if (ParticleTransform == null)
            {
                return;
            }

            // Grab the computed style and the renderer:
            ComputedStyle computed = Style.Computed;
            LayoutBox     box      = computed.FirstBox;

            if (box == null)
            {
                // display:none.
                return;
            }

            // Get the top left inner corner (inside margin and border):
            float width  = box.PaddedWidth;
            float height = box.PaddedHeight;
            float top    = box.Y + box.Border.Top;
            float left   = box.X + box.Border.Left;

            // Figure out the middle of that:
            float middleX = left + (width / 2);
            float middleY = top + (height / 2);

            // Map it to our world location:
            ParticleTransform.localPosition = renderer.PixelToWorldUnit(middleX, middleY, computed.ZIndex);

            BatchProperty.GotBatchAlready = false;

            // Setup the batch (so we can get the queue number):
            renderer.SetupBatch(BatchProperty, null, null);

            // Set the particle material to the batch - this'll ensure it gets the right renderQueue:
            renderer.CurrentBatch.Mesh.SetMaterial(ParticleMaterial);
        }
예제 #31
0
        /// <summary>Creates a new UI Camera which will be rendered with the given renderer.</summary>
        /// <param name="renderer">The renderer that will render this camera.</param>
        public UICamera(Renderman renderer)
        {
            Renderer = renderer;

            // Create the root gameobject:
            Gameobject = new GameObject();

            // Create camera gameobject:
            CameraObject = new GameObject();

            // Parent the camera to the root:
            CameraObject.transform.parent = Gameobject.transform;

            // Add a camera:
            SourceCamera = CameraObject.AddComponent <Camera>();

            // Set the clear flags:
            SourceCamera.clearFlags = CameraClearFlags.Depth;

            // Set the culling mask:
            SourceCamera.cullingMask = (1 << UI.Layer);

            // Make it forward rendered:
            SourceCamera.renderingPath = RenderingPath.Forward;

            // Setup the cameras distance:
            SetCameraDistance(UI.GetCameraDistance());

            // Setup the field of view:
            SetFieldOfView(UI.GetFieldOfView());

            // Parent it to the root:
            Gameobject.transform.parent = UI.GUINode.transform;

            // Call the camera creation method:
            UI.CameraGotCreated(SourceCamera);
        }
		/// <summary>Draws a character with x-inverted UV's. Used for rendering e.g. "1 < 2" in right-to-left.</summary>
		private void DrawInvertCharacter(int index,ref float left,float top,Renderman renderer,float zIndex,BoxRegion screenRegion){
			
			Glyph character=Characters[index];
			
			if(character==null){
				return;
			}
			
			if(Kerning!=null){
				left+=Kerning[index] * FontSize;
			}
			
			if(character.Space){
				left+=SpaceSize+LetterSpacing;
				return;
			}
			
			float y=top+Ascender-((character.Height+character.MinY) * FontSize);
			
			AtlasLocation locatedAt=character.Location;
			
			if(locatedAt==null){
				// Not in font.
				return;
			}
			
			screenRegion.Set(left + (character.LeftSideBearing * FontSize),y,locatedAt.Width * ScaleFactor,locatedAt.Height * ScaleFactor);
			
			if(screenRegion.Overlaps(renderer.ClippingBoundary)){
				// True if this character is visible.
				
				// Ensure correct batch:
				SetupBatch(null,locatedAt.Atlas);
			
				MeshBlock block=Add();
				block.SetColour(FontColour);
				
				// And clip our meshblock to fit within boundary:
				block.ImageUV=null;
				UVBlock uvs=block.SetClipped(renderer.ClippingBoundary,screenRegion,renderer,zIndex,locatedAt,block.TextUV);
				
				if(uvs.Shared){
					uvs=new UVBlock(uvs);
				}
				
				// Invert along X:
				float temp=uvs.MinX;
				uvs.MinX=uvs.MaxX;
				uvs.MaxX=temp;
				
				// Assign to the block:
				block.TextUV=uvs;
				
			}
			
			left+=(character.AdvanceWidth * FontSize)+LetterSpacing;
		}
		/// <summary>Draws a character and advances the pen onwards.</summary>
		private void DrawCharacter(int index,ref float left,float top,Renderman renderer,float zIndex,BoxRegion screenRegion){
			
			Glyph character=Characters[index];
			
			if(character==null){
				return;
			}
			
			if(Kerning!=null){
				left+=Kerning[index] * FontSize;
			}
			
			AtlasLocation locatedAt;
			
			if(character.Image!=null){
				
				if(!character.Image.Loaded()){
					return;
				}
				
				// It's an image (e.g. Emoji).
				locatedAt=RequireImage(character.Image);
				
				if(locatedAt==null){
					// It needs to be isolated. Big emoji image!
					return;
				}
				
				if(CharacterProviders.FixHeight){
					// Set the region:
					screenRegion.Set(left,top,locatedAt.Width,locatedAt.Height);
				}else{
					screenRegion.Set(left,top,FontSize,FontSize);
				}
				
				if(screenRegion.Overlaps(renderer.ClippingBoundary)){
						
					// Ensure correct batch:
					SetupBatch(locatedAt.Atlas,null);
					
					// If the two overlap, this means it's actually visible.
					MeshBlock block=Add();
					
					// Set it's colour:
					block.SetColour(Element.Style.Computed.ColorOverlay);
					
					// And clip our meshblock to fit within boundary:
					block.TextUV=null;
					block.ImageUV=block.SetClipped(renderer.ClippingBoundary,screenRegion,renderer,zIndex,locatedAt,block.ImageUV);
				}
				
				left+=(character.AdvanceWidth)+LetterSpacing;
				return;
			}else if(character.Space){
				left+=SpaceSize+LetterSpacing;
				return;
			}
			
			
			locatedAt=character.Location;
			
			if(locatedAt==null){
				// Not in font.
				return;
			}
			
			float y=top+Ascender-((character.Height+character.MinY) * FontSize);
			
			screenRegion.Set(left + (character.LeftSideBearing * FontSize),y,locatedAt.Width * ScaleFactor,locatedAt.Height * ScaleFactor);
			
			if(screenRegion.Overlaps(renderer.ClippingBoundary)){
				// True if this character is visible.
				
				// Ensure correct batch:
				SetupBatch(null,locatedAt.Atlas);
				
				MeshBlock block=Add();
				block.SetColour(FontColour);
				
				// And clip our meshblock to fit within boundary:
				block.ImageUV=null;
				block.TextUV=block.SetClipped(renderer.ClippingBoundary,screenRegion,renderer,zIndex,locatedAt,block.TextUV);
				
			}
			
			left+=(character.AdvanceWidth * FontSize)+LetterSpacing;
		}