Esempio n. 1
0
        public override bool OnAttributeChange(string property)
        {
            // Note that base handles width, height, x, y etc.

            if (property == "viewbox")
            {
                // SVG viewbox
                Viewbox = ValueHelpers.GetViewbox(this["viewbox"]);
            }
            else if (property == "overflow")
            {
                // Overflow
                Overflow = ValueHelpers.GetOverflow(this["overflow"]);
            }
            else if (property == "preserveaspectratio")
            {
                // Aspect ratio
                AspectRatio = new AspectRatio(this["preserveaspectratio"]);
            }
            else if (!base.OnAttributeChange(property))
            {
                return(false);
            }


            return(true);
        }
Esempio n. 2
0
        /// <summary>
        /// Gets the clip path.
        /// </summary>
        public override VectorPath GetPath(SVGElement context, RenderContext renderer)
        {
            if (_computedPath == null)
            {
                Matrix4x4 transform;
                bool      applyExtra;

                if (ClipPathUnits == CoordinateUnits.ObjectBoundingBox)
                {
                    BoxRegion bounds = context.Bounds;

                    transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(
                                                  bounds.Width, bounds.Height, 0f
                                                  ));

                    transform *= Matrix4x4.TRS(new Vector3(
                                                   bounds.X, bounds.Y, 0f
                                                   ), Quaternion.identity, Vector3.one);

                    applyExtra = true;
                }
                else
                {
                    transform  = Matrix4x4.identity;
                    applyExtra = false;
                }

                // For each child which is a PathBase, append it.
                _computedPath = new VectorPath();

                AddChildPaths(this, _computedPath, renderer, transform, applyExtra);
            }

            return(_computedPath);
        }
Esempio n. 3
0
        /// <summary>Adds the given region into this one.</summary>
        public void Combine(BoxRegion r)
        {
            if (r.X < X)
            {
                X = r.X;
            }

            if (r.Y < Y)
            {
                Y = r.Y;
            }

            if (r.MaxX > MaxX)
            {
                MaxX = r.MaxX;
            }

            if (r.MaxY > MaxY)
            {
                MaxY = r.MaxY;
            }

            Width  = MaxX - X;
            Height = MaxY - Y;
        }
        static public GameObject CubeRegion()
        {
            Resources.UnloadUnusedAssets();
            string     resourcePath = "Prefabs/RegionCube";
            GameObject prefab       = (GameObject)Resources.Load(resourcePath);
            GameObject regionCube   = GameObject.Instantiate(prefab, new Vector3(0, 0, 0), Quaternion.identity);

            BoxRegion boxRegion = regionCube.AddComponent <BoxRegion>();

            boxRegion.color = new Color(0.8f, 0.0f, 0.0f, 0.3f);

            MyExposeToEditor myExposeToEditor = regionCube.AddComponent <MyExposeToEditor>();

            myExposeToEditor.CanTransform             = true;
            myExposeToEditor.CanInspect               = true;
            myExposeToEditor.CanDuplicate             = true;
            myExposeToEditor.CanRename                = true;
            myExposeToEditor.CanCreatePrefab          = false;
            myExposeToEditor.ShowSelectionGizmo       = true;
            myExposeToEditor.AddColliders             = false;
            myExposeToEditor.ShowTransform            = false;
            myExposeToEditor.CanSetLoadTransformToRos = false;

            return(regionCube);
        }
Esempio n. 5
0
 /// <summary>Makes sure this box fits inside the given one by clipping it so it does.</summary>
 /// <param name="bound">The bounding box that this must be clipped to.</param>
 public void ClipBy(BoxRegion box)
 {
     ClipLeft(box.X);
     ClipRight(box.MaxX);
     ClipTop(box.Y);
     ClipBottom(box.MaxY);
 }
Esempio n. 6
0
    public static int Main(string[] args)
    {
        string filename = args[0];

        // instantiate the reader:
        gdcm.ImageRegionReader reader = new gdcm.ImageRegionReader();
        reader.SetFileName(filename);

        // pull DICOM info:
        if (!reader.ReadInformation())
        {
            return(1);
        }
        // Get file infos
        gdcm.File f = reader.GetFile();

        // get some info about image
        UIntArrayType dims      = ImageHelper.GetDimensionsValue(f);
        PixelFormat   pf        = ImageHelper.GetPixelFormatValue(f);
        int           pixelsize = pf.GetPixelSize();

        // buffer to get the pixels
        byte[] buffer = new byte[dims[0] * dims[1] * pixelsize];

        // define a simple box region.
        BoxRegion box = new BoxRegion();

        for (uint z = 0; z < dims[2]; z++)
        {
            // Define that I want the image 0, full size (dimx x dimy pixels)
            // and do that for each z:
            box.SetDomain(0, dims[0] - 1, 0, dims[1] - 1, z, z);
            //System.Console.WriteLine( box.toString() );
            reader.SetRegion(box);

            // reader will try to load the uncompressed image region into buffer.
            // the call returns an error when buffer.Length is too small. For instance
            // one can call:
            // uint buf_len = reader.ComputeBufferLength(); // take into account pixel size
            // to get the exact size of minimum buffer
            if (reader.ReadIntoBuffer(buffer, (uint)buffer.Length))
            {
                using (System.IO.Stream stream =
                           System.IO.File.Open(@"/tmp/frame.raw",
                                               System.IO.FileMode.Create))
                {
                    System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream);
                    writer.Write(buffer);
                }
            }
            else
            {
                throw new Exception("can't read pixels error");
            }
        }

        return(0);
    }
Esempio n. 7
0
    public static int Main(string[] args)
    {
        string filename = args[0];

        // instantiate the reader:
        gdcm.ImageRegionReader reader = new gdcm.ImageRegionReader();
        reader.SetFileName( filename );

        // pull DICOM info:
        if (!reader.ReadInformation()) return 1;
        // Get file infos
        gdcm.File f = reader.GetFile();

        // get some info about image
        UIntArrayType dims = ImageHelper.GetDimensionsValue(f);
        PixelFormat pf = ImageHelper.GetPixelFormatValue (f);
        int pixelsize = pf.GetPixelSize();
        PhotometricInterpretation pi = ImageHelper.GetPhotometricInterpretationValue(f);
        Console.WriteLine( pi.toString() );

        // buffer to get the pixels
        byte[] buffer = new byte[ dims[0] * dims[1] * pixelsize ];

        // define a simple box region.
        BoxRegion box = new BoxRegion();
        for (uint z = 0; z < dims[2]; z++)
          {
          // Define that I want the image 0, full size (dimx x dimy pixels)
          // and do that for each z:
          box.SetDomain(0, dims[0] - 1, 0, dims[1] - 1, z, z);
          //System.Console.WriteLine( box.toString() );
          reader.SetRegion( box );

          // reader will try to load the uncompressed image region into buffer.
          // the call returns an error when buffer.Length is too small. For instance
          // one can call:
          // uint buf_len = reader.ComputeBufferLength(); // take into account pixel size
          // to get the exact size of minimum buffer
          if (reader.ReadIntoBuffer(buffer, (uint)buffer.Length))
        {
        using (System.IO.Stream stream =
          System.IO.File.Open(@"/tmp/frame.raw",
            System.IO.FileMode.Create))
          {
          System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream);
          writer.Write(buffer);
          }
        }
          else
        {
        throw new Exception("can't read pixels error");
        }
          }

        return 0;
    }
Esempio n. 8
0
        /// <summary>Makes sure this box fits inside the given one by clipping it so it does.</summary>
        /// <param name="bound">The bounding box that this must be clipped to.</param>
        public bool ClipByChecked(BoxRegion box)
        {
            bool clipped = (ClipLeft(box.X) != 0f);

            clipped |= (ClipRight(box.MaxX) != 0f);
            clipped |= (ClipTop(box.Y) != 0f);
            clipped |= (ClipBottom(box.MaxY) != 0f);

            return(clipped);
        }
Esempio n. 9
0
        /// <summary>Makes sure this box fits inside the given one by clipping it so it does.
        /// Any pixels sliced off this box are also sliced off affect.</summary>
        /// <param name="bound">The bounding box that this must be clipped to.</param>
        /// <param name="affect">A secondary box that will also be clipped with this one.
        /// May, for example, be a region of UV pixel coordinates.</param>
        public void ClipByAffecting(BoxRegion bound, BoxRegion affect)
        {
            if (affect == null)
            {
                // No second box - just clip normally.
                ClipBy(bound);
                return;
            }

            affect.RemoveFromLeft(ClipLeft(bound.X));
            affect.RemoveFromRight(ClipRight(bound.MaxX));
            // The bottom of the graphic is actually the TOP of our verts - it's inverted, so we simply do:
            affect.RemoveFromBottom(ClipTop(bound.Y));
            affect.RemoveFromTop(ClipBottom(bound.MaxY));
        }
        public void Render(float alpha, float cornerX, float cornerY)
        {
            // Grab the renderer:
            Renderman renderer = RoundCorners.Renderer;

            // Get the z-Index:
            float zIndex = renderer.Depth + 0.006f;

            // Figure out where half way is (divide by 2):
            int halfway = (BlocksRequired >> 1);

            Color colour;

            if (Border.Colour == null)
            {
                if (RoundCorners.Computed.Text != null)
                {
                    // Same as the font colour:
                    colour = RoundCorners.Computed.Text.FontColour;
                }
                else
                {
                    // Get the default colour:
                    colour = Color.black;

                    // Alpha is required:
                    colour.a = alpha;
                }
            }
            else if (Border.Colour.Length == 1)
            {
                // Get the only colour:
                colour = Border.Colour[0];
            }
            else
            {
                // Get the first colour:
                colour = Border.Colour[FromIndex];
            }

            // Grab the clipping boundary:
            BoxRegion clip = renderer.ClippingBoundary;

            // Make it relative to the corners location:
            float minClipX = clip.X - cornerX;
            float minClipY = clip.Y - cornerY;
            float maxClipX = clip.MaxX - cornerX;
            float maxClipY = clip.MaxY - cornerY;

            // For each block..
            for (int i = 0; i < BlocksRequired; i++)
            {
                // Get a block:
                MeshBlock block = Border.Add();

                // Read the outer arc:
                Vector2 outerPointA = OuterArc[i];

                // Figure out the bounding box (constant for a particular block).
                float minX = outerPointA.x;
                float maxX = minX;
                float minY = outerPointA.y;
                float maxY = minY;

                Vector2 outerPointB = OuterArc[i + 1];

                // Update the bounding box:
                if (outerPointB.x < minX)
                {
                    minX = outerPointB.x;
                }
                else if (outerPointB.x > maxX)
                {
                    maxX = outerPointB.x;
                }

                if (outerPointB.y < minY)
                {
                    minY = outerPointB.y;
                }
                else if (outerPointB.y > maxY)
                {
                    maxY = outerPointB.y;
                }

                // Line segment A->B on the "outer" arc.

                // Read the inner arc:
                Vector2 innerPointA = InnerArc[i];

                // Update the bounding box:
                if (innerPointA.x < minX)
                {
                    minX = innerPointA.x;
                }
                else if (innerPointA.x > maxX)
                {
                    maxX = innerPointA.x;
                }

                if (innerPointA.y < minY)
                {
                    minY = innerPointA.y;
                }
                else if (innerPointA.y > maxY)
                {
                    maxY = innerPointA.y;
                }

                Vector2 innerPointB = InnerArc[i + 1];

                // Update the bounding box:
                if (innerPointB.x < minX)
                {
                    minX = innerPointB.x;
                }
                else if (innerPointB.x > maxX)
                {
                    maxX = innerPointB.x;
                }

                if (innerPointB.y < minY)
                {
                    minY = innerPointB.y;
                }
                else if (innerPointB.y > maxY)
                {
                    maxY = innerPointB.y;
                }

                // How does our bounding box compare to the clipping region?
                if (maxX < minClipX)
                {
                    continue;
                }
                else if (minX > maxClipX)
                {
                    continue;
                }

                if (maxY < minClipY)
                {
                    continue;
                }
                else if (minY > maxClipY)
                {
                    continue;
                }

                // Line segment A->B on the "inner" arc.

                // Set the UV to that of the solid block colour pixel:
                block.SetSolidColourUV();

                // Get the border colour:
                if (i == halfway)
                {
                    // Get the next colour:

                    if (Border.Colour != null && Border.Colour.Length != 1)
                    {
                        colour = Border.Colour[ToIndex];
                    }
                }

                // Set the border colour:
                block.SetColour(colour);

                // Apply the block region:
                block.VertexTopLeft  = renderer.PixelToWorldUnit(cornerX + outerPointA.x, cornerY + outerPointA.y, zIndex);
                block.VertexTopRight = renderer.PixelToWorldUnit(cornerX + outerPointB.x, cornerY + outerPointB.y, zIndex);

                block.VertexBottomLeft  = renderer.PixelToWorldUnit(cornerX + innerPointA.x, cornerY + innerPointA.y, zIndex);
                block.VertexBottomRight = renderer.PixelToWorldUnit(cornerX + innerPointB.x, cornerY + innerPointB.y, zIndex);
            }
        }
Esempio n. 11
0
 /// <summary>Evaluates if one box overlaps another.</summary>
 /// <param name="box">The other box to check with.</param>
 /// <returns>True if the given box overlaps this one.</returns>
 public bool Overlaps(BoxRegion box)
 {
     return(box.X <= MaxX && box.MaxX >= X && box.Y <= MaxY && box.MaxY >= Y);
 }
		/// <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;
		}
		/// <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;
		}
		protected override void Layout(){
			
			if(Characters==null||FontToDraw==null||Characters.Length==0){
				return;
			}
			
			// The blocks we allocate here come from FontToDraw.
			// They use the same renderer and same layout service, but just a different mesh.
			// This is to enable potentially very large font atlases with multiple fonts.
			ComputedStyle computed=Element.Style.Computed;
			Renderman renderer=Element.Document.Renderer;
			
			float top=computed.OffsetTop + computed.StyleOffsetTop;
			float left=computed.OffsetLeft + computed.StyleOffsetLeft;
			
			// Should we auto-alias the text?
			
			// Note that this property "drags" to following elements which is correct.
			// We don't really want to break batching chains for aliasing.
			
			if(Alias==float.MaxValue){
				// Yep! Note all values here are const.
				float aliasing=Fonts.AutoAliasOffset - ( (FontSize-Fonts.AutoAliasRelative) * Fonts.AutoAliasRamp);
				
				if(aliasing>0.1f){
					renderer.FontAliasing=aliasing;
				}
				
			}else{
				
				// Write aliasing:
				renderer.FontAliasing=Alias;
				
			}
			
			if(Extrude!=0f){
				// Compute the extrude now:
				if(Text3D==null){
					Text3D=Get3D(FontSize,FontColour,ref left,ref top);
				}else{
					// Update it.
				}
				
				return;
				
			}else{
				Text3D=null;
			}
			
			
			if(!AllWhitespace){
				// Firstly, make sure the batch is using the right font texture.
				// This may generate a new batch if the font doesn't match the previous or existing font.
				
				// Get the full shape of the element:
				int width=computed.PaddedWidth;
				int height=computed.PaddedHeight;
				int minY=computed.OffsetTop+computed.BorderTop;
				int minX=computed.OffsetLeft+computed.BorderLeft;
				
				BoxRegion boundary=new BoxRegion(minX,minY,width,height);
				
				if(!boundary.Overlaps(renderer.ClippingBoundary)){
					
					if(Visible){
						SetVisibility(false);
					}
					
					return;
				}else if(!Visible){
					
					// ImageLocation will allocate here if it's needed.
					SetVisibility(true);
					
				}
				
			}
			
			float zIndex=computed.ZIndex;
			BoxRegion screenRegion=new BoxRegion();
			
			// First up, underline.
			if(TextLine!=null){
				// We have one. Locate it next.
				float lineWeight=(FontToDraw.StrikeSize * FontSize);
				float yOffset=0f;
				
				switch(TextLine.Type){
				
					case TextLineType.Underline:
						yOffset=Ascender + lineWeight;
					break;
					case TextLineType.StrikeThrough:
						yOffset=(FontToDraw.StrikeOffset * FontSize);
						yOffset=Ascender - yOffset;
					break;
					case TextLineType.Overline:
						yOffset=(lineWeight * 2f);
					break;
				}
				
				Color lineColour=FontColour;
				
				if(TextLine.ColourOverride){
					lineColour=TextLine.Colour;
				}
				
				screenRegion.Set(left,top+yOffset,computed.PixelWidth,lineWeight);
				
				if(screenRegion.Overlaps(renderer.ClippingBoundary)){
					
					// Ensure we have a batch:
					SetupBatch(null,null);
					
					// This region is visible. Clip it:
					screenRegion.ClipBy(renderer.ClippingBoundary);
					// And get our block ready:
					MeshBlock block=Add();
					// Set the UV to that of the solid block colour pixel:
					block.SetSolidColourUV();
					// Set the colour:
					block.SetColour(lineColour);
					
					block.SetClipped(renderer.ClippingBoundary,screenRegion,renderer,zIndex);
				}
				
			}
			
			
			// Next, render the characters.
			// If we're rendering from right to left, flip the punctuation over.
			
			// Is the word itself rightwards?
			bool rightwardWord=false;
			
			if(StartPunctuationCount<Characters.Length){
				// Is the first actual character a rightwards one?
				Glyph firstChar=Characters[StartPunctuationCount];
				
				if(firstChar!=null){
					rightwardWord=firstChar.Rightwards;
				}
				
			}
			
			// Right to left (e.g. arabic):
			if(computed.DrawDirection==DirectionType.RTL){
			
				int end=Characters.Length-EndPunctuationCount;
				
				// Draw the punctuation from the end of the string first, backwards:
				if(EndPunctuationCount>0){
					for(int i=Characters.Length-1;i>=end;i--){
						DrawInvertCharacter(i,ref left,top,renderer,zIndex,screenRegion);
					}
				}
				
				if(rightwardWord){
					// Render the word itself backwards.
					
					for(int i=end-1;i>=StartPunctuationCount;i--){
						DrawCharacter(i,ref left,top,renderer,zIndex,screenRegion);
					}
					
				}else{
				
					// Draw the middle characters:
					for(int i=StartPunctuationCount;i<end;i++){
						DrawCharacter(i,ref left,top,renderer,zIndex,screenRegion);
					}
					
				}
				
				// Draw the punctuation from the start of the string last, backwards:
				
				if(StartPunctuationCount>0){
					
					for(int i=StartPunctuationCount-1;i>=0;i--){
						DrawInvertCharacter(i,ref left,top,renderer,zIndex,screenRegion);
					}
					
				}
				
			}else if(rightwardWord){
				
				// Render the word itself backwards.
				
				for(int i=Characters.Length-1;i>=0;i--){
					DrawCharacter(i,ref left,top,renderer,zIndex,screenRegion);
				}
				
			}else{
				
				// Draw it as is.
				
				for(int i=0;i<Characters.Length;i++){
					
					DrawCharacter(i,ref left,top,renderer,zIndex,screenRegion);
				}
				
			}
			
		}
Esempio n. 15
0
        public void AddViewBoxTransform(BoxRegion region, AspectRatio aspectRatio, SVGSVGElement frag)
        {
            // Get the tags computed style:
            Css.ComputedStyle tagStyle = (frag == null) ? null : frag.Style.Computed;

            float x = (tagStyle == null ? 0 : tagStyle.OffsetLeft);
            float y = (tagStyle == null ? 0 : tagStyle.OffsetTop);

            if (region.IsEmpty)
            {
                PushMatrix(TranslateMatrix(x, y));
                return;
            }

            float width  = (tagStyle == null ? region.Width : tagStyle.PixelWidth);
            float height = (tagStyle == null ? region.Height : tagStyle.PixelHeight);

            float fScaleX = width / region.Width;
            float fScaleY = height / region.Height;             //(this.MinY < 0 ? -1 : 1) *
            float fMinX   = -region.X * fScaleX;
            float fMinY   = -region.Y * fScaleY;

            if (aspectRatio == null)
            {
                aspectRatio = new AspectRatio(SVGPreserveAspectRatio.xMidYMid, false);
            }

            if (aspectRatio.Align != SVGPreserveAspectRatio.none)
            {
                if (aspectRatio.Slice)
                {
                    fScaleX = (float)Math.Max(fScaleX, fScaleY);
                    fScaleY = (float)Math.Max(fScaleX, fScaleY);
                }
                else
                {
                    fScaleX = (float)Math.Min(fScaleX, fScaleY);
                    fScaleY = (float)Math.Min(fScaleX, fScaleY);
                }

                float fViewMidX = (region.Width / 2) * fScaleX;
                float fViewMidY = (region.Height / 2) * fScaleY;
                float fMidX     = width / 2;
                float fMidY     = height / 2;
                fMinX = -region.X * fScaleX;
                fMinY = -region.Y * fScaleY;

                switch (aspectRatio.Align)
                {
                case SVGPreserveAspectRatio.xMinYMin:
                    break;

                case SVGPreserveAspectRatio.xMidYMin:
                    fMinX += fMidX - fViewMidX;
                    break;

                case SVGPreserveAspectRatio.xMaxYMin:
                    fMinX += width - region.Width * fScaleX;
                    break;

                case SVGPreserveAspectRatio.xMinYMid:
                    fMinY += fMidY - fViewMidY;
                    break;

                case SVGPreserveAspectRatio.xMidYMid:
                    fMinX += fMidX - fViewMidX;
                    fMinY += fMidY - fViewMidY;
                    break;

                case SVGPreserveAspectRatio.xMaxYMid:
                    fMinX += width - region.Width * fScaleX;
                    fMinY += fMidY - fViewMidY;
                    break;

                case SVGPreserveAspectRatio.xMinYMax:
                    fMinY += height - region.Height * fScaleY;
                    break;

                case SVGPreserveAspectRatio.xMidYMax:
                    fMinX += fMidX - fViewMidX;
                    fMinY += height - region.Height * fScaleY;
                    break;

                case SVGPreserveAspectRatio.xMaxYMax:
                    fMinX += width - region.Width * fScaleX;
                    fMinY += height - region.Height * fScaleY;
                    break;

                default:
                    break;
                }
            }

            // Clip now:
            SetClip(new BoxRegion(x, y, width, height), false);

            Matrix4x4 matrix = ScaleMatrix(fScaleX, fScaleY);

            matrix *= TranslateMatrix(x, y);
            matrix *= TranslateMatrix(fMinX, fMinY);

            // Push it:
            PushMatrix(matrix);
        }
Esempio n. 16
0
        /// <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;
        }
Esempio n. 17
0
        /// <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;
        }
Esempio n. 18
0
//--------------------------------------
		protected override void Layout(){
			if(Image==null || !Image.Loaded()){
				return;
			}
			
			if(Clipping==BackgroundClipping.Text){
				return;
			}
			
			Renderman renderer=Element.Document.Renderer;
			
			if(Image.Animated || Image.IsDynamic || renderer.RenderMode==RenderMode.NoAtlas || Filtering!=FilterMode.Point || ForcedIsolate){
				// SPA is an animation format, so we need a custom texture atlas to deal with it.
				// This is because the frames of any animation would quickly exhaust our global texture atlas.
				// So to get a custom atlas, we must isolate this property.
				Isolate();
			}else if(Image.IsVideo){
				// Similarly with a video, we need to isolate it aswell.
				Isolate();
				
				#if !MOBILE
				if(!Image.Video.isPlaying && Element["autoplay"]!=null){
					// Play now:
					Image.Video.Play();
					
					// Fire an onplay event:
					Element.Run("onplay");
					
					// Clear:
					Element["autoplay"]=null;
				}
				
				#endif
			}else{
				// Reverse isolation, if we are isolated already:
				Include();
			}
			
			ComputedStyle computed=Element.Style.Computed;
			
			// Get the full shape of the element:
			int width=computed.PaddedWidth;
			int height=computed.PaddedHeight;
			int minY=computed.OffsetTop+computed.BorderTop;
			int minX=computed.OffsetLeft+computed.BorderLeft;
			
			if(width==0||height==0){
				if(Visible){
					SetVisibility(false);
				}
				return;
			}
			
			BoxRegion boundary=new BoxRegion(minX,minY,width,height);
			
			if(!boundary.Overlaps(renderer.ClippingBoundary)){
				
				if(Visible){
					SetVisibility(false);
				}
				
				return;
			}else if(!Visible){
				
				// ImageLocation will allocate here if it's needed.
				SetVisibility(true);
				
			}
			
			boundary.ClipBy(renderer.ClippingBoundary);
			
			// Texture time - get it's location on that atlas:
			AtlasLocation locatedAt=ImageLocation;
			
			if(locatedAt==null){
				// We're not using the atlas here.
				
				if(!Isolated){
					Isolate();
				}
				
				int imgWidth=Image.Width();
				int imgHeight=Image.Height();
				locatedAt=new AtlasLocation(0,0,imgWidth,imgHeight,imgWidth,imgHeight);
			}
			
			// Isolation is all done - safe to setup the batch now:
			SetupBatch(locatedAt.Atlas,null);
			
			// Great - Use locatedAt.Width/locatedAt.Height - this removes any risk of overflowing into some other image.
			
			int imageCountX=1;
			int imageCountY=1;
			int trueImageWidth=locatedAt.Width;
			int trueImageHeight=locatedAt.Height;
			int imageWidth=trueImageWidth;
			int imageHeight=trueImageHeight;
			bool autoX=false;
			bool autoY=false;
			
			if(Image.PixelPerfect){
				imageWidth=(int)(imageWidth*ScreenInfo.ResolutionScale);
				imageHeight=(int)(imageWidth*ScreenInfo.ResolutionScale);
			}
			
			if(SizeX!=null){
				if(SizeX.Single!=0f){
					imageWidth=(int)(width*SizeX.Single);
				}else if(SizeX.PX!=0){
					imageWidth=SizeX.PX;
				}else if(SizeX.IsAuto()){
					autoX=true;
				}
			}
			
			if(SizeY!=null){
				if(SizeY.Single!=0f){
					imageHeight=(int)(height*SizeY.Single);
				}else if(SizeY.PX!=0){
					imageHeight=SizeY.PX;
				}else if(SizeY.IsAuto()){
					autoY=true;
				}
			}
			
			if(autoX){
				
				imageWidth=imageHeight * trueImageWidth / trueImageHeight;
				
			}else if(autoY){
				
				imageHeight=imageWidth * trueImageHeight / trueImageWidth;
				
			}
			
			// offsetX and offsetY are the images position offset from where it should be (e.g. x of -200 means it's 200px left)
			
			// Resolve the true offset values:
			int offsetX=0;
			int offsetY=0;
			
			if(OffsetX!=null){
				
				// Resolve a potential mixed % and px:
				offsetX=OffsetX.GetMixed(width-imageWidth);
				
			}
			
			if(OffsetY!=null){
				
				// Resolve a potential mixed % and px:
				offsetY=OffsetY.GetMixed(height-imageHeight);
				
			}
			
			if(RepeatX){
				// Get the rounded up number of images:
				imageCountX=(width-1)/imageWidth+1;
				
				if(offsetX!=0){
					// If we have an offset, another image is introduced.
					imageCountX++;
				}
			}
			
			if(RepeatY){
				// Get the rounded up number of images:
				imageCountY=(height-1)/imageHeight+1;
				if(offsetY!=0){
					// If we have an offset, another image is introduced.
					imageCountY++;
				}
			}
			
			int blockX=minX+offsetX;
			int blockY=minY+offsetY;
			
			if(RepeatX&&offsetX>0){
				// We're repeating and the image is offset by a +ve number.
				// This means a small gap, OffsetX px wide, is open on this left side.
				// So to fill it, we need to offset this first image by a much bigger number - the value imageWidth-OffsetX.
				blockX-=(imageWidth-offsetX);
				// This results in the first image having OffsetX pixels exposed in the box - this is what we want.
			}
			
			if(RepeatY&&offsetY>0){
				// Similar thing to above:
				blockY-=(imageHeight-offsetY);
			}
			
			BoxRegion screenRegion=new BoxRegion();

			bool first=true;
			int startX=blockX;
			Color colour=computed.ColorOverlay;
			float zIndex=(computed.ZIndex-0.003f);
			
			for(int y=0;y<imageCountY;y++){
				for(int x=0;x<imageCountX;x++){
					// Draw at blockX/blockY.
					screenRegion.Set(blockX,blockY,imageWidth,imageHeight);
					
					if(screenRegion.Overlaps(boundary)){
						// If the two overlap, this means it's actually visible.
						MeshBlock block=Add();
						
						if(Image.Animated&&first){
							first=false;
							// Make sure we have an instance:
							Image.GoingOnDisplay();
							block.ParentMesh.SetMaterial(Image.Animation.AnimatedMaterial);
						}else if(Image.IsVideo&&first){
							first=false;
							block.ParentMesh.SetMaterial(Image.VideoMaterial);
						}else if(Isolated&&first){
							first=false;
							block.ParentMesh.SetMaterial(Image.ImageMaterial);
						}
						
						// Set it's colour:
						block.SetColour(colour);
						
						// And clip our meshblock to fit within boundary:
						block.TextUV=null;
						block.ImageUV=block.SetClipped(boundary,screenRegion,renderer,zIndex,locatedAt,block.ImageUV);
					}
					
					blockX+=imageWidth;
				}
				blockX=startX;
				blockY+=imageHeight;
			}
			
		}
Esempio n. 20
0
        protected override void Layout()
        {
            if (Corners != null)
            {
                Corners.PreLayout();
            }

            ComputedStyle computed = Element.Style.Computed;

            // Find the zIndex:
            // NB: At same depth as BGColour - right at the back.
            float zIndex = (computed.ZIndex - 0.006f);

            // Get the co-ord of the top edge:
            int top  = computed.OffsetTop;
            int left = computed.OffsetLeft;

            // And the dimensions of the lines:
            // Note: boxwidth doesn't include the left/right widths to prevent overlapping.
            int boxWidth  = computed.PaddedWidth;
            int boxHeight = computed.PaddedHeight + WidthTop + WidthBottom;

            BoxRegion screenRegion = new BoxRegion();
            Renderman renderer     = Element.Document.Renderer;

            // Get the default colour - that's the same as the text colour:
            Color colour = Color.black;

            // Is the border multicoloured?
            bool multiColour = false;

            // Does this border have a colour?
            if (Colour == null)
            {
                // Grab the text colour if there is one:
                if (computed.Text != null)
                {
                    // It's the same as the font colour:
                    colour = computed.Text.FontColour;
                }
                else
                {
                    // Nope - We need to set alpha:
                    colour.a = computed.ColorOverlay.a;
                }
            }
            else if (Colour.Length == 1)
            {
                colour = Colour[0];
            }
            else
            {
                multiColour = true;
            }

            for (int i = 0; i < 4; i++)
            {
                int lineHeight = 0;
                int lineWidth  = 0;

                // Co-ords of the top-left corner for our box:
                int cornerY = top;
                int cornerX = left;

                if (i == 0 || i == 2)
                {
                    // Top or bottom:
                    lineWidth  = boxWidth;
                    lineHeight = BorderWidth(i);
                }
                else
                {
                    lineWidth  = BorderWidth(i);
                    lineHeight = boxHeight;
                }

                // Does this border have multiple colours?
                if (multiColour)
                {
                    colour = Colour[i];
                }

                if (Corners != null)
                {
                    Corners.Layout(i, ref cornerX, ref cornerY, ref lineWidth, ref lineHeight);
                }
                else
                {
                    switch (i)
                    {
                    case 0:
                        // Top:
                        cornerX += WidthLeft;

                        break;

                    case 1:
                        // Right:
                        cornerX += boxWidth + WidthLeft;

                        break;

                    case 2:
                        // Bottom:
                        cornerY += boxHeight - WidthBottom;
                        cornerX += WidthLeft;

                        break;
                    }
                }

                screenRegion.Set(cornerX, cornerY, lineWidth, lineHeight);

                if (screenRegion.Overlaps(renderer.ClippingBoundary))
                {
                    // This region is visible. Clip it:
                    screenRegion.ClipBy(renderer.ClippingBoundary);

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

                    // And get our block ready:
                    MeshBlock block = Add();

                    // Set the UV to that of the solid block colour pixel:
                    block.SetSolidColourUV();

                    // Set the border colour:
                    block.SetColour(colour);

                    block.SetClipped(renderer.ClippingBoundary, screenRegion, renderer, zIndex);
                }
            }
        }
		protected override void Layout(){
			
			if(Corners!=null){
				Corners.PreLayout();
			}
			
			ComputedStyle computed=Element.Style.Computed;
			
			// Find the zIndex:
			// NB: At same depth as BGColour - right at the back.
			float zIndex=(computed.ZIndex-0.006f);
			
			// Get the co-ord of the top edge:
			int top=computed.OffsetTop;
			int left=computed.OffsetLeft;
			
			// And the dimensions of the lines:
			// Note: boxwidth doesn't include the left/right widths to prevent overlapping.
			int boxWidth=computed.PaddedWidth;
			int boxHeight=computed.PaddedHeight+WidthTop+WidthBottom;
			
			BoxRegion screenRegion=new BoxRegion();
			Renderman renderer=Element.Document.Renderer;
			
			// Get the default colour - that's the same as the text colour:
			Color colour=Color.black;
			
			// Is the border multicoloured?
			bool multiColour=false;
			
			// Does this border have a colour?
			if(Colour==null){
				
				// Grab the text colour if there is one:
				if(computed.Text!=null){
					
					// It's the same as the font colour:
					colour=computed.Text.FontColour;
					
				}else{
				
					// Nope - We need to set alpha:
					colour.a=computed.ColorOverlay.a;
					
				}
				
			}else if(Colour.Length==1){
				colour=Colour[0];
			}else{
				multiColour=true;
			}
			
			for(int i=0;i<4;i++){
				int lineHeight=0;
				int lineWidth=0;
				
				// Co-ords of the top-left corner for our box:
				int cornerY=top;
				int cornerX=left;
				
				if(i==0 || i==2){
					// Top or bottom:
					lineWidth=boxWidth;
					lineHeight=BorderWidth(i);
				}else{
					lineWidth=BorderWidth(i);
					lineHeight=boxHeight;
				}
				
				// Does this border have multiple colours?
				if(multiColour){
					colour=Colour[i];
				}
				
				if(Corners!=null){
					Corners.Layout(i,ref cornerX,ref cornerY,ref lineWidth,ref lineHeight);
				}else{
					switch(i){
						case 0:
							// Top:
							cornerX+=WidthLeft;
							
						break;
						case 1:
							// Right:
							cornerX+=boxWidth+WidthLeft;
							
						break;
						case 2:
							// Bottom:
							cornerY+=boxHeight-WidthBottom;
							cornerX+=WidthLeft;
							
						break;
					}
				}
				
				screenRegion.Set(cornerX,cornerY,lineWidth,lineHeight);
				
				if(screenRegion.Overlaps(renderer.ClippingBoundary)){
					
					// This region is visible. Clip it:
					screenRegion.ClipBy(renderer.ClippingBoundary);
					
					// Ensure we have a batch (doesn't change graphics or font textures, thus both null):
					SetupBatch(null,null);
					
					// And get our block ready:
					MeshBlock block=Add();
					
					// Set the UV to that of the solid block colour pixel:
					block.SetSolidColourUV();
					
					// Set the border colour:
					block.SetColour(colour);
					
					block.SetClipped(renderer.ClippingBoundary,screenRegion,renderer,zIndex);
				}
				
			}
		}
Esempio n. 22
0
        protected override void Layout()
        {
            if (Image == null || !Image.Loaded())
            {
                return;
            }

            if (Clipping == BackgroundClipping.Text)
            {
                return;
            }

            Renderman renderer = Element.Document.Renderer;

            if (Image.Animated || Image.IsDynamic || renderer.RenderMode == RenderMode.NoAtlas || Filtering != FilterMode.Point || ForcedIsolate)
            {
                // SPA is an animation format, so we need a custom texture atlas to deal with it.
                // This is because the frames of any animation would quickly exhaust our global texture atlas.
                // So to get a custom atlas, we must isolate this property.
                Isolate();
            }
            else if (Image.IsVideo)
            {
                // Similarly with a video, we need to isolate it aswell.
                Isolate();

                                #if !MOBILE
                if (!Image.Video.isPlaying && Element["autoplay"] != null)
                {
                    // Play now:
                    Image.Video.Play();

                    // Fire an onplay event:
                    Element.Run("onplay");

                    // Clear:
                    Element["autoplay"] = null;
                }
                                #endif
            }
            else
            {
                // Reverse isolation, if we are isolated already:
                Include();
            }

            ComputedStyle computed = Element.Style.Computed;

            // Get the full shape of the element:
            int width  = computed.PaddedWidth;
            int height = computed.PaddedHeight;
            int minY   = computed.OffsetTop + computed.BorderTop;
            int minX   = computed.OffsetLeft + computed.BorderLeft;

            if (width == 0 || height == 0)
            {
                if (Visible)
                {
                    SetVisibility(false);
                }
                return;
            }

            BoxRegion boundary = new BoxRegion(minX, minY, width, height);

            if (!boundary.Overlaps(renderer.ClippingBoundary))
            {
                if (Visible)
                {
                    SetVisibility(false);
                }

                return;
            }
            else if (!Visible)
            {
                // ImageLocation will allocate here if it's needed.
                SetVisibility(true);
            }

            boundary.ClipBy(renderer.ClippingBoundary);

            // Texture time - get it's location on that atlas:
            AtlasLocation locatedAt = ImageLocation;

            if (locatedAt == null)
            {
                // We're not using the atlas here.

                if (!Isolated)
                {
                    Isolate();
                }

                int imgWidth  = Image.Width();
                int imgHeight = Image.Height();
                locatedAt = new AtlasLocation(0, 0, imgWidth, imgHeight, imgWidth, imgHeight);
            }

            // Isolation is all done - safe to setup the batch now:
            SetupBatch(locatedAt.Atlas, null);

            // Great - Use locatedAt.Width/locatedAt.Height - this removes any risk of overflowing into some other image.

            int  imageCountX     = 1;
            int  imageCountY     = 1;
            int  trueImageWidth  = locatedAt.Width;
            int  trueImageHeight = locatedAt.Height;
            int  imageWidth      = trueImageWidth;
            int  imageHeight     = trueImageHeight;
            bool autoX           = false;
            bool autoY           = false;

            if (Image.PixelPerfect)
            {
                imageWidth  = (int)(imageWidth * ScreenInfo.ResolutionScale);
                imageHeight = (int)(imageWidth * ScreenInfo.ResolutionScale);
            }

            if (SizeX != null)
            {
                if (SizeX.Single != 0f)
                {
                    imageWidth = (int)(width * SizeX.Single);
                }
                else if (SizeX.PX != 0)
                {
                    imageWidth = SizeX.PX;
                }
                else if (SizeX.IsAuto())
                {
                    autoX = true;
                }
            }

            if (SizeY != null)
            {
                if (SizeY.Single != 0f)
                {
                    imageHeight = (int)(height * SizeY.Single);
                }
                else if (SizeY.PX != 0)
                {
                    imageHeight = SizeY.PX;
                }
                else if (SizeY.IsAuto())
                {
                    autoY = true;
                }
            }

            if (autoX)
            {
                imageWidth = imageHeight * trueImageWidth / trueImageHeight;
            }
            else if (autoY)
            {
                imageHeight = imageWidth * trueImageHeight / trueImageWidth;
            }

            // offsetX and offsetY are the images position offset from where it should be (e.g. x of -200 means it's 200px left)

            // Resolve the true offset values:
            int offsetX = 0;
            int offsetY = 0;

            if (OffsetX != null)
            {
                // Resolve a potential mixed % and px:
                offsetX = OffsetX.GetMixed(width - imageWidth);
            }

            if (OffsetY != null)
            {
                // Resolve a potential mixed % and px:
                offsetY = OffsetY.GetMixed(height - imageHeight);
            }

            if (RepeatX)
            {
                // Get the rounded up number of images:
                imageCountX = (width - 1) / imageWidth + 1;

                if (offsetX != 0)
                {
                    // If we have an offset, another image is introduced.
                    imageCountX++;
                }
            }

            if (RepeatY)
            {
                // Get the rounded up number of images:
                imageCountY = (height - 1) / imageHeight + 1;
                if (offsetY != 0)
                {
                    // If we have an offset, another image is introduced.
                    imageCountY++;
                }
            }

            int blockX = minX + offsetX;
            int blockY = minY + offsetY;

            if (RepeatX && offsetX > 0)
            {
                // We're repeating and the image is offset by a +ve number.
                // This means a small gap, OffsetX px wide, is open on this left side.
                // So to fill it, we need to offset this first image by a much bigger number - the value imageWidth-OffsetX.
                blockX -= (imageWidth - offsetX);
                // This results in the first image having OffsetX pixels exposed in the box - this is what we want.
            }

            if (RepeatY && offsetY > 0)
            {
                // Similar thing to above:
                blockY -= (imageHeight - offsetY);
            }

            BoxRegion screenRegion = new BoxRegion();

            bool  first  = true;
            int   startX = blockX;
            Color colour = computed.ColorOverlay;
            float zIndex = (computed.ZIndex - 0.003f);

            for (int y = 0; y < imageCountY; y++)
            {
                for (int x = 0; x < imageCountX; x++)
                {
                    // Draw at blockX/blockY.
                    screenRegion.Set(blockX, blockY, imageWidth, imageHeight);

                    if (screenRegion.Overlaps(boundary))
                    {
                        // If the two overlap, this means it's actually visible.
                        MeshBlock block = Add();

                        if (Image.Animated && first)
                        {
                            first = false;
                            // Make sure we have an instance:
                            Image.GoingOnDisplay();
                            block.ParentMesh.SetMaterial(Image.Animation.AnimatedMaterial);
                        }
                        else if (Image.IsVideo && first)
                        {
                            first = false;
                            block.ParentMesh.SetMaterial(Image.VideoMaterial);
                        }
                        else if (Isolated && first)
                        {
                            first = false;
                            block.ParentMesh.SetMaterial(Image.ImageMaterial);
                        }

                        // Set it's colour:
                        block.SetColour(colour);

                        // And clip our meshblock to fit within boundary:
                        block.TextUV  = null;
                        block.ImageUV = block.SetClipped(boundary, screenRegion, renderer, zIndex, locatedAt, block.ImageUV);
                    }

                    blockX += imageWidth;
                }
                blockX  = startX;
                blockY += imageHeight;
            }
        }
Esempio n. 23
0
        protected override void Layout()
        {
            if (Characters == null || FontToDraw == null || Characters.Length == 0)
            {
                return;
            }

            // The blocks we allocate here come from FontToDraw.
            // They use the same renderer and same layout service, but just a different mesh.
            // This is to enable potentially very large font atlases with multiple fonts.
            ComputedStyle computed = Element.Style.Computed;
            Renderman     renderer = Element.Document.Renderer;

            float top  = computed.OffsetTop + computed.StyleOffsetTop;
            float left = computed.OffsetLeft + computed.StyleOffsetLeft;

            // Should we auto-alias the text?

            // Note that this property "drags" to following elements which is correct.
            // We don't really want to break batching chains for aliasing.

            if (Alias == float.MaxValue)
            {
                // Yep! Note all values here are const.
                float aliasing = Fonts.AutoAliasOffset - ((FontSize - Fonts.AutoAliasRelative) * Fonts.AutoAliasRamp);

                if (aliasing > 0.1f)
                {
                    renderer.FontAliasing = aliasing;
                }
            }
            else
            {
                // Write aliasing:
                renderer.FontAliasing = Alias;
            }

            if (Extrude != 0f)
            {
                // Compute the extrude now:
                if (Text3D == null)
                {
                    Text3D = Get3D(FontSize, FontColour, ref left, ref top);
                }
                else
                {
                    // Update it.
                }

                return;
            }
            else
            {
                Text3D = null;
            }


            if (!AllWhitespace)
            {
                // Firstly, make sure the batch is using the right font texture.
                // This may generate a new batch if the font doesn't match the previous or existing font.

                // Get the full shape of the element:
                int width  = computed.PaddedWidth;
                int height = computed.PaddedHeight;
                int minY   = computed.OffsetTop + computed.BorderTop;
                int minX   = computed.OffsetLeft + computed.BorderLeft;

                BoxRegion boundary = new BoxRegion(minX, minY, width, height);

                if (!boundary.Overlaps(renderer.ClippingBoundary))
                {
                    if (Visible)
                    {
                        SetVisibility(false);
                    }

                    return;
                }
                else if (!Visible)
                {
                    // ImageLocation will allocate here if it's needed.
                    SetVisibility(true);
                }
            }

            float     zIndex       = computed.ZIndex;
            BoxRegion screenRegion = new BoxRegion();

            // First up, underline.
            if (TextLine != null)
            {
                // We have one. Locate it next.
                float lineWeight = (FontToDraw.StrikeSize * FontSize);
                float yOffset    = 0f;

                switch (TextLine.Type)
                {
                case TextLineType.Underline:
                    yOffset = Ascender + lineWeight;
                    break;

                case TextLineType.StrikeThrough:
                    yOffset = (FontToDraw.StrikeOffset * FontSize);
                    yOffset = Ascender - yOffset;
                    break;

                case TextLineType.Overline:
                    yOffset = (lineWeight * 2f);
                    break;
                }

                Color lineColour = FontColour;

                if (TextLine.ColourOverride)
                {
                    lineColour = TextLine.Colour;
                }

                screenRegion.Set(left, top + yOffset, computed.PixelWidth, lineWeight);

                if (screenRegion.Overlaps(renderer.ClippingBoundary))
                {
                    // Ensure we have a batch:
                    SetupBatch(null, null);

                    // This region is visible. Clip it:
                    screenRegion.ClipBy(renderer.ClippingBoundary);
                    // And get our block ready:
                    MeshBlock block = Add();
                    // Set the UV to that of the solid block colour pixel:
                    block.SetSolidColourUV();
                    // Set the colour:
                    block.SetColour(lineColour);

                    block.SetClipped(renderer.ClippingBoundary, screenRegion, renderer, zIndex);
                }
            }


            // Next, render the characters.
            // If we're rendering from right to left, flip the punctuation over.

            // Is the word itself rightwards?
            bool rightwardWord = false;

            if (StartPunctuationCount < Characters.Length)
            {
                // Is the first actual character a rightwards one?
                Glyph firstChar = Characters[StartPunctuationCount];

                if (firstChar != null)
                {
                    rightwardWord = firstChar.Rightwards;
                }
            }

            // Right to left (e.g. arabic):
            if (computed.DrawDirection == DirectionType.RTL)
            {
                int end = Characters.Length - EndPunctuationCount;

                // Draw the punctuation from the end of the string first, backwards:
                if (EndPunctuationCount > 0)
                {
                    for (int i = Characters.Length - 1; i >= end; i--)
                    {
                        DrawInvertCharacter(i, ref left, top, renderer, zIndex, screenRegion);
                    }
                }

                if (rightwardWord)
                {
                    // Render the word itself backwards.

                    for (int i = end - 1; i >= StartPunctuationCount; i--)
                    {
                        DrawCharacter(i, ref left, top, renderer, zIndex, screenRegion);
                    }
                }
                else
                {
                    // Draw the middle characters:
                    for (int i = StartPunctuationCount; i < end; i++)
                    {
                        DrawCharacter(i, ref left, top, renderer, zIndex, screenRegion);
                    }
                }

                // Draw the punctuation from the start of the string last, backwards:

                if (StartPunctuationCount > 0)
                {
                    for (int i = StartPunctuationCount - 1; i >= 0; i--)
                    {
                        DrawInvertCharacter(i, ref left, top, renderer, zIndex, screenRegion);
                    }
                }
            }
            else if (rightwardWord)
            {
                // Render the word itself backwards.

                for (int i = Characters.Length - 1; i >= 0; i--)
                {
                    DrawCharacter(i, ref left, top, renderer, zIndex, screenRegion);
                }
            }
            else
            {
                // Draw it as is.

                for (int i = 0; i < Characters.Length; i++)
                {
                    DrawCharacter(i, ref left, top, renderer, zIndex, screenRegion);
                }
            }
        }