public static void Create(Vector3 pos, string text, ColorRgba color) { GameObject pe = new GameObject(GameRes.Data.Prefabs.PowerupEffect_Prefab); pe.GetComponent<PowerupEffect>().Text = text; pe.GetComponent<TextRenderer>().ColorTint = color; pe.Transform.Pos = pos; Scene.Current.RegisterObj(pe); }
public PixelData(int width, int height, ColorRgba[] data) { if (data == null) throw new ArgumentNullException("data"); if (width < 0) throw new ArgumentException("Width may not be negative.", "width"); if (height < 0) throw new ArgumentException("Height may not be negative.", "height"); this.SetPixelDataRgba(data, width, height); }
public PixelData(int width, int height, ColorRgba backColor) { if (width < 0) throw new ArgumentException("Width may not be negative.", "width"); if (height < 0) throw new ArgumentException("Height may not be negative.", "height"); this.width = width; this.height = height; this.data = new ColorRgba[width * height]; for (int i = 0; i < this.data.Length; i++) this.data[i] = backColor; }
/// <summary> /// Extracts a Bitmaps pixel data. /// </summary> /// <param name="bm"></param> /// <returns></returns> public static ColorRgba[] GetPixelDataRgba(this Bitmap bm) { int[] argbValues = GetPixelDataIntArgb(bm); // Convert to ColorRGBA ColorRgba[] result = new ColorRgba[argbValues.Length]; unchecked { for (int i = 0; i < argbValues.Length; i++) result[i].SetIntArgb(argbValues[i]); } return result; }
public static void VisualizeAtlas(Bitmap bitmap, List<Rect> atlas) { ColorRgba atlasColor = new ColorRgba(255, 128, 128, 164); // Draw atlas rects if (atlas != null) { Pen atlasPen = new Pen(Color.FromArgb(atlasColor.A, atlasColor.R, atlasColor.G, atlasColor.B)); using (Graphics g = Graphics.FromImage(bitmap)) { foreach (Rect r in atlas) g.DrawRectangle(atlasPen, r.X, r.Y, r.W, r.H); } } }
void ICmpInitializable.OnInit(Component.InitContext context) { if (context == InitContext.Activate && DualityApp.ExecContext != DualityApp.ExecutionContext.Editor) { this.fade = 1.0f; TextRenderer r = this.GameObj.Renderer as TextRenderer; r.ColorTint = r.ColorTint.WithAlpha(MathF.Rnd.NextFloat(0.125f, 1.0f)); this.baseColor = r.ColorTint; float scale = MathF.Rnd.NextFloat(1.0f, 3.0f) * MathF.Rnd.NextFloat(0.5f, 1.0f); this.GameObj.Transform.RelativeScale = Vector3.One * scale; this.GameObj.Transform.RelativeVel += MathF.Rnd.NextVector3(1.0f / scale); this.GameObj.Transform.RelativeAngleVel += MathF.Rnd.NextFloat(-0.005f, 0.005f) / scale; } }
void ICmpUpdatable.OnUpdate() { Trigger trig = this.GameObj.GetComponent<Trigger>(); SpriteRenderer sprite = this.GameObj.GetComponent<SpriteRenderer>(); if (trig.Triggered && !this.wasTriggered) { this.oldColorTint = sprite.ColorTint; sprite.ColorTint = ColorRgba.Mix(this.oldColorTint, ColorRgba.Red, 0.5f); } else if (!trig.Triggered && this.wasTriggered) { sprite.ColorTint = this.oldColorTint; } this.wasTriggered = trig.Triggered; }
public static void SetPixelDataArgb(this PixelData pixelData, int[] data, int width = -1, int height = -1) { if (width < 0) width = pixelData.Width; if (height < 0) height = pixelData.Height; if (data.Length != width * height) throw new ArgumentException("Data length doesn't match width * height", "pixelData"); ColorRgba[] tempData = new ColorRgba[width * height]; Parallel.ForEach(Partitioner.Create(0, tempData.Length), range => { for (int i = range.Item1; i < range.Item2; i++) { tempData[i].A = (byte)((data[i] & 0xFF000000) >> 24); tempData[i].R = (byte)((data[i] & 0x00FF0000) >> 16); tempData[i].G = (byte)((data[i] & 0x0000FF00) >> 8); tempData[i].B = (byte)((data[i] & 0x000000FF) >> 0); } }); pixelData.SetData(tempData, width, height); }
public PixelData Read(Stream stream) { ColorRgba[] rawColorData; int width; int height; PixelData pixelData = new PixelData(); using (Bitmap bitmap = Bitmap.FromStream(stream) as Bitmap) { // Retrieve data BitmapData bitmapData = bitmap.LockBits( new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); int pixelCount = bitmapData.Width * bitmapData.Height; int[] argbValues = new int[pixelCount]; Marshal.Copy(bitmapData.Scan0, argbValues, 0, pixelCount); bitmap.UnlockBits(bitmapData); width = bitmapData.Width; height = bitmapData.Height; rawColorData = new ColorRgba[width * height]; Parallel.ForEach(Partitioner.Create(0, rawColorData.Length), range => { for (int i = range.Item1; i < range.Item2; i++) { rawColorData[i].A = (byte)((argbValues[i] & 0xFF000000) >> 24); rawColorData[i].R = (byte)((argbValues[i] & 0x00FF0000) >> 16); rawColorData[i].G = (byte)((argbValues[i] & 0x0000FF00) >> 8); rawColorData[i].B = (byte)((argbValues[i] & 0x000000FF) >> 0); } }); } pixelData.SetData(rawColorData, width, height); pixelData.ColorTransparentPixels(); return pixelData; }
protected void PrepareVerticesSmooth(ref VertexC1P3T4A1[] vertices, IDrawDevice device, float curAnimFrameFade, ColorRgba mainClr, Rect uvRect, Rect uvRectNext) { Vector3 posTemp = this.gameobj.Transform.Pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; MathF.GetTransformDotVec(this.GameObj.Transform.Angle, scaleTemp, out xDot, out yDot); Rect rectTemp = this.rect.Transformed(this.gameobj.Transform.Scale, this.gameobj.Transform.Scale); Vector2 edge1 = rectTemp.TopLeft; Vector2 edge2 = rectTemp.BottomLeft; Vector2 edge3 = rectTemp.BottomRight; Vector2 edge4 = rectTemp.TopRight; MathF.TransformDotVec(ref edge1, ref xDot, ref yDot); MathF.TransformDotVec(ref edge2, ref xDot, ref yDot); MathF.TransformDotVec(ref edge3, ref xDot, ref yDot); MathF.TransformDotVec(ref edge4, ref xDot, ref yDot); if (vertices == null || vertices.Length != 4) vertices = new VertexC1P3T4A1[4]; vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = uvRect.X; vertices[0].TexCoord.Y = uvRect.Y; vertices[0].TexCoord.Z = uvRectNext.X; vertices[0].TexCoord.W = uvRectNext.Y; vertices[0].Color = mainClr; vertices[0].Attrib = curAnimFrameFade; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = uvRect.X; vertices[1].TexCoord.Y = uvRect.BottomY; vertices[1].TexCoord.Z = uvRectNext.X; vertices[1].TexCoord.W = uvRectNext.BottomY; vertices[1].Color = mainClr; vertices[1].Attrib = curAnimFrameFade; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = uvRect.RightX; vertices[2].TexCoord.Y = uvRect.BottomY; vertices[2].TexCoord.Z = uvRectNext.RightX; vertices[2].TexCoord.W = uvRectNext.BottomY; vertices[2].Color = mainClr; vertices[2].Attrib = curAnimFrameFade; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = uvRect.RightX; vertices[3].TexCoord.Y = uvRect.Y; vertices[3].TexCoord.Z = uvRectNext.RightX; vertices[3].TexCoord.W = uvRectNext.Y; vertices[3].Color = mainClr; vertices[3].Attrib = curAnimFrameFade; if (this.pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
/// <summary> /// Creates a new complex Material. /// </summary> /// <param name="technique">The <see cref="Duality.Resources.DrawTechnique"/> to use.</param> /// <param name="mainColor">The <see cref="MainColor"/> to use.</param> /// <param name="textures">A set of <see cref="Duality.Resources.Texture">Textures</see> to use.</param> /// <param name="uniforms">A set of <see cref="Duality.Resources.ShaderFieldInfo">uniform values</see> to use.</param> public Material(ContentRef <DrawTechnique> technique, ColorRgba mainColor, Dictionary <string, ContentRef <Texture> > textures = null, Dictionary <string, float[]> uniforms = null) { this.info = new BatchInfo(technique, mainColor, textures, uniforms); }
/// <summary> /// Picks all <see cref="Duality.ICmpRenderer">ICmpRenderers</see> contained within the specified /// rectangular area. /// </summary> /// <param name="x">x-Coordinate of the Rect.</param> /// <param name="y">y-Coordinate of the Rect.</param> /// <param name="w">Width of the Rect.</param> /// <param name="h">Height of the Rect.</param> /// <returns>A set of all <see cref="Duality.ICmpRenderer">ICmpRenderers</see> that have been picked.</returns> public HashSet <ICmpRenderer> PickRenderersIn(int x, int y, int w, int h) { Rect dstRect = new Rect(x, y, w, h); Rect srcRect = new Rect(DualityApp.TargetResolution); if (!dstRect.Intersects(srcRect)) { return(new HashSet <ICmpRenderer>()); } dstRect = dstRect.Intersection(srcRect); this.RenderPickingMap(); x = Math.Max((int)dstRect.X, 0); y = Math.Max((int)dstRect.Y, 0); w = Math.Min((int)dstRect.W, this.pickingTex.PixelWidth - x); h = Math.Min((int)dstRect.H, this.pickingTex.PixelHeight - y); HashSet <ICmpRenderer> result = new HashSet <ICmpRenderer>(); int rendererIdLast = 0; unsafe { fixed(byte *pDataBegin = this.pickingBuffer) { for (int j = 0; j < h; ++j) { byte *pData = pDataBegin + 4 * (x + (y + j) * this.pickingTex.PixelWidth); for (int i = 0; i < w; ++i) { int rendererId = (*pData << 16) | (*(pData + 1) << 8) | (*(pData + 2) << 0); if (rendererId != rendererIdLast) { if (rendererId - 1 > this.pickingMap.Count) { Log.Core.WriteWarning("Unexpected picking result: {0}", ColorRgba.FromIntArgb(rendererId)); } else if (rendererId != 0 && !(this.pickingMap[rendererId - 1] as Component).Disposed) { result.Add(this.pickingMap[rendererId - 1]); } rendererIdLast = rendererId; } pData += 4; } } } } return(result); }
private void PrepareNextFrame() { byte[] internalBuffer = new byte[8]; if (streams[0].ReadUInt8(ref internalBuffer) == 1) { for (int i = 0; i < 256; i++) { byte r = streams[3].ReadUInt8(ref internalBuffer); byte g = streams[3].ReadUInt8(ref internalBuffer); byte b = streams[3].ReadUInt8(ref internalBuffer); /*byte a =*/ streams[3].ReadUInt8(ref internalBuffer); palette[i] = new ColorRgba(r, g, b); } } for (int y = 0; y < height; y++) { byte c; int x = 0; while ((c = streams[0].ReadUInt8(ref internalBuffer)) != 128) { if (c < 128) { int u; if (c == 0x00) { u = streams[0].ReadInt16(ref internalBuffer); } else { u = c; } for (int i = 0; i < u; i++) { byte pixel = streams[3].ReadUInt8(ref internalBuffer); currentBuffer[y * width + x] = pixel; x++; } } else { int u; if (c == 0x81) { u = streams[0].ReadInt16(ref internalBuffer); } else { u = c - 106; } int n = streams[1].ReadInt16(ref internalBuffer) + (streams[2].ReadUInt8(ref internalBuffer) + y - 127) * width; for (int i = 0; i < u; i++) { currentBuffer[y * width + x] = lastBuffer[n]; x++; n++; } } } } for (int i = 0; i < currentBuffer.Length; i++) { currentFrame.MainLayer.Data[i] = palette[currentBuffer[i]]; } videoTexture.LoadData(currentFrame, TextureSizeMode.NonPowerOfTwo); Buffer.BlockCopy(currentBuffer, 0, lastBuffer, 0, currentBuffer.Length); }
protected void PrepareVertices(ref VertexC1P3T2[] vertices, IDrawDevice device, ColorRgba mainClr, Rect uvRect) { Vector3 posTemp = this.gameobj.Transform.Pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; MathF.GetTransformDotVec(this.GameObj.Transform.Angle, scaleTemp, out xDot, out yDot); Rect rectTemp = this.rect.Transform(this.gameobj.Transform.Scale, this.gameobj.Transform.Scale); Vector2 edge1 = rectTemp.TopLeft; Vector2 edge2 = rectTemp.BottomLeft; Vector2 edge3 = rectTemp.BottomRight; Vector2 edge4 = rectTemp.TopRight; MathF.TransformDotVec(ref edge1, ref xDot, ref yDot); MathF.TransformDotVec(ref edge2, ref xDot, ref yDot); MathF.TransformDotVec(ref edge3, ref xDot, ref yDot); MathF.TransformDotVec(ref edge4, ref xDot, ref yDot); if (vertices == null || vertices.Length != 4) { vertices = new VertexC1P3T2[4]; } vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = uvRect.X; vertices[0].TexCoord.Y = uvRect.Y; vertices[0].Color = mainClr; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = uvRect.X; vertices[1].TexCoord.Y = uvRect.MaximumY; vertices[1].Color = mainClr; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = uvRect.MaximumX; vertices[2].TexCoord.Y = uvRect.MaximumY; vertices[2].Color = mainClr; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = uvRect.MaximumX; vertices[3].TexCoord.Y = uvRect.Y; vertices[3].Color = mainClr; if (this.pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
/// <summary> /// Emits sets of vertices for glyphs and icons based on this formatted text. To render it, use each set of vertices combined with /// the corresponding Fonts <see cref="Material"/>. /// </summary> /// <param name="vertText">One set of vertices for each Font that is available to this ForattedText.</param> /// <param name="vertIcons">A set of icon vertices.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="z">An Z-Offset applied to the position of each emitted vertex.</param> /// <param name="clr">The color value that is applied to each emitted vertex.</param> /// <param name="angle">An angle by which the text is rotated (before applying the offset).</param> /// <param name="scale">A factor by which the text is scaled (before applying the offset).</param> /// <returns> /// Returns an array of vertex counts for each emitted vertex array. /// Index 0 represents the number of emitted icon vertices, Index n represents the number of vertices emitted using Font n - 1. /// </returns> public int[] EmitVertices(ref VertexC1P3T2[][] vertText, ref VertexC1P3T2[] vertIcons, float x, float y, float z, ColorRgba clr, float angle = 0.0f, float scale = 1.0f) { Vector2 xDot, yDot; MathF.GetTransformDotVec(angle, scale, out xDot, out yDot); return this.EmitVertices(ref vertText, ref vertIcons, x, y, z, clr, xDot, yDot); }
public RenderState(FormattedText parent) { this.parent = parent; this.vertTextIndex = new int[this.parent.fonts != null ? this.parent.fonts.Length : 0]; this.font = (this.parent.fonts != null && this.parent.fonts.Length > 0) ? this.parent.fonts[0].Res : null; this.color = ColorRgba.White; this.lineAlign = parent.lineAlign; this.PeekLineStats(); this.offset.X = this.lineBeginX; }
/// <summary> /// Colors the log entry with the specified value. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entry"></param> /// <param name="color"></param> public static T WithColor <T>(this T entry, ColorRgba color) where T : VisualLogEntry { entry.Color = color; return(entry); }
protected void PrepareVerticesSmooth(ref VertexC1P3T4A1[] vertices, IDrawDevice device, float curAnimFrameFade, ColorRgba mainClr, Rect uvRect, Rect uvRectNext) { Vector3 pos = this.gameobj.Transform.Pos; Vector2 xDot, yDot; MathF.GetTransformDotVec(this.gameobj.Transform.Angle, this.gameobj.Transform.Scale, out xDot, out yDot); Rect rectTemp = rect.Transformed(gameobj.Transform.Scale, gameobj.Transform.Scale); Vector2 edge1 = rectTemp.TopLeft; Vector2 edge2 = rectTemp.BottomLeft; Vector2 edge3 = rectTemp.BottomRight; Vector2 edge4 = rectTemp.TopRight; MathF.TransformDotVec(ref edge1, ref xDot, ref yDot); MathF.TransformDotVec(ref edge2, ref xDot, ref yDot); MathF.TransformDotVec(ref edge3, ref xDot, ref yDot); MathF.TransformDotVec(ref edge4, ref xDot, ref yDot); float left = uvRect.X; float right = uvRect.RightX; float top = uvRect.Y; float bottom = uvRect.BottomY; float nextLeft = uvRectNext.X; float nextRight = uvRectNext.RightX; float nextTop = uvRectNext.Y; float nextBottom = uvRectNext.BottomY; if ((flipMode & FlipMode.Horizontal) != FlipMode.None) { edge1.X = -edge1.X; edge2.X = -edge2.X; edge3.X = -edge3.X; edge4.X = -edge4.X; } if ((flipMode & FlipMode.Vertical) != FlipMode.None) { edge1.Y = -edge1.Y; edge2.Y = -edge2.Y; edge3.Y = -edge3.Y; edge4.Y = -edge4.Y; } if (vertices == null /*|| vertices.Length != 4*/) { vertices = new VertexC1P3T4A1[4]; } vertices[0].Pos.X = pos.X + edge1.X; vertices[0].Pos.Y = pos.Y + edge1.Y; vertices[0].Pos.Z = pos.Z + VertexZOffset; vertices[0].TexCoord.X = left; vertices[0].TexCoord.Y = top; vertices[0].TexCoord.Z = nextLeft; vertices[0].TexCoord.W = nextTop; vertices[0].Color = mainClr; vertices[0].Attrib = curAnimFrameFade; vertices[1].Pos.X = pos.X + edge2.X; vertices[1].Pos.Y = pos.Y + edge2.Y; vertices[1].Pos.Z = pos.Z + VertexZOffset; vertices[1].TexCoord.X = left; vertices[1].TexCoord.Y = bottom; vertices[1].TexCoord.Z = nextLeft; vertices[1].TexCoord.W = nextBottom; vertices[1].Color = mainClr; vertices[1].Attrib = curAnimFrameFade; vertices[2].Pos.X = pos.X + edge3.X; vertices[2].Pos.Y = pos.Y + edge3.Y; vertices[2].Pos.Z = pos.Z + VertexZOffset; vertices[2].TexCoord.X = right; vertices[2].TexCoord.Y = bottom; vertices[2].TexCoord.Z = nextRight; vertices[2].TexCoord.W = nextBottom; vertices[2].Color = mainClr; vertices[2].Attrib = curAnimFrameFade; vertices[3].Pos.X = pos.X + edge4.X; vertices[3].Pos.Y = pos.Y + edge4.Y; vertices[3].Pos.Z = pos.Z + VertexZOffset; vertices[3].TexCoord.X = right; vertices[3].TexCoord.Y = top; vertices[3].TexCoord.Z = nextRight; vertices[3].TexCoord.W = nextTop; vertices[3].Color = mainClr; vertices[3].Attrib = curAnimFrameFade; if (pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
public static Geometry FromFileSystemEntry(FileSystemEntry entry) { var geometry = new Geometry(); using (var stream = entry.Open()) using (var reader = new StreamReader(stream)) { string line; int image = 0; float thickness = 0; Matrix2x2 rotMat = new Matrix2x2(); Vector2 translation = new Vector2(); ColorRgba color = new ColorRgba(0, 0, 0, 0); GeometryStyle style = GeometryStyle.Undefined; var tris = new List <Triangle2D>(); var lines = new List <Line2D>(); Action ApplyStyle = () => { switch (style) { //no data parsed yet case GeometryStyle.Undefined: break; case GeometryStyle.TexturedTri: geometry.Entries.Add(new GeometryTexturedTriangles(new List <Triangle2D>(tris), color, image, rotMat, translation)); tris.Clear(); break; case GeometryStyle.SolidTri: geometry.Entries.Add(new GeometrySolidTriangles(new List <Triangle2D>(tris), color)); tris.Clear(); break; case GeometryStyle.Line: geometry.Entries.Add(new GeometryLines(new List <Line2D>(lines), color, thickness)); lines.Clear(); break; } style = GeometryStyle.Undefined; }; while ((line = reader.ReadLine()) != null) { line = line.Trim(); var lineMode = line.First(); line = line.TrimStart('c', 's', 'l', 't'); var paramList = line.Split(':'); //trim each entry of the param list for (var i = 0; i < paramList.Length; ++i) { paramList[i] = paramList[i].Trim(); } switch (lineMode) { //Clear - Finish the last geometry case 'c': ApplyStyle(); break; //Style - Header for the following data case 's': //Check that we have atleast 1 param if (paramList.Length < 1) { throw new InvalidDataException(); } //Check which style we are using switch (paramList.First()) { //this is the solid triangle style case "s": if (paramList.Length != 5) { throw new InvalidDataException(); } style = GeometryStyle.SolidTri; color = new ColorRgba( Convert.ToByte(paramList[1]), Convert.ToByte(paramList[2]), Convert.ToByte(paramList[3]), Convert.ToByte(paramList[4])); break; //this is the line style case "l": if (paramList.Length != 6) { throw new InvalidDataException(); } style = GeometryStyle.Line; thickness = ParseUtility.ParseFloat(paramList[1]); color = new ColorRgba( Convert.ToByte(paramList[2]), Convert.ToByte(paramList[3]), Convert.ToByte(paramList[4]), Convert.ToByte(paramList[5])); break; //this is the textured triangle style case "tc": if (paramList.Length != 12) { throw new InvalidDataException(); } style = GeometryStyle.TexturedTri; color = new ColorRgba( Convert.ToByte(paramList[1]), Convert.ToByte(paramList[2]), Convert.ToByte(paramList[3]), Convert.ToByte(paramList[4])); //image id used image = Convert.ToInt32(paramList[5]); //transformation parameters, to map the geometry above the texture rotMat = new Matrix2x2( ParseUtility.ParseFloat(paramList[6]), ParseUtility.ParseFloat(paramList[7]), ParseUtility.ParseFloat(paramList[8]), ParseUtility.ParseFloat(paramList[9])); translation.X = ParseUtility.ParseFloat(paramList[10]); translation.Y = ParseUtility.ParseFloat(paramList[11]); break; } break; //A line case 'l': lines.Add(new Line2D( new Vector2(ParseUtility.ParseFloat(paramList[0]), ParseUtility.ParseFloat(paramList[1])), new Vector2(ParseUtility.ParseFloat(paramList[2]), ParseUtility.ParseFloat(paramList[3])))); break; //A triangle case 't': tris.Add(new Triangle2D( new Vector2(ParseUtility.ParseFloat(paramList[0]), ParseUtility.ParseFloat(paramList[1])), new Vector2(ParseUtility.ParseFloat(paramList[2]), ParseUtility.ParseFloat(paramList[3])), new Vector2(ParseUtility.ParseFloat(paramList[4]), ParseUtility.ParseFloat(paramList[5])))); break; } } ApplyStyle(); } geometry.CalculateBoundings(); return(geometry); }
public void DrawMaterial(string name, int frame, float x, float y, Alignment alignment, ColorRgba color, float scaleX = 1f, float scaleY = 1f) { if (metadata.Graphics.TryGetValue(name, out GraphicResource res)) { res.Draw(canvas, frame, x, y, alignment, color, scaleX, scaleY); } }
protected override void OnCollectStateWorldOverlayDrawcalls(Canvas canvas) { base.OnCollectStateWorldOverlayDrawcalls(canvas); // Assure we know how to display the current selection this.ValidateSelectionStats(); List<ObjectEditorSelObj> transformObjSel = this.allObjSel.Where(s => s.HasTransform).ToList(); Point cursorPos = this.PointToClient(Cursor.Position); canvas.PushState(); canvas.State.ZOffset = -1.0f; // Draw indirectly selected object overlay canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Solid, ColorRgba.Lerp(this.FgColor, this.BgColor, 0.75f))); this.DrawSelectionMarkers(canvas, this.indirectObjSel); if (this.mouseoverObject != null && (this.mouseoverAction == ObjectEditorAction.RectSelect || this.mouseoverSelect) && !transformObjSel.Contains(this.mouseoverObject)) this.DrawSelectionMarkers(canvas, new [] { this.mouseoverObject }); // Draw selected object overlay canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Solid, this.FgColor)); this.DrawSelectionMarkers(canvas, transformObjSel); // Draw overall selection boundary if (transformObjSel.Count > 1) { float midZ = transformObjSel.Average(t => t.Pos.Z); float maxZDiff = transformObjSel.Max(t => MathF.Abs(t.Pos.Z - midZ)); if (maxZDiff > 0.001f) { canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Solid, ColorRgba.Lerp(this.FgColor, this.BgColor, 0.5f))); canvas.DrawSphere( this.selectionCenter.X, this.selectionCenter.Y, this.selectionCenter.Z, this.selectionRadius); } else { canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Solid, ColorRgba.Lerp(this.FgColor, this.BgColor, 0.5f))); canvas.DrawCircle( this.selectionCenter.X, this.selectionCenter.Y, this.selectionCenter.Z, this.selectionRadius); } } // Draw scale action dots bool canMove = this.actionObjSel.Any(s => s.IsActionAvailable(ObjectEditorAction.Move)); bool canScale = (canMove && this.actionObjSel.Count > 1) || this.actionObjSel.Any(s => s.IsActionAvailable(ObjectEditorAction.Scale)); if (canScale) { float dotR = 3.0f / this.GetScaleAtZ(this.selectionCenter.Z); canvas.State.ZOffset -= 0.1f; canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Solid, this.FgColor)); canvas.FillCircle( this.selectionCenter.X + this.selectionRadius, this.selectionCenter.Y, this.selectionCenter.Z, dotR); canvas.FillCircle( this.selectionCenter.X - this.selectionRadius, this.selectionCenter.Y, this.selectionCenter.Z, dotR); canvas.FillCircle( this.selectionCenter.X, this.selectionCenter.Y + this.selectionRadius, this.selectionCenter.Z, dotR); canvas.FillCircle( this.selectionCenter.X, this.selectionCenter.Y - this.selectionRadius, this.selectionCenter.Z, dotR); canvas.State.ZOffset += 0.1f; } if (this.action != ObjectEditorAction.None) { // Draw action lock axes this.DrawLockedAxes(canvas, this.selectionCenter.X, this.selectionCenter.Y, this.selectionCenter.Z, this.selectionRadius * 4); } canvas.PopState(); }
void IGraphicsBackend.BeginRendering(IDrawDevice device, RenderOptions options, RenderStats stats) { DebugCheckOpenGLErrors(); this.currentDevice = device; this.renderStats = stats; // Prepare the target surface for rendering NativeRenderTarget.Bind(options.Target as NativeRenderTarget); // Determine whether masked blending should use alpha-to-coverage mode if (NativeRenderTarget.BoundRT != null) { this.useAlphaToCoverageBlend = NativeRenderTarget.BoundRT.Samples > 0; } else if (GraphicsBackend.ActiveInstance.ActiveWindow != null) { this.useAlphaToCoverageBlend = GraphicsBackend.ActiveInstance.ActiveWindow.IsMultisampled; } else { this.useAlphaToCoverageBlend = GraphicsBackend.ActiveInstance.DefaultGraphicsMode.Samples > 0; } if (this.primaryVBO == 0) { GL.GenBuffers(1, out this.primaryVBO); } GL.BindBuffer(BufferTarget.ArrayBuffer, this.primaryVBO); // Setup viewport Rect viewportRect = options.Viewport; GL.Viewport((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H); GL.Scissor((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H); // Clear buffers ClearBufferMask glClearMask = 0; ColorRgba clearColor = options.ClearColor; if ((options.ClearFlags & ClearFlag.Color) != ClearFlag.None) { glClearMask |= ClearBufferMask.ColorBufferBit; } if ((options.ClearFlags & ClearFlag.Depth) != ClearFlag.None) { glClearMask |= ClearBufferMask.DepthBufferBit; } GL.ClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f); GL.ClearDepth((double)options.ClearDepth); // The "float version" is from OpenGL 4.1.. GL.Clear(glClearMask); // Configure Rendering params if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Always); } else { GL.Enable(EnableCap.ScissorTest); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Lequal); } OpenTK.Matrix4 openTkModelView; Matrix4 modelView = options.ModelViewMatrix; GetOpenTKMatrix(ref modelView, out openTkModelView); GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref openTkModelView); OpenTK.Matrix4 openTkProjection; Matrix4 projection = options.ProjectionMatrix; GetOpenTKMatrix(ref projection, out openTkProjection); GL.MatrixMode(MatrixMode.Projection); GL.LoadMatrix(ref openTkProjection); if (NativeRenderTarget.BoundRT != null) { if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Translate(0.0f, viewportRect.H * 0.5f, 0.0f); } GL.Scale(1.0f, -1.0f, 1.0f); if (options.RenderMode == RenderMatrix.OrthoScreen) { GL.Translate(0.0f, -viewportRect.H * 0.5f, 0.0f); } } }
public override void Draw(Canvas target, Vector3 basePos, float baseRotation, float baseScale) { float originRadius = 5.0f; float vectorThickness = 4.0f; float borderRadius = DefaultOutlineWidth; float vectorLengthFactor = 1.0f; // Scale anti-proportional to perspective scale in order to keep a constant size // in screen space even when actually drawing in world space. { float scale = 1.0f; Vector3 posTemp = this.origin + basePos; target.DrawDevice.PreprocessCoords(ref posTemp, ref scale); originRadius /= scale; borderRadius /= scale; vectorThickness /= scale; if (this.invariantScale) { vectorLengthFactor /= scale; } } // Determine base and target positions Vector3 originPos = this.origin; Vector3 targetPos = this.origin + new Vector3(this.vec * vectorLengthFactor); MathF.TransformCoord(ref originPos.X, ref originPos.Y, baseRotation, baseScale); MathF.TransformCoord(ref targetPos.X, ref targetPos.Y, baseRotation, baseScale); originPos += basePos; targetPos += basePos; // Downscale vector arrow, if too small for display otherwise float vectorLen = (targetPos.Xy - originPos.Xy).Length; float vectorLenScale = MathF.Clamp(vectorLen / (vectorThickness * 7.0f), 0.0f, 1.0f); vectorThickness *= vectorLenScale; // Create arrow polygon Vector2 dirForward = (targetPos.Xy - originPos.Xy).Normalized; Vector2 dirLeft = dirForward.PerpendicularLeft; Vector2 dirRight = -dirLeft; Vector2[] arrow = new Vector2[7]; arrow[0] = dirLeft * vectorThickness * 0.5f; arrow[1] = dirLeft * vectorThickness * 0.5f + dirForward * (vectorLen - vectorThickness * 2); arrow[2] = dirLeft * vectorThickness * 1.25f + dirForward * (vectorLen - vectorThickness * 2); arrow[3] = dirForward * vectorLen; arrow[4] = dirRight * vectorThickness * 1.25f + dirForward * (vectorLen - vectorThickness * 2); arrow[5] = dirRight * vectorThickness * 0.5f + dirForward * (vectorLen - vectorThickness * 2); arrow[6] = dirRight * vectorThickness * 0.5f; Vector2[] arrowHead = new Vector2[3]; arrowHead[0] = arrow[2]; arrowHead[1] = arrow[3]; arrowHead[2] = arrow[4]; Vector2[] arrowLine = new Vector2[4]; arrowLine[0] = arrow[0]; arrowLine[1] = arrow[1]; arrowLine[2] = arrow[5]; arrowLine[3] = arrow[6]; // Draw vector and outline ColorRgba areaColor = target.State.ColorTint * this.Color; ColorRgba outlineColor = areaColor * ColorRgba.Black; target.State.ColorTint = areaColor; target.FillPolygon( arrowLine, originPos.X, originPos.Y, originPos.Z); target.FillPolygon( arrowHead, originPos.X, originPos.Y, originPos.Z); if (target.DrawDevice.DepthWrite) { target.State.ZOffset -= 0.1f; } target.State.ColorTint = outlineColor; target.FillPolygonOutline( arrow, borderRadius, originPos.X, originPos.Y, originPos.Z); // Draw origin and outline if (target.DrawDevice.DepthWrite) { target.State.ZOffset -= 0.1f; } target.State.ColorTint = areaColor; target.FillCircle( originPos.X, originPos.Y, originPos.Z, originRadius - borderRadius * 0.5f); if (target.DrawDevice.DepthWrite) { target.State.ZOffset -= 0.1f; } target.State.ColorTint = outlineColor; target.FillCircleSegment( originPos.X, originPos.Y, originPos.Z, originRadius, 0.0f, MathF.RadAngle360, borderRadius); }
private static void DrawTileHighlights(Canvas canvas, ICmpTilemapRenderer renderer, Point2 origin, IReadOnlyGrid<bool> highlight, ColorRgba fillTint, ColorRgba outlineTint, TileHighlightMode mode, List<Vector2[]> outlineCache = null) { if (highlight.Width == 0 || highlight.Height == 0) return; // Generate strippled line texture if not available yet if (strippledLineTex == null) { PixelData pixels = new PixelData(8, 1); for (int i = 0; i < pixels.Width / 2; i++) pixels[i, 0] = ColorRgba.White; for (int i = pixels.Width / 2; i < pixels.Width; i++) pixels[i, 0] = ColorRgba.TransparentWhite; using (Pixmap pixmap = new Pixmap(pixels)) { strippledLineTex = new Texture(pixmap, TextureSizeMode.Default, TextureMagFilter.Nearest, TextureMinFilter.Nearest, TextureWrapMode.Repeat, TextureWrapMode.Repeat, TexturePixelFormat.Rgba); } } BatchInfo defaultMaterial = new BatchInfo(DrawTechnique.Alpha, canvas.State.Material.MainColor); BatchInfo strippleMaterial = new BatchInfo(DrawTechnique.Alpha, canvas.State.Material.MainColor, strippledLineTex); bool uncertain = (mode & TileHighlightMode.Uncertain) != 0; bool selection = (mode & TileHighlightMode.Selection) != 0; Component component = renderer as Component; Transform transform = component.GameObj.Transform; Tilemap tilemap = renderer.ActiveTilemap; Tileset tileset = tilemap != null ? tilemap.Tileset.Res : null; Vector2 tileSize = tileset != null ? tileset.TileSize : Tileset.DefaultTileSize; Rect localRect = renderer.LocalTilemapRect; // Determine the object's local coordinate system (rotated, scaled) in world space Vector2 worldAxisX = Vector2.UnitX; Vector2 worldAxisY = Vector2.UnitY; MathF.TransformCoord(ref worldAxisX.X, ref worldAxisX.Y, transform.Angle, transform.Scale); MathF.TransformCoord(ref worldAxisY.X, ref worldAxisY.Y, transform.Angle, transform.Scale); Vector2 localOriginPos = tileSize * origin; Vector2 worldOriginPos = localOriginPos.X * worldAxisX + localOriginPos.Y * worldAxisY; canvas.PushState(); { // Configure the canvas so our shapes are properly rotated and scaled canvas.State.TransformHandle = -localRect.TopLeft; canvas.State.TransformAngle = transform.Angle; canvas.State.TransformScale = new Vector2(transform.Scale); // Fill all highlighted tiles that are currently visible { canvas.State.SetMaterial(defaultMaterial); canvas.State.ColorTint = fillTint * ColorRgba.White.WithAlpha(selection ? 0.2f : 0.375f); // Determine tile visibility Vector2 worldTilemapOriginPos = localRect.TopLeft; MathF.TransformCoord(ref worldTilemapOriginPos.X, ref worldTilemapOriginPos.Y, transform.Angle, transform.Scale); TilemapCulling.TileInput cullingIn = new TilemapCulling.TileInput { // Remember: All these transform values are in world space TilemapPos = transform.Pos + new Vector3(worldTilemapOriginPos) + new Vector3(worldOriginPos), TilemapScale = transform.Scale, TilemapAngle = transform.Angle, TileCount = new Point2(highlight.Width, highlight.Height), TileSize = tileSize }; TilemapCulling.TileOutput cullingOut = TilemapCulling.GetVisibleTileRect(canvas.DrawDevice, cullingIn); int renderedTileCount = cullingOut.VisibleTileCount.X * cullingOut.VisibleTileCount.Y; // Draw all visible highlighted tiles { Point2 tileGridPos = cullingOut.VisibleTileStart; Vector2 renderStartPos = worldOriginPos + tileGridPos.X * tileSize.X * worldAxisX + tileGridPos.Y * tileSize.Y * worldAxisY;; Vector2 renderPos = renderStartPos; Vector2 tileXStep = worldAxisX * tileSize.X; Vector2 tileYStep = worldAxisY * tileSize.Y; int lineMergeCount = 0; int totalRects = 0; for (int tileIndex = 0; tileIndex < renderedTileCount; tileIndex++) { bool current = highlight[tileGridPos.X, tileGridPos.Y]; if (current) { // Try to merge consecutive rects in the same line to reduce drawcalls / CPU load bool hasNext = (tileGridPos.X + 1 < highlight.Width) && ((tileGridPos.X + 1 - cullingOut.VisibleTileStart.X) < cullingOut.VisibleTileCount.X); bool next = hasNext ? highlight[tileGridPos.X + 1, tileGridPos.Y] : false; if (next) { lineMergeCount++; } else { totalRects++; canvas.FillRect( transform.Pos.X + renderPos.X - lineMergeCount * tileXStep.X, transform.Pos.Y + renderPos.Y - lineMergeCount * tileXStep.Y, transform.Pos.Z, tileSize.X * (1 + lineMergeCount), tileSize.Y); lineMergeCount = 0; } } tileGridPos.X++; renderPos += tileXStep; if ((tileGridPos.X - cullingOut.VisibleTileStart.X) >= cullingOut.VisibleTileCount.X) { tileGridPos.X = cullingOut.VisibleTileStart.X; tileGridPos.Y++; renderPos = renderStartPos; renderPos += tileYStep * (tileGridPos.Y - cullingOut.VisibleTileStart.Y); } } } } // Draw highlight area outlines, unless flagged as uncertain if (!uncertain) { // Determine the outlines of individual highlighted tile patches if (outlineCache == null) outlineCache = new List<Vector2[]>(); if (outlineCache.Count == 0) { GetTileAreaOutlines(highlight, tileSize, ref outlineCache); } // Draw outlines around all highlighted tile patches canvas.State.SetMaterial(selection ? strippleMaterial : defaultMaterial); canvas.State.ColorTint = outlineTint; foreach (Vector2[] outline in outlineCache) { // For strippled-line display, determine total length of outline if (selection) { float totalLength = 0.0f; for (int i = 1; i < outline.Length; i++) { totalLength += (outline[i - 1] - outline[i]).Length; } canvas.State.TextureCoordinateRect = new Rect(totalLength / strippledLineTex.PixelWidth, 1.0f); } // Draw the outline canvas.DrawPolygon( outline, transform.Pos.X + worldOriginPos.X, transform.Pos.Y + worldOriginPos.Y, transform.Pos.Z); } } // If this is an uncertain highlight, i.e. not actually reflecting the represented action, // draw a gizmo to indicate this for the user. if (uncertain) { Vector2 highlightSize = new Vector2(highlight.Width * tileSize.X, highlight.Height * tileSize.Y); Vector2 highlightCenter = highlightSize * 0.5f; Vector3 circlePos = transform.Pos + new Vector3(worldOriginPos + worldAxisX * highlightCenter + worldAxisY * highlightCenter); float circleRadius = MathF.Min(tileSize.X, tileSize.Y) * 0.2f; canvas.State.SetMaterial(defaultMaterial); canvas.State.ColorTint = outlineTint; canvas.FillCircle( circlePos.X, circlePos.Y, circlePos.Z, circleRadius); } } canvas.PopState(); }
protected void PrepareVerticesLightSmooth(ref VertexC1P3T4A4A1[] vertices, IDrawDevice device, float curAnimFrameFade, ColorRgba mainClr, Rect uvRect, Rect uvRectNext, DrawTechnique tech) { bool perPixel = tech is LightingTechnique; Vector3 pos = this.GameObj.Transform.Pos; Vector3 posTemp = pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; float rotation = this.GameObj.Transform.Angle; MathF.GetTransformDotVec(rotation, out xDot, out yDot); Rect rectTemp = this.rect.Transformed(this.GameObj.Transform.Scale, this.GameObj.Transform.Scale); Vector2 edge1 = rectTemp.TopLeft; Vector2 edge2 = rectTemp.BottomLeft; Vector2 edge3 = rectTemp.BottomRight; Vector2 edge4 = rectTemp.TopRight; MathF.TransformDotVec(ref edge1, ref xDot, ref yDot); MathF.TransformDotVec(ref edge2, ref xDot, ref yDot); MathF.TransformDotVec(ref edge3, ref xDot, ref yDot); MathF.TransformDotVec(ref edge4, ref xDot, ref yDot); // Using Per-Vertex Lighting? Calculate vertex light values Vector4[] vertexLight = null; if (!perPixel) { vertexLight = new Vector4[4]; Light.GetLightAtWorldPos(pos + new Vector3(edge1), out vertexLight[0], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge2), out vertexLight[1], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge3), out vertexLight[2], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge4), out vertexLight[3], this.vertexTranslucency); } Vector2.Multiply(ref edge1, scaleTemp, out edge1); Vector2.Multiply(ref edge2, scaleTemp, out edge2); Vector2.Multiply(ref edge3, scaleTemp, out edge3); Vector2.Multiply(ref edge4, scaleTemp, out edge4); // Using Per-Pixel Lighting? Pass objRotation Matrix via vertex attribute. Vector4 objRotMat = Vector4.Zero; if (perPixel) { objRotMat = new Vector4((float)Math.Cos(-rotation), -(float)Math.Sin(-rotation), (float)Math.Sin(-rotation), (float)Math.Cos(-rotation)); } if (vertices == null || vertices.Length != 4) { vertices = new VertexC1P3T4A4A1[4]; } // Calculate UV coordinates float left = uvRect.X; float right = uvRect.RightX; float top = uvRect.Y; float bottom = uvRect.BottomY; float nextLeft = uvRectNext.X; float nextRight = uvRectNext.RightX; float nextTop = uvRectNext.Y; float nextBottom = uvRectNext.BottomY; if ((this.flipMode & FlipMode.Horizontal) != FlipMode.None) { MathF.Swap(ref left, ref right); MathF.Swap(ref nextLeft, ref nextRight); } if ((this.flipMode & FlipMode.Vertical) != FlipMode.None) { MathF.Swap(ref top, ref bottom); MathF.Swap(ref nextTop, ref nextBottom); } // Directly pass World Position with each vertex, see note in Light.cs vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = left; vertices[0].TexCoord.Y = top; vertices[0].TexCoord.Z = nextLeft; vertices[0].TexCoord.W = nextTop; vertices[0].Color = mainClr; vertices[0].Attrib = perPixel ? objRotMat : vertexLight[0]; vertices[0].Attrib2 = curAnimFrameFade; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = left; vertices[1].TexCoord.Y = bottom; vertices[1].TexCoord.Z = nextLeft; vertices[1].TexCoord.W = nextBottom; vertices[1].Color = mainClr; vertices[1].Attrib = perPixel ? objRotMat : vertexLight[1]; vertices[1].Attrib2 = curAnimFrameFade; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = right; vertices[2].TexCoord.Y = bottom; vertices[2].TexCoord.Z = nextRight; vertices[2].TexCoord.W = nextBottom; vertices[2].Color = mainClr; vertices[2].Attrib = perPixel ? objRotMat : vertexLight[2]; vertices[2].Attrib2 = curAnimFrameFade; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = right; vertices[3].TexCoord.Y = top; vertices[3].TexCoord.Z = nextRight; vertices[3].TexCoord.W = nextTop; vertices[3].Color = mainClr; vertices[3].Attrib = perPixel ? objRotMat : vertexLight[3]; vertices[3].Attrib2 = curAnimFrameFade; if (this.pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
public override void Draw(IDrawDevice device) { if (this.particles == null) { return; } Texture tex = this.RetrieveTexture(); if (tex == null) { return; } Vector2 particleHalfSize = this.particleSize * 0.5f; float objAngle; float objScale; Vector3 objPos; if (this.worldSpace) { objAngle = 0.0f; objScale = 1.0f; objPos = Vector3.Zero; } else { objAngle = this.GameObj.Transform.Angle; objScale = this.GameObj.Transform.Scale; objPos = this.GameObj.Transform.Pos; } Vector2 objXDot, objYDot; MathF.GetTransformDotVec(objAngle, objScale, out objXDot, out objYDot); if (this.vertexBuffer == null) { this.vertexBuffer = new RawList <VertexC1P3T2>(this.particles.Count * 4); } this.vertexBuffer.Count = this.vertexBuffer.Count = this.particles.Count * 4; VertexC1P3T2[] vertexData = this.vertexBuffer.Data; Particle[] particleData = this.particles.Data; int particleCount = this.particles.Count; for (int i = 0; i < particleCount; i++) { ColorRgba color = particleData[i].Color; float alpha = (float)color.A / 255.0f; if (this.fadeOutAt < 1.0f) { alpha *= MathF.Clamp((1.0f - particleData[i].AgeFactor) / this.fadeOutAt, 0.0f, 1.0f); } if (this.fadeInAt > 0.0f) { alpha *= MathF.Clamp(particleData[i].AgeFactor / this.fadeInAt, 0.0f, 1.0f); } color.A = (byte)(alpha * 255.0f); Rect uvRect; tex.LookupAtlas(particleData[i].SpriteIndex, out uvRect); Vector3 particlePos = particleData[i].Position; MathF.TransformDotVec(ref particlePos, ref objXDot, ref objYDot); particlePos += objPos; float particleAngle = objAngle + particleData[i].Angle; float particleScale = objScale; device.PreprocessCoords(ref particlePos, ref particleScale); Vector2 xDot, yDot; MathF.GetTransformDotVec(particleAngle, particleScale, out xDot, out yDot); Vector2 edgeTopLeft = new Vector2(-particleHalfSize.X, -particleHalfSize.Y); Vector2 edgeBottomLeft = new Vector2(-particleHalfSize.X, particleHalfSize.Y); Vector2 edgeBottomRight = new Vector2(particleHalfSize.X, particleHalfSize.Y); Vector2 edgeTopRight = new Vector2(particleHalfSize.X, -particleHalfSize.Y); MathF.TransformDotVec(ref edgeTopLeft, ref xDot, ref yDot); MathF.TransformDotVec(ref edgeBottomLeft, ref xDot, ref yDot); MathF.TransformDotVec(ref edgeBottomRight, ref xDot, ref yDot); MathF.TransformDotVec(ref edgeTopRight, ref xDot, ref yDot); int vertexBaseIndex = i * 4; vertexData[vertexBaseIndex + 0].Pos.X = particlePos.X + edgeTopLeft.X; vertexData[vertexBaseIndex + 0].Pos.Y = particlePos.Y + edgeTopLeft.Y; vertexData[vertexBaseIndex + 0].Pos.Z = particlePos.Z; vertexData[vertexBaseIndex + 0].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 0].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 0].Color = color; vertexData[vertexBaseIndex + 1].Pos.X = particlePos.X + edgeBottomLeft.X; vertexData[vertexBaseIndex + 1].Pos.Y = particlePos.Y + edgeBottomLeft.Y; vertexData[vertexBaseIndex + 1].Pos.Z = particlePos.Z; vertexData[vertexBaseIndex + 1].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 1].TexCoord.Y = uvRect.BottomY; vertexData[vertexBaseIndex + 1].Color = color; vertexData[vertexBaseIndex + 2].Pos.X = particlePos.X + edgeBottomRight.X; vertexData[vertexBaseIndex + 2].Pos.Y = particlePos.Y + edgeBottomRight.Y; vertexData[vertexBaseIndex + 2].Pos.Z = particlePos.Z; vertexData[vertexBaseIndex + 2].TexCoord.X = uvRect.RightX; vertexData[vertexBaseIndex + 2].TexCoord.Y = uvRect.BottomY; vertexData[vertexBaseIndex + 2].Color = color; vertexData[vertexBaseIndex + 3].Pos.X = particlePos.X + edgeTopRight.X; vertexData[vertexBaseIndex + 3].Pos.Y = particlePos.Y + edgeTopRight.Y; vertexData[vertexBaseIndex + 3].Pos.Z = particlePos.Z; vertexData[vertexBaseIndex + 3].TexCoord.X = uvRect.RightX; vertexData[vertexBaseIndex + 3].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 3].Color = color; } device.AddVertices(this.material, VertexMode.Quads, vertexData, this.vertexBuffer.Count); }
public Element NextElement(bool stopAtLineBreak = false) { if (this.elemIndex >= this.parent.elements.Length) return null; Element elem = this.parent.elements[this.elemIndex]; if (elem is TextElement && this.font != null) { TextElement textElem = elem as TextElement; string textToDisplay; string fittingText; // Word wrap by glyph / word if (this.parent.maxWidth > 0 && this.parent.wrapMode != WrapMode.Element) { FitTextMode fitMode = FitTextMode.ByChar; if (this.parent.wrapMode == WrapMode.Word) fitMode = (this.lineAlign == Alignment.Right) ? FitTextMode.ByWordLeadingSpace : FitTextMode.ByWordTrailingSpace; textToDisplay = textElem.Text.Substring(this.curElemWrapIndex, textElem.Text.Length - this.curElemWrapIndex); fittingText = this.font.FitText(textToDisplay, this.lineAvailWidth - (this.offset.X - this.lineBeginX), fitMode); // If by-word results in instant line break: Do it by glyph instead if (this.offset.X == this.lineBeginX && fittingText.Length == 0 && this.parent.wrapMode == WrapMode.Word) fittingText = this.font.FitText(textToDisplay, this.lineAvailWidth - (this.offset.X - this.lineBeginX), FitTextMode.ByChar); // If doing it by glyph results in an instant line break: Use at least one glyph anyway if (this.lineAvailWidth == this.parent.maxWidth && this.offset.X == this.lineBeginX && this.parent.maxHeight == 0 && fittingText.Length == 0) fittingText = textToDisplay.Substring(0, 1); } // No word wrap (or by whole element) else { textToDisplay = textElem.Text; fittingText = textElem.Text; } Vector2 textElemSize = this.font.MeasureText(fittingText); // Perform word wrap by whole Element if (this.parent.maxWidth > 0 && this.parent.wrapMode == WrapMode.Element) { if ((this.lineAvailWidth < this.parent.maxWidth || this.offset.X > this.lineBeginX || this.parent.maxHeight > 0) && this.offset.X + textElemSize.X > this.lineAvailWidth) { if (stopAtLineBreak) return null; else this.PerformNewLine(); if (this.offset.Y + this.lineHeight > this.parent.maxHeight) return null; } } this.curElemText = fittingText; this.curElemVertTextIndex = this.vertTextIndex[this.fontIndex]; this.curElemOffset = this.offset; // If it all fits: Stop wrap mode, proceed with next element if (fittingText.Length == textToDisplay.Length) { this.curElemWrapIndex = 0; this.elemIndex++; } // If only some part fits: Move wrap index & return else if (fittingText.Length > 0) { this.curElemWrapIndex += fittingText.Length; } // If nothing fits: Begin a new line & return else { if (stopAtLineBreak) return null; else this.PerformNewLine(); if (this.parent.maxHeight != 0 && this.offset.Y + this.lineHeight > this.parent.maxHeight) return null; } this.vertTextIndex[this.fontIndex] += fittingText.Length * 4; this.offset.X += textElemSize.X; this.lineWidth += textElemSize.X; this.lineHeight = Math.Max(this.lineHeight, this.font.LineSpacing); this.lineBaseLine = Math.Max(this.lineBaseLine, this.font.BaseLine); } else if (elem is TextElement && this.font == null) { this.elemIndex++; } else if (elem is IconElement) { IconElement iconElem = elem as IconElement; bool iconValid = this.parent.icons != null && iconElem.IconIndex >= 0 && iconElem.IconIndex < this.parent.icons.Length; Icon icon = iconValid ? this.parent.icons[iconElem.IconIndex] : new Icon(); // Word Wrap if (this.parent.maxWidth > 0) { while ((this.lineAvailWidth < this.parent.maxWidth || this.offset.X > this.lineBeginX || this.parent.maxHeight > 0) && this.offset.X - this.lineBeginX + icon.size.X > this.lineAvailWidth) { if (stopAtLineBreak) return null; else this.PerformNewLine(); if (this.offset.Y + this.lineHeight > this.parent.maxHeight) return null; } } this.curElemVertIconIndex = this.vertIconIndex; this.curElemOffset = this.offset; this.vertIconIndex += 4; this.offset.X += icon.size.X; this.lineWidth += icon.size.X; this.lineHeight = Math.Max(this.lineHeight, icon.size.Y); this.lineBaseLine = Math.Max(this.lineBaseLine, (int)Math.Round(icon.size.Y)); this.elemIndex++; } else if (elem is FontChangeElement) { FontChangeElement fontChangeElem = elem as FontChangeElement; this.fontIndex = fontChangeElem.FontIndex; bool fontValid = this.parent.fonts != null && this.fontIndex >= 0 && this.fontIndex < this.parent.fonts.Length; ContentRef<Font> font = fontValid ? this.parent.fonts[this.fontIndex] : null; this.font = font.Res; this.elemIndex++; } else if (elem is ColorChangeElement) { ColorChangeElement colorChangeElem = elem as ColorChangeElement; this.color = colorChangeElem.Color; this.elemIndex++; } else if (elem is AlignChangeElement) { AlignChangeElement alignChangeElem = elem as AlignChangeElement; this.lineAlign = alignChangeElem.Align; this.elemIndex++; } else if (elem is NewLineElement) { this.elemIndex++; if (stopAtLineBreak) return null; else this.PerformNewLine(); if (this.parent.maxHeight != 0 && this.offset.Y + this.lineHeight > this.parent.maxHeight) return null; } return elem; }
public override void Draw(IDrawDevice device) { // Determine basic working data Tilemap tilemap = this.ActiveTilemap; Tileset tileset = tilemap != null ? tilemap.Tileset.Res : null; Point2 tileCount = tilemap != null ? tilemap.Size : new Point2(1, 1); Vector2 tileSize = tileset != null ? tileset.TileSize : Tileset.DefaultTileSize; // Early-out, if insufficient if (tilemap == null) { return; } if (tileset == null) { return; } // Determine the total size and origin of the rendered Tilemap Vector2 renderTotalSize = tileCount * tileSize; Vector2 renderOrigin = Vector2.Zero; this.origin.ApplyTo(ref renderOrigin, ref renderTotalSize); MathF.TransformCoord(ref renderOrigin.X, ref renderOrigin.Y, this.GameObj.Transform.Angle, this.GameObj.Transform.Scale); // Determine Tile visibility TilemapCulling.TileInput cullingIn = new TilemapCulling.TileInput { // Remember: All these transform values are in world space TilemapPos = this.GameObj.Transform.Pos + new Vector3(renderOrigin), TilemapScale = this.GameObj.Transform.Scale, TilemapAngle = this.GameObj.Transform.Angle, TileCount = tileCount, TileSize = tileSize }; TilemapCulling.TileOutput cullingOut = TilemapCulling.GetVisibleTileRect(device, cullingIn); int renderedTileCount = cullingOut.VisibleTileCount.X * cullingOut.VisibleTileCount.Y; // Determine rendering parameters Material material = (tileset != null ? tileset.RenderMaterial : null) ?? Material.Checkerboard.Res; ColorRgba mainColor = this.colorTint; // Reserve the required space for vertex data in our locally cached buffer if (this.vertices == null) { this.vertices = new RawList <VertexC1P3T2>(); } this.vertices.Count = renderedTileCount * 4; VertexC1P3T2[] vertexData = this.vertices.Data; // Determine and adjust data for Z offset generation float depthPerTile = -cullingIn.TileSize.Y * cullingIn.TilemapScale * this.tileDepthScale; if (this.tileDepthMode == TileDepthOffsetMode.Flat) { depthPerTile = 0.0f; } float originDepthOffset = Rect.Align(this.origin, 0, 0, 0, tileCount.Y * depthPerTile).Y; if (this.tileDepthMode == TileDepthOffsetMode.World) { originDepthOffset += (this.GameObj.Transform.Pos.Y / (float)tileSize.Y) * depthPerTile; } float renderBaseOffset = this.offset + this.tileDepthOffset * depthPerTile + originDepthOffset; // Prepare vertex generation data Vector2 tileXStep = cullingOut.XAxisWorld * cullingIn.TileSize.X; Vector2 tileYStep = cullingOut.YAxisWorld * cullingIn.TileSize.Y; Vector3 renderPos = cullingOut.RenderOriginWorld; float renderOffset = renderBaseOffset; Point2 tileGridPos = cullingOut.VisibleTileStart; // Prepare vertex data array for batch-submitting IReadOnlyGrid <Tile> tiles = tilemap.Tiles; TileInfo[] tileData = tileset.TileData.Data; int submittedTileCount = 0; int vertexBaseIndex = 0; for (int tileIndex = 0; tileIndex < renderedTileCount; tileIndex++) { Tile tile = tiles[tileGridPos.X, tileGridPos.Y]; if (tile.Index < tileData.Length) { Rect uvRect = tileData[tile.Index].TexCoord0; bool visualEmpty = tileData[tile.Index].IsVisuallyEmpty; int tileBaseOffset = tileData[tile.Index].DepthOffset; float localDepthOffset = (tile.DepthOffset + tileBaseOffset) * depthPerTile; if (!visualEmpty) { vertexData[vertexBaseIndex + 0].Pos.X = renderPos.X; vertexData[vertexBaseIndex + 0].Pos.Y = renderPos.Y; vertexData[vertexBaseIndex + 0].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 0].DepthOffset = renderOffset + localDepthOffset; vertexData[vertexBaseIndex + 0].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 0].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 0].Color = mainColor; vertexData[vertexBaseIndex + 1].Pos.X = renderPos.X + tileYStep.X; vertexData[vertexBaseIndex + 1].Pos.Y = renderPos.Y + tileYStep.Y; vertexData[vertexBaseIndex + 1].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 1].DepthOffset = renderOffset + localDepthOffset + depthPerTile; vertexData[vertexBaseIndex + 1].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 1].TexCoord.Y = uvRect.Y + uvRect.H; vertexData[vertexBaseIndex + 1].Color = mainColor; vertexData[vertexBaseIndex + 2].Pos.X = renderPos.X + tileXStep.X + tileYStep.X; vertexData[vertexBaseIndex + 2].Pos.Y = renderPos.Y + tileXStep.Y + tileYStep.Y; vertexData[vertexBaseIndex + 2].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 2].DepthOffset = renderOffset + localDepthOffset + depthPerTile; vertexData[vertexBaseIndex + 2].TexCoord.X = uvRect.X + uvRect.W; vertexData[vertexBaseIndex + 2].TexCoord.Y = uvRect.Y + uvRect.H; vertexData[vertexBaseIndex + 2].Color = mainColor; vertexData[vertexBaseIndex + 3].Pos.X = renderPos.X + tileXStep.X; vertexData[vertexBaseIndex + 3].Pos.Y = renderPos.Y + tileXStep.Y; vertexData[vertexBaseIndex + 3].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 3].DepthOffset = renderOffset + localDepthOffset; vertexData[vertexBaseIndex + 3].TexCoord.X = uvRect.X + uvRect.W; vertexData[vertexBaseIndex + 3].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 3].Color = mainColor; bool vertical = tileData[tile.Index].IsVertical; if (vertical) { vertexData[vertexBaseIndex + 0].DepthOffset += depthPerTile; vertexData[vertexBaseIndex + 3].DepthOffset += depthPerTile; } submittedTileCount++; vertexBaseIndex += 4; } } tileGridPos.X++; renderPos.X += tileXStep.X; renderPos.Y += tileXStep.Y; if ((tileGridPos.X - cullingOut.VisibleTileStart.X) >= cullingOut.VisibleTileCount.X) { tileGridPos.X = cullingOut.VisibleTileStart.X; tileGridPos.Y++; renderPos = cullingOut.RenderOriginWorld; renderPos.X += tileYStep.X * (tileGridPos.Y - cullingOut.VisibleTileStart.Y); renderPos.Y += tileYStep.Y * (tileGridPos.Y - cullingOut.VisibleTileStart.Y); renderOffset = renderBaseOffset + tileGridPos.Y * depthPerTile; } } // Submit all the vertices as one draw batch device.AddVertices( material, VertexMode.Quads, vertexData, submittedTileCount * 4); Profile.AddToStat(@"Duality\Stats\Render\Tilemaps\NumTiles", renderedTileCount); Profile.AddToStat(@"Duality\Stats\Render\Tilemaps\NumVertices", submittedTileCount * 4); }
protected void PrepareVerticesLightSmooth(ref VertexC1P3T4A4A1[] vertices, IDrawDevice device, float curAnimFrameFade, ColorRgba mainClr, Rect uvRect, Rect uvRectNext, DrawTechnique tech) { bool perPixel = tech is LightingTechnique; Vector3 pos = this.GameObj.Transform.Pos; Vector3 posTemp = pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; float rotation = this.GameObj.Transform.Angle; MathF.GetTransformDotVec(rotation, out xDot, out yDot); Rect rectTemp = this.rect.Transformed(this.GameObj.Transform.Scale, this.GameObj.Transform.Scale); Vector2 edge1 = rectTemp.TopLeft; Vector2 edge2 = rectTemp.BottomLeft; Vector2 edge3 = rectTemp.BottomRight; Vector2 edge4 = rectTemp.TopRight; MathF.TransformDotVec(ref edge1, ref xDot, ref yDot); MathF.TransformDotVec(ref edge2, ref xDot, ref yDot); MathF.TransformDotVec(ref edge3, ref xDot, ref yDot); MathF.TransformDotVec(ref edge4, ref xDot, ref yDot); // Using Per-Vertex Lighting? Calculate vertex light values Vector4[] vertexLight = null; if (!perPixel) { vertexLight = new Vector4[4]; Light.GetLightAtWorldPos(pos + new Vector3(edge1), out vertexLight[0], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge2), out vertexLight[1], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge3), out vertexLight[2], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge4), out vertexLight[3], this.vertexTranslucency); } Vector2.Multiply(ref edge1, scaleTemp, out edge1); Vector2.Multiply(ref edge2, scaleTemp, out edge2); Vector2.Multiply(ref edge3, scaleTemp, out edge3); Vector2.Multiply(ref edge4, scaleTemp, out edge4); // Using Per-Pixel Lighting? Pass objRotation Matrix via vertex attribute. Vector4 objRotMat = Vector4.Zero; if (perPixel) objRotMat = new Vector4((float)Math.Cos(-rotation), -(float)Math.Sin(-rotation), (float)Math.Sin(-rotation), (float)Math.Cos(-rotation)); if (vertices == null || vertices.Length != 4) vertices = new VertexC1P3T4A4A1[4]; // Calculate UV coordinates float left = uvRect.X; float right = uvRect.RightX; float top = uvRect.Y; float bottom = uvRect.BottomY; float nextLeft = uvRectNext.X; float nextRight = uvRectNext.RightX; float nextTop = uvRectNext.Y; float nextBottom = uvRectNext.BottomY; if ((this.flipMode & FlipMode.Horizontal) != FlipMode.None) { MathF.Swap(ref left, ref right); MathF.Swap(ref nextLeft, ref nextRight); } if ((this.flipMode & FlipMode.Vertical) != FlipMode.None) { MathF.Swap(ref top, ref bottom); MathF.Swap(ref nextTop, ref nextBottom); } // Directly pass World Position with each vertex, see note in Light.cs vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = left; vertices[0].TexCoord.Y = top; vertices[0].TexCoord.Z = nextLeft; vertices[0].TexCoord.W = nextTop; vertices[0].Color = mainClr; vertices[0].Attrib = perPixel ? objRotMat : vertexLight[0]; vertices[0].Attrib2 = curAnimFrameFade; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = left; vertices[1].TexCoord.Y = bottom; vertices[1].TexCoord.Z = nextLeft; vertices[1].TexCoord.W = nextBottom; vertices[1].Color = mainClr; vertices[1].Attrib = perPixel ? objRotMat : vertexLight[1]; vertices[1].Attrib2 = curAnimFrameFade; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = right; vertices[2].TexCoord.Y = bottom; vertices[2].TexCoord.Z = nextRight; vertices[2].TexCoord.W = nextBottom; vertices[2].Color = mainClr; vertices[2].Attrib = perPixel ? objRotMat : vertexLight[2]; vertices[2].Attrib2 = curAnimFrameFade; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = right; vertices[3].TexCoord.Y = top; vertices[3].TexCoord.Z = nextRight; vertices[3].TexCoord.W = nextTop; vertices[3].Color = mainClr; vertices[3].Attrib = perPixel ? objRotMat : vertexLight[3]; vertices[3].Attrib2 = curAnimFrameFade; if (this.pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
public void MergeTiles(string path, int offset, int count) { ContentRef <Material> material; PixelData mask; ContentResolver.Current.RequestTileset(path, out material, out mask); Materials.Add(material); PixelData texture = material.Res.MainTexture.Res.BasePixmap.Res.MainLayer; int width = (texture.Width / TileSize); int height = (texture.Height / TileSize); isMaskEmpty.Length += count; isMaskFilled.Length += count; isTileFilled.Length += count; int partStart = defaultLayerTiles.Count; for (int i = 0; i < count; i++) { int ty = (offset + i) / width; int tx = (offset + i) % width; BitArray tileMask = new BitArray(TileSize * TileSize); bool maskEmpty = true; bool maskFilled = true; bool tileFilled = true; for (int x = 0; x < TileSize; x++) { for (int y = 0; y < TileSize; y++) { ColorRgba px = mask[tx * TileSize + x, ty *TileSize + y]; // Consider any fully white or fully transparent pixel in the masks as non-solid and all others as solid bool masked = (px != ColorRgba.White && px.A > 0); tileMask[x + TileSize * y] = masked; maskEmpty &= !masked; maskFilled &= masked; ColorRgba pxTex = texture[tx * TileSize + x, ty *TileSize + y]; masked = (pxTex.A > 20); tileFilled &= masked; } } masks.Add(tileMask); int idx = (partStart + i); isMaskEmpty[idx] = maskEmpty; isMaskFilled[idx] = maskFilled; isTileFilled[idx] = tileFilled || !maskEmpty; defaultLayerTiles.Add(new LayerTile { TileID = idx, Material = material, MaterialOffset = new Point2(tx * TileSize, ty * TileSize), MaterialAlpha = 255 }); } IsValid = true; }
public TileSet(string path) { Materials = new RawList <ContentRef <Material> >(); ContentRef <Material> material; PixelData mask; ContentResolver.Current.RequestTileset(path, out material, out mask); Materials.Add(material); TileSize = DefaultTileSize; PixelData texture = material.Res.MainTexture.Res.BasePixmap.Res.MainLayer; int width = (texture.Width / TileSize); int height = (texture.Height / TileSize); TilesPerRow = width; int tileCount = width * height; masks = new RawList <BitArray>(); isMaskEmpty = new BitArray(tileCount); isMaskFilled = new BitArray(tileCount); isTileFilled = new BitArray(tileCount); defaultLayerTiles = new RawList <LayerTile>(); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { BitArray tileMask = new BitArray(TileSize * TileSize); bool maskEmpty = true; bool maskFilled = true; bool tileFilled = true; for (int x = 0; x < TileSize; x++) { for (int y = 0; y < TileSize; y++) { ColorRgba px = mask[j * TileSize + x, i *TileSize + y]; // Consider any fully white or fully transparent pixel in the masks as non-solid and all others as solid bool masked = (px != ColorRgba.White && px.A > 0); tileMask[x + TileSize * y] = masked; maskEmpty &= !masked; maskFilled &= masked; ColorRgba pxTex = texture[j * TileSize + x, i *TileSize + y]; masked = (pxTex.A > 20); tileFilled &= masked; } } masks.Add(tileMask); int idx = (j + width * i); isMaskEmpty[idx] = maskEmpty; isMaskFilled[idx] = maskFilled; isTileFilled[idx] = tileFilled || !maskEmpty; defaultLayerTiles.Add(new LayerTile { TileID = idx, Material = material, MaterialOffset = new Point2(TileSize * ((i * width + j) % TilesPerRow), TileSize * ((i * width + j) / TilesPerRow)), MaterialAlpha = 255 }); } } IsValid = true; }
protected void PrepareVerticesLight(ref VertexC1P3T2A4[] vertices, IDrawDevice device, ColorRgba mainClr, Rect uvRect, DrawTechnique tech) { bool perPixel = tech is LightingTechnique; Vector3 pos = this.GameObj.Transform.Pos; Vector3 posTemp = pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; float rotation = this.GameObj.Transform.Angle; MathF.GetTransformDotVec(rotation, out xDot, out yDot); Rect rectTemp = this.rect.Transform(this.GameObj.Transform.Scale, this.GameObj.Transform.Scale); Vector2 edge1 = rectTemp.TopLeft; Vector2 edge2 = rectTemp.BottomLeft; Vector2 edge3 = rectTemp.BottomRight; Vector2 edge4 = rectTemp.TopRight; MathF.TransformDotVec(ref edge1, ref xDot, ref yDot); MathF.TransformDotVec(ref edge2, ref xDot, ref yDot); MathF.TransformDotVec(ref edge3, ref xDot, ref yDot); MathF.TransformDotVec(ref edge4, ref xDot, ref yDot); // Using Per-Vertex Lighting? Calculate vertex light values Vector4[] vertexLight = null; if (!perPixel) { vertexLight = new Vector4[4]; Light.GetLightAtWorldPos(pos + new Vector3(edge1), out vertexLight[0], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge2), out vertexLight[1], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge3), out vertexLight[2], this.vertexTranslucency); Light.GetLightAtWorldPos(pos + new Vector3(edge4), out vertexLight[3], this.vertexTranslucency); } Vector2.Multiply(ref edge1, scaleTemp, out edge1); Vector2.Multiply(ref edge2, scaleTemp, out edge2); Vector2.Multiply(ref edge3, scaleTemp, out edge3); Vector2.Multiply(ref edge4, scaleTemp, out edge4); // Using Per-Pixel Lighting? Pass objRotation Matrix via vertex attribute. Vector4 objRotMat = Vector4.Zero; if (perPixel) objRotMat = new Vector4((float)Math.Cos(-rotation), -(float)Math.Sin(-rotation), (float)Math.Sin(-rotation), (float)Math.Cos(-rotation)); if (vertices == null || vertices.Length != 4) vertices = new VertexC1P3T2A4[4]; vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = uvRect.X; vertices[0].TexCoord.Y = uvRect.Y; vertices[0].Color = mainClr; vertices[0].Attrib = perPixel ? objRotMat : vertexLight[0]; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = uvRect.X; vertices[1].TexCoord.Y = uvRect.MaximumY; vertices[1].Color = mainClr; vertices[1].Attrib = perPixel ? objRotMat : vertexLight[1]; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = uvRect.MaximumX; vertices[2].TexCoord.Y = uvRect.MaximumY; vertices[2].Color = mainClr; vertices[2].Attrib = perPixel ? objRotMat : vertexLight[2]; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = uvRect.MaximumX; vertices[3].TexCoord.Y = uvRect.Y; vertices[3].Color = mainClr; vertices[3].Attrib = perPixel ? objRotMat : vertexLight[3]; }
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Color brightChecker = Color.FromArgb(224, 224, 224); Color darkChecker = Color.FromArgb(192, 192, 192); e.Graphics.FillRectangle(new HatchBrush(HatchStyle.LargeCheckerBoard, brightChecker, darkChecker), this.rectPanel); if (this.value != null) { Color val = Color.FromArgb(this.value.ToIntArgb()); Color valSolid = Color.FromArgb(255, val); e.Graphics.FillRectangle( new SolidBrush(val), this.rectPanel.X, this.rectPanel.Y, this.rectPanel.Width / 2, this.rectPanel.Height); e.Graphics.FillRectangle( new SolidBrush(valSolid), this.rectPanel.X + this.rectPanel.Width / 2, this.rectPanel.Y, this.rectPanel.Width / 2, this.rectPanel.Height); ColorRgba rgba = this.value.ConvertTo <ColorRgba>(); Color textColor = rgba.GetLuminance() > 0.5f ? Color.Black : Color.White; StringFormat format = StringFormat.GenericDefault; format.Alignment = StringAlignment.Center; format.LineAlignment = StringAlignment.Center; format.Trimming = StringTrimming.EllipsisCharacter; e.Graphics.DrawString( string.Format("{0}, {1}, {2}, {3}", rgba.R, rgba.G, rgba.B, rgba.A), this.ControlRenderer.FontRegular, new SolidBrush(Color.FromArgb(128, textColor)), this.rectPanel, format); } e.Graphics.DrawRectangle(SystemPens.ControlLightLight, this.rectPanel.X + 1, this.rectPanel.Y + 1, this.rectPanel.Width - 2, this.rectPanel.Height - 2); e.Graphics.DrawRectangle(SystemPens.ControlDark, this.rectPanel); ButtonState buttonCDiagState = ButtonState.Disabled; if (!this.ReadOnly && this.Enabled) { if (this.buttonCDiagPressed) { buttonCDiagState = ButtonState.Pressed; } else if (this.buttonCDiagHovered) { buttonCDiagState = ButtonState.Hot; } else { buttonCDiagState = ButtonState.Normal; } } ControlRenderer.DrawButton( e.Graphics, this.rectCDiagButton, buttonCDiagState, null, Properties.GeneralResCache.ColorWheel); ButtonState buttonCPickState = ButtonState.Disabled; if (!this.ReadOnly && this.Enabled) { if (this.buttonCPickPressed) { buttonCPickState = ButtonState.Pressed; } else if (this.buttonCPickHovered) { buttonCPickState = ButtonState.Hot; } else { buttonCPickState = ButtonState.Normal; } } ControlRenderer.DrawButton( e.Graphics, this.rectCPickButton, buttonCPickState, null, Properties.GeneralResCache.ColorPick); }
/// <summary> /// Sets the layers pixel data in the ColorRgba format. Note that the specified data will be copied and thus modifying it /// outside won't affect the Layer it has been inserted into. /// </summary> /// <param name="pixelData"></param> /// <param name="width"></param> /// <param name="height"></param> public void SetPixelDataRgba(ColorRgba[] pixelData, int width = -1, int height = -1) { if (width < 0) width = this.width; if (height < 0) height = this.height; if (pixelData.Length != width * height) throw new ArgumentException("Data length doesn't match width * height", "pixelData"); this.width = width; this.height = height; this.data = pixelData.Clone() as ColorRgba[]; }
public override void OnWorldOverlayDrawcalls(Canvas canvas) { RigidBody body = this.Environment.ActiveBody; if (body == null) { return; } DesignTimeObjectData designTimeData = DesignTimeObjectData.Get(body.GameObj); if (designTimeData.IsHidden) { return; } float knobSize = 7.0f; float worldKnobSize = knobSize / MathF.Max(0.0001f, canvas.DrawDevice.GetScaleAtZ(0.0f)); // Determine the color in which we'll draw the interaction markers ColorRgba markerColor = this.Environment.FgColor; canvas.State.ZOffset = -1.0f; // Prepare the transform matrix for this object, so // we can move the RigidBody vertices into world space quickly Transform transform = body.GameObj.Transform; Vector2 bodyPos = transform.Pos.Xy; Vector2 bodyDotX; Vector2 bodyDotY; MathF.GetTransformDotVec(transform.Angle, transform.Scale, out bodyDotX, out bodyDotY); // Draw an interaction indicator for every vertex of the active bodies shapes Vector3 mousePosWorld = this.Environment.ActiveWorldPos; foreach (ShapeInfo shape in body.Shapes) { if (shape is CircleShapeInfo) { CircleShapeInfo circle = shape as CircleShapeInfo; Vector2 circleWorldPos = circle.Position; MathF.TransformDotVec(ref circleWorldPos, ref bodyDotX, ref bodyDotY); circleWorldPos = bodyPos + circleWorldPos; // Draw the circles center as a vertex if (this.activeVertex == 0 && this.activeShape == shape) { canvas.State.ColorTint = markerColor; } else { canvas.State.ColorTint = markerColor.WithAlpha(0.75f); } canvas.FillRect( circleWorldPos.X - worldKnobSize * 0.5f, circleWorldPos.Y - worldKnobSize * 0.5f, worldKnobSize, worldKnobSize); } else { Vector2[] vertices = this.GetVertices(shape); if (vertices == null) { continue; } Vector2[] worldVertices = new Vector2[vertices.Length]; // Transform the shapes vertices into world space for (int index = 0; index < vertices.Length; index++) { Vector2 vertex = vertices[index]; MathF.TransformDotVec(ref vertex, ref bodyDotX, ref bodyDotY); worldVertices[index] = bodyPos + vertex; } // Draw the vertices for (int i = 0; i < worldVertices.Length; i++) { if (this.activeVertex == i && this.activeShape == shape) { canvas.State.ColorTint = markerColor; } else { canvas.State.ColorTint = markerColor.WithAlpha(0.75f); } canvas.FillRect( worldVertices[i].X - worldKnobSize * 0.5f, worldVertices[i].Y - worldKnobSize * 0.5f, worldKnobSize, worldKnobSize); } } } // Interaction indicator for an existing vertex if (this.activeVertex != -1) { canvas.State.ColorTint = markerColor; canvas.DrawRect( this.activeEdgeWorldPos.X - worldKnobSize, this.activeEdgeWorldPos.Y - worldKnobSize, worldKnobSize * 2.0f, worldKnobSize * 2.0f); } // Interaction indicator for a vertex-to-be-created else if (this.activeEdge != -1) { canvas.State.ColorTint = markerColor.WithAlpha(0.35f); canvas.FillRect( this.activeEdgeWorldPos.X - worldKnobSize * 0.5f, this.activeEdgeWorldPos.Y - worldKnobSize * 0.5f, worldKnobSize * 1.0f, worldKnobSize * 1.0f); canvas.State.ColorTint = markerColor; canvas.DrawRect( this.activeEdgeWorldPos.X - worldKnobSize, this.activeEdgeWorldPos.Y - worldKnobSize, worldKnobSize * 2.0f, worldKnobSize * 2.0f); } }
private ColorRgba[] InternalRescale(int w, int h, FilterMethod filter) { if (this.width == w && this.height == h) return null; ColorRgba[] tempDestData = new ColorRgba[w * h]; if (filter == FilterMethod.Nearest) { // Don't use Parallel.For here, the overhead is too big and the compiler // does a great job optimizing this piece of code without, so don't get in the way. for (int i = 0; i < tempDestData.Length; i++) { int y = i / w; int x = i - (y * w); int xTmp = (x * this.width) / w; int yTmp = (y * this.height) / h; int nTmp = xTmp + (yTmp * this.width); tempDestData[i] = this.data[nTmp]; } } else if (filter == FilterMethod.Linear) { //for (int i = 0; i < tempDestData.Length; i++) System.Threading.Tasks.Parallel.For(0, tempDestData.Length, i => { int y = i / w; int x = i - (y * w); float xRatio = ((float)(x * this.width) / (float)w) + 0.5f; float yRatio = ((float)(y * this.height) / (float)h) + 0.5f; int xTmp = (int)xRatio; int yTmp = (int)yRatio; xRatio -= xTmp; yRatio -= yTmp; int xTmp2 = xTmp + 1; int yTmp2 = yTmp + 1; xTmp = xTmp < this.width ? xTmp : this.width - 1; yTmp = (yTmp < this.height ? yTmp : this.height - 1) * this.width; xTmp2 = xTmp2 < this.width ? xTmp2 : this.width - 1; yTmp2 = (yTmp2 < this.height ? yTmp2 : this.height - 1) * this.width; int nTmp0 = xTmp + yTmp; int nTmp1 = xTmp2 + yTmp; int nTmp2 = xTmp + yTmp2; int nTmp3 = xTmp2 + yTmp2; tempDestData[i].R = (byte) ( ((float)this.data[nTmp0].R * (1.0f - xRatio) * (1.0f - yRatio)) + ((float)this.data[nTmp1].R * xRatio * (1.0f - yRatio)) + ((float)this.data[nTmp2].R * yRatio * (1.0f - xRatio)) + ((float)this.data[nTmp3].R * xRatio * yRatio) ); tempDestData[i].G = (byte) ( ((float)this.data[nTmp0].G * (1.0f - xRatio) * (1.0f - yRatio)) + ((float)this.data[nTmp1].G * xRatio * (1.0f - yRatio)) + ((float)this.data[nTmp2].G * yRatio * (1.0f - xRatio)) + ((float)this.data[nTmp3].G * xRatio * yRatio) ); tempDestData[i].B = (byte) ( ((float)this.data[nTmp0].B * (1.0f - xRatio) * (1.0f - yRatio)) + ((float)this.data[nTmp1].B * xRatio * (1.0f - yRatio)) + ((float)this.data[nTmp2].B * yRatio * (1.0f - xRatio)) + ((float)this.data[nTmp3].B * xRatio * yRatio) ); tempDestData[i].A = (byte) ( ((float)this.data[nTmp0].A * (1.0f - xRatio) * (1.0f - yRatio)) + ((float)this.data[nTmp1].A * xRatio * (1.0f - yRatio)) + ((float)this.data[nTmp2].A * yRatio * (1.0f - xRatio)) + ((float)this.data[nTmp3].A * xRatio * yRatio) ); }); } return tempDestData; }
protected void PrepareVertices(ref VertexC1P3T2[] vertices, IDrawDevice device, ColorRgba mainClr, Rect uvRect) { Vector3 posTemp = this.gameobj.Transform.Pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; MathF.GetTransformDotVec(this.GameObj.Transform.Angle, scaleTemp, out xDot, out yDot); Rect rectTemp = this.rect.Transform(this.gameobj.Transform.Scale, this.gameobj.Transform.Scale); Vector2 edge1 = rectTemp.TopLeft; Vector2 edge2 = rectTemp.BottomLeft; Vector2 edge3 = rectTemp.BottomRight; Vector2 edge4 = rectTemp.TopRight; MathF.TransformDotVec(ref edge1, ref xDot, ref yDot); MathF.TransformDotVec(ref edge2, ref xDot, ref yDot); MathF.TransformDotVec(ref edge3, ref xDot, ref yDot); MathF.TransformDotVec(ref edge4, ref xDot, ref yDot); if (vertices == null || vertices.Length != 4) vertices = new VertexC1P3T2[4]; vertices[0].SetVertex(posTemp.X + edge1.X, posTemp.Y + edge1.Y, posTemp.Z + this.VertexZOffset, uvRect.X, uvRect.Y, mainClr); vertices[1].SetVertex(posTemp.X + edge2.X, posTemp.Y + edge2.Y, posTemp.Z + this.VertexZOffset, uvRect.X, uvRect.MaximumY, mainClr); vertices[2].SetVertex(posTemp.X + edge3.X, posTemp.Y + edge3.Y, posTemp.Z + this.VertexZOffset, uvRect.MaximumX, uvRect.MaximumY, mainClr); vertices[3].SetVertex(posTemp.X + edge4.X, posTemp.Y + edge4.Y, posTemp.Z + this.VertexZOffset, uvRect.MaximumX, uvRect.Y, mainClr); if (this.pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
/// <summary> /// Sets the color of all transparent pixels to the specified color. /// </summary> /// <param name="transparentColor"></param> public void ColorTransparentPixels(ColorRgba transparentColor) { for (int i = 0; i < this.data.Length; i++) { if (this.data[i].A != 0) continue; this.data[i] = transparentColor; } }
/// <summary> /// Creates a new single-texture Material. /// </summary> /// <param name="technique">The <see cref="Duality.Resources.DrawTechnique"/> to use.</param> /// <param name="mainColor">The <see cref="MainColor"/> to use.</param> /// <param name="mainTex">The main <see cref="Duality.Resources.Texture"/> to use.</param> public Material(ContentRef <DrawTechnique> technique, ColorRgba mainColor, ContentRef <Texture> mainTex) { this.info = new BatchInfo(technique, mainColor, mainTex); }
protected void PrepareVertices(ref VertexC1P3T2[] vertices, IDrawDevice device, ColorRgba mainClr, Rect uvRect) { Vector3 posTemp = this.gameobj.Transform.Pos; float scaleTemp = 1.0f; device.PreprocessCoords(ref posTemp, ref scaleTemp); Vector2 xDot, yDot; MathF.GetTransformDotVec(this.GameObj.Transform.Angle, scaleTemp, out xDot, out yDot); Rect rectTemp = this.rect.Transformed(this.gameobj.Transform.Scale, this.gameobj.Transform.Scale); Vector2 edge1 = rectTemp.TopLeft; Vector2 edge2 = rectTemp.BottomLeft; Vector2 edge3 = rectTemp.BottomRight; Vector2 edge4 = rectTemp.TopRight; MathF.TransformDotVec(ref edge1, ref xDot, ref yDot); MathF.TransformDotVec(ref edge2, ref xDot, ref yDot); MathF.TransformDotVec(ref edge3, ref xDot, ref yDot); MathF.TransformDotVec(ref edge4, ref xDot, ref yDot); float left = uvRect.X; float right = uvRect.RightX; float top = uvRect.Y; float bottom = uvRect.BottomY; if ((this.flipMode & FlipMode.Horizontal) != FlipMode.None) MathF.Swap(ref left, ref right); if ((this.flipMode & FlipMode.Vertical) != FlipMode.None) MathF.Swap(ref top, ref bottom); if (vertices == null || vertices.Length != 4) vertices = new VertexC1P3T2[4]; vertices[0].Pos.X = posTemp.X + edge1.X; vertices[0].Pos.Y = posTemp.Y + edge1.Y; vertices[0].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[0].TexCoord.X = left; vertices[0].TexCoord.Y = top; vertices[0].Color = mainClr; vertices[1].Pos.X = posTemp.X + edge2.X; vertices[1].Pos.Y = posTemp.Y + edge2.Y; vertices[1].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[1].TexCoord.X = left; vertices[1].TexCoord.Y = bottom; vertices[1].Color = mainClr; vertices[2].Pos.X = posTemp.X + edge3.X; vertices[2].Pos.Y = posTemp.Y + edge3.Y; vertices[2].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[2].TexCoord.X = right; vertices[2].TexCoord.Y = bottom; vertices[2].Color = mainClr; vertices[3].Pos.X = posTemp.X + edge4.X; vertices[3].Pos.Y = posTemp.Y + edge4.Y; vertices[3].Pos.Z = posTemp.Z + this.VertexZOffset; vertices[3].TexCoord.X = right; vertices[3].TexCoord.Y = top; vertices[3].Color = mainClr; if (this.pixelGrid) { vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X); vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X); vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X); vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { vertices[0].Pos.X += 0.5f; vertices[1].Pos.X += 0.5f; vertices[2].Pos.X += 0.5f; vertices[3].Pos.X += 0.5f; } vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y); vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y); vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y); vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y); if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { vertices[0].Pos.Y += 0.5f; vertices[1].Pos.Y += 0.5f; vertices[2].Pos.Y += 0.5f; vertices[3].Pos.Y += 0.5f; } } }
private void DrawLocalAngleConstraint(Canvas canvas, RigidBody body, Vector2 anchor, float minAngle, float maxAngle, float currentAngle, float radius) { Vector3 bodyPos = body.GameObj.Transform.Pos; ColorRgba clr = this.JointColor; ColorRgba clrErr = this.JointErrorColor; Vector2 anchorToWorld = body.GameObj.Transform.GetWorldVector(anchor); Vector2 angleVecMin = Vector2.FromAngleLength(minAngle, radius); Vector2 angleVecMax = Vector2.FromAngleLength(maxAngle, radius); Vector2 errorVec = Vector2.FromAngleLength(currentAngle, radius); float angleDistMin = MathF.Abs(currentAngle - minAngle); float angleDistMax = MathF.Abs(currentAngle - maxAngle); float angleRange = maxAngle - minAngle; bool hasError = angleDistMin > angleDistMax ? angleDistMin >= angleRange : angleDistMax >= angleRange; if (hasError) { float circleBegin = currentAngle; float circleEnd = angleDistMin < angleDistMax ? minAngle : maxAngle; if (MathF.TurnDir(circleBegin, circleEnd) < 0) { MathF.Swap(ref circleBegin, ref circleEnd); circleEnd = circleBegin + MathF.CircularDist(circleBegin, circleEnd); } canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clrErr)); canvas.DrawLine( bodyPos.X + anchorToWorld.X, bodyPos.Y + anchorToWorld.Y, bodyPos.Z, bodyPos.X + anchorToWorld.X + errorVec.X, bodyPos.Y + anchorToWorld.Y + errorVec.Y, bodyPos.Z); canvas.DrawCircleSegment( bodyPos.X + anchorToWorld.X, bodyPos.Y + anchorToWorld.Y, bodyPos.Z, radius, circleBegin, circleEnd); this.DrawLocalText(canvas, body, string.Format("{0:F0}°", MathF.RadToDeg(currentAngle)), anchorToWorld + errorVec, Vector2.UnitY, errorVec.Angle); } canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr)); canvas.DrawCircleSegment( bodyPos.X + anchorToWorld.X, bodyPos.Y + anchorToWorld.Y, bodyPos.Z, radius, minAngle, maxAngle); canvas.DrawLine( bodyPos.X + anchorToWorld.X, bodyPos.Y + anchorToWorld.Y, bodyPos.Z, bodyPos.X + anchorToWorld.X + angleVecMin.X, bodyPos.Y + anchorToWorld.Y + angleVecMin.Y, bodyPos.Z); canvas.DrawLine( bodyPos.X + anchorToWorld.X, bodyPos.Y + anchorToWorld.Y, bodyPos.Z, bodyPos.X + anchorToWorld.X + angleVecMax.X, bodyPos.Y + anchorToWorld.Y + angleVecMax.Y, bodyPos.Z); this.DrawLocalText(canvas, body, string.Format("{0:F0}°", MathF.RadToDeg(minAngle)), anchorToWorld + angleVecMin, angleVecMin.Angle); this.DrawLocalText(canvas, body, string.Format("{0:F0}°", MathF.RadToDeg(maxAngle)), anchorToWorld + angleVecMax, angleVecMax.Angle); }
protected internal override void OnCollectDrawcalls(Canvas canvas) { base.OnCollectDrawcalls(canvas); IDrawDevice device = canvas.DrawDevice; float scaleTemp = 1.0f; Vector3 posTemp = Vector3.Zero; device.PreprocessCoords(ref posTemp, ref scaleTemp); if (posTemp.Z <= canvas.DrawDevice.NearZ) { return; } float alphaTemp = 0.5f; alphaTemp *= (float)Math.Min(1.0d, ((posTemp.Z - device.NearZ) / (device.NearZ * 5.0f))); if (alphaTemp <= 0.005f) { return; } float stepTemp = 4.0f * this.gridSize * MathF.Max(0.25f, MathF.Pow(2.0f, -MathF.Round(1.0f - MathF.Log(1.0f / scaleTemp, 2.0f)))); float scaledStep = stepTemp * scaleTemp; float viewBoundRad = device.TargetSize.Length * 0.5f; int lineCount = (2 + (int)MathF.Ceiling(viewBoundRad * 2 / scaledStep)) * 4; ColorRgba gridColor = this.FgColor.WithAlpha(alphaTemp); VertexC1P3[] vertices = new VertexC1P3[lineCount * 4]; float beginPos; float pos; int lineIndex; int vertOff = 0; beginPos = posTemp.X % scaledStep - (lineCount / 8) * scaledStep; pos = beginPos; lineIndex = 0; for (int x = 0; x < lineCount; x++) { bool primaryLine = lineIndex % 4 == 0; bool secondaryLine = lineIndex % 4 == 2; vertices[vertOff + x * 2 + 0].Color = primaryLine ? gridColor : gridColor.WithAlpha(alphaTemp * (secondaryLine ? 0.5f : 0.25f)); vertices[vertOff + x * 2 + 0].Pos.X = pos; vertices[vertOff + x * 2 + 0].Pos.Y = -viewBoundRad; vertices[vertOff + x * 2 + 0].Pos.Z = posTemp.Z + 1; vertices[vertOff + x * 2 + 1] = vertices[vertOff + x * 2 + 0]; vertices[vertOff + x * 2 + 1].Pos.Y = viewBoundRad; pos += scaledStep / 4; lineIndex++; } vertOff += lineCount * 2; beginPos = posTemp.Y % scaledStep - (lineCount / 8) * scaledStep; pos = beginPos; lineIndex = 0; for (int y = 0; y < lineCount; y++) { bool primaryLine = lineIndex % 4 == 0; bool secondaryLine = lineIndex % 4 == 2; vertices[vertOff + y * 2 + 0].Color = primaryLine ? gridColor : gridColor.WithAlpha(alphaTemp * (secondaryLine ? 0.5f : 0.25f)); vertices[vertOff + y * 2 + 0].Pos.X = -viewBoundRad; vertices[vertOff + y * 2 + 0].Pos.Y = pos; vertices[vertOff + y * 2 + 0].Pos.Z = posTemp.Z + 1; vertices[vertOff + y * 2 + 1] = vertices[vertOff + y * 2 + 0]; vertices[vertOff + y * 2 + 1].Pos.X = viewBoundRad; pos += scaledStep / 4; lineIndex++; } vertOff += lineCount * 2; device.AddVertices(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White), VertexMode.Lines, vertices); }
/// <summary> /// Replaces a Bitmaps pixel data. /// </summary> /// <param name="bm"></param> /// <param name="pixelData"></param> public static void SetPixelDataRgba(this Bitmap bm, ColorRgba[] pixelData) { int[] argbValues = new int[pixelData.Length]; unchecked { for (int i = 0; i < pixelData.Length; i++) argbValues[i] = pixelData[i].ToIntArgb(); } SetPixelDataIntArgb(bm, argbValues); }
private void DrawWorldAxisConstraint(Canvas canvas, RigidBody body, Vector2 worldAxis, Vector2 localAnchor, Vector2 worldAnchor, float min = 1, float max = -1) { Vector3 bodyPos = body.GameObj.Transform.Pos; worldAxis = worldAxis.Normalized; bool infinite = false; if (min > max) { min = -10000000.0f; max = 10000000.0f; infinite = true; } Vector2 anchorToWorld = body.GameObj.Transform.GetWorldVector(localAnchor); float axisVal = Vector2.Dot(bodyPos.Xy + anchorToWorld - worldAnchor, worldAxis); Vector2 basePos = MathF.PointLineNearestPoint( bodyPos.X + anchorToWorld.X, bodyPos.Y + anchorToWorld.Y, worldAnchor.X + worldAxis.X * min, worldAnchor.Y + worldAxis.Y * min, worldAnchor.X + worldAxis.X * max, worldAnchor.Y + worldAxis.Y * max, infinite); float errorVal = (bodyPos.Xy + anchorToWorld - basePos).Length; Vector2 errorVec = basePos - bodyPos.Xy; bool hasError = errorVal >= 1.0f; ColorRgba clr = this.JointColor; ColorRgba clrErr = this.JointErrorColor; if (hasError) { canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clrErr)); canvas.DrawLine( bodyPos.X + anchorToWorld.X, bodyPos.Y + anchorToWorld.Y, bodyPos.Z, basePos.X, basePos.Y, bodyPos.Z); this.DrawLocalText(canvas, body, string.Format("{0:F1}", errorVal), errorVec * 0.5f, new Vector2(0.5f, 0.0f), errorVec.PerpendicularLeft.Angle); } canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr)); canvas.DrawLine( worldAnchor.X + worldAxis.X * min, worldAnchor.Y + worldAxis.Y * min, bodyPos.Z, worldAnchor.X + worldAxis.X * max, worldAnchor.Y + worldAxis.Y * max, bodyPos.Z); if (!infinite) { canvas.DrawLine( worldAnchor.X + worldAxis.X * min + worldAxis.PerpendicularLeft.X * 5.0f, worldAnchor.Y + worldAxis.Y * min + worldAxis.PerpendicularLeft.Y * 5.0f, bodyPos.Z, worldAnchor.X + worldAxis.X * min + worldAxis.PerpendicularRight.X * 5.0f, worldAnchor.Y + worldAxis.Y * min + worldAxis.PerpendicularRight.Y * 5.0f, bodyPos.Z); canvas.DrawLine( worldAnchor.X + worldAxis.X * max + worldAxis.PerpendicularLeft.X * 5.0f, worldAnchor.Y + worldAxis.Y * max + worldAxis.PerpendicularLeft.Y * 5.0f, bodyPos.Z, worldAnchor.X + worldAxis.X * max + worldAxis.PerpendicularRight.X * 5.0f, worldAnchor.Y + worldAxis.Y * max + worldAxis.PerpendicularRight.Y * 5.0f, bodyPos.Z); } }
/// <summary> /// Extracts a rectangular region of this Layer. If the extracted region is bigger than the original Layer, /// all new space is filled with a background color. /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="w"></param> /// <param name="h"></param> /// <param name="backColor"></param> public void SubImage(int x, int y, int w, int h, ColorRgba backColor) { Layer tempLayer = new Layer(w, h, backColor); this.DrawOnto(tempLayer, BlendMode.Solid, -x, -y); tempLayer.CopyTo(this); }
protected internal override void OnCollectWorldOverlayDrawcalls(Canvas canvas) { base.OnCollectWorldOverlayDrawcalls(canvas); List <RigidBody> visibleColliders = this.QueryVisibleColliders().ToList(); RigidBody selectedBody = this.QuerySelectedCollider(); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White)); canvas.State.TextFont = Font.GenericMonospace10; canvas.State.TextInvariantScale = true; canvas.State.ZOffset = this.depthOffset; Font textFont = canvas.State.TextFont.Res; // Retrieve selected shapes ObjectEditorCamViewState editorState = this.View.ActiveState as ObjectEditorCamViewState; object[] editorSelectedObjects = editorState != null?editorState.SelectedObjects.Select(item => item.ActualObject).ToArray() : new object[0]; bool isAnyBodySelected = (selectedBody != null); bool isAnyShapeSelected = isAnyBodySelected && editorSelectedObjects.OfType <ShapeInfo>().Any(); // Draw Shape layer foreach (RigidBody body in visibleColliders) { if (!body.Shapes.Any()) { continue; } Vector3 objPos = body.GameObj.Transform.Pos; float objAngle = body.GameObj.Transform.Angle; float objScale = body.GameObj.Transform.Scale; bool isBodySelected = (body == selectedBody); float bodyAlpha = isBodySelected ? 1.0f : (isAnyBodySelected ? 0.5f : 1.0f); float maxDensity = body.Shapes.Max(s => s.Density); float minDensity = body.Shapes.Min(s => s.Density); float avgDensity = (maxDensity + minDensity) * 0.5f; int shapeIndex = 0; foreach (ShapeInfo shape in body.Shapes) { CircleShapeInfo circle = shape as CircleShapeInfo; PolyShapeInfo poly = shape as PolyShapeInfo; ChainShapeInfo chain = shape as ChainShapeInfo; LoopShapeInfo loop = shape as LoopShapeInfo; bool isShapeSelected = isBodySelected && editorSelectedObjects.Contains(shape); float shapeAlpha = bodyAlpha * (isShapeSelected ? 1.0f : (isAnyShapeSelected && isBodySelected ? 0.75f : 1.0f)); float densityRelative = MathF.Abs(maxDensity - minDensity) < 0.01f ? 1.0f : shape.Density / avgDensity; ColorRgba shapeColor = shape.IsSensor ? this.ShapeSensorColor : this.ShapeColor; ColorRgba fontColor = this.FgColor; if (!body.IsAwake) { shapeColor = shapeColor.ToHsva().WithSaturation(0.0f).ToRgba(); } if (!shape.IsValid) { shapeColor = this.ShapeErrorColor; } // Draw the shape itself ColorRgba fillColor = shapeColor.WithAlpha((0.25f + densityRelative * 0.25f) * shapeAlpha); ColorRgba outlineColor = ColorRgba.Lerp(shapeColor, fontColor, isShapeSelected ? 0.75f : 0.25f).WithAlpha(shapeAlpha); this.DrawShape(canvas, body.GameObj.Transform, shape, fillColor, outlineColor); // Calculate the center coordinate Vector2 shapeCenter = Vector2.Zero; if (circle != null) { shapeCenter = circle.Position * objScale; } else { Vector2[] shapeVertices = null; if (poly != null) { shapeVertices = poly.Vertices; } else if (loop != null) { shapeVertices = loop.Vertices; } else if (chain != null) { shapeVertices = chain.Vertices; } for (int i = 0; i < shapeVertices.Length; i++) { shapeCenter += shapeVertices[i]; } shapeCenter /= shapeVertices.Length; } MathF.TransformCoord(ref shapeCenter.X, ref shapeCenter.Y, objAngle, objScale); // Draw shape index if (body == selectedBody) { string indexText = shapeIndex.ToString(); Vector2 textSize = textFont.MeasureText(indexText); canvas.State.ColorTint = fontColor.WithAlpha((shapeAlpha + 1.0f) * 0.5f); canvas.DrawText(indexText, objPos.X + shapeCenter.X, objPos.Y + shapeCenter.Y, 0.0f); } shapeIndex++; } // Draw center of mass if (body.BodyType == BodyType.Dynamic) { Vector2 localMassCenter = body.LocalMassCenter; MathF.TransformCoord(ref localMassCenter.X, ref localMassCenter.Y, objAngle, objScale); float size = this.GetScreenConstantScale(canvas, 6.0f); canvas.State.ColorTint = this.MassCenterColor.WithAlpha(bodyAlpha); canvas.DrawLine( objPos.X + localMassCenter.X - size, objPos.Y + localMassCenter.Y, 0.0f, objPos.X + localMassCenter.X + size, objPos.Y + localMassCenter.Y, 0.0f); canvas.DrawLine( objPos.X + localMassCenter.X, objPos.Y + localMassCenter.Y - size, 0.0f, objPos.X + localMassCenter.X, objPos.Y + localMassCenter.Y + size, 0.0f); } // Draw transform center { float size = this.GetScreenConstantScale(canvas, 3.0f); canvas.State.ColorTint = this.ObjectCenterColor.WithAlpha(bodyAlpha); canvas.FillCircle(objPos.X, objPos.Y, 0.0f, size); } } }
/// <summary> /// Extracts a rectangular region of this Layer. If the extracted region is bigger than the original Layer, /// all new space is filled with a background color. /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="w"></param> /// <param name="h"></param> /// <param name="backColor"></param> public Layer CloneSubImage(int x, int y, int w, int h, ColorRgba backColor) { Layer tempLayer = new Layer(w, h, backColor); this.DrawOnto(tempLayer, BlendMode.Solid, -x, -y); return tempLayer; }
private void DrawShape(Canvas canvas, Transform transform, ShapeInfo shape, ColorRgba fillColor, ColorRgba outlineColor) { if (shape is CircleShapeInfo) { this.DrawShape(canvas, transform, shape as CircleShapeInfo, fillColor, outlineColor); } else if (shape is LoopShapeInfo) { this.DrawShape(canvas, transform, shape as LoopShapeInfo, fillColor, outlineColor); } else if (shape is ChainShapeInfo) { this.DrawShape(canvas, transform, shape as ChainShapeInfo, fillColor, outlineColor); } else if (shape is PolyShapeInfo) { this.DrawShape(canvas, transform, shape as PolyShapeInfo, fillColor, outlineColor); } }
/// <summary> /// Performs a drawing operation from this Layer to a target layer. /// </summary> /// <param name="target"></param> /// <param name="blend"></param> /// <param name="destX"></param> /// <param name="destY"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="srcX"></param> /// <param name="srcY"></param> /// <param name="colorTint"></param> public void DrawOnto(Layer target, BlendMode blend, int destX, int destY, int width, int height, int srcX, int srcY, ColorRgba colorTint) { if (colorTint == ColorRgba.White) { this.DrawOnto(target, blend, destX, destY, width, height, srcX, srcY); return; } if (width == -1) width = this.width; if (height == -1) height = this.height; int beginX = MathF.Max(0, -destX, -srcX); int beginY = MathF.Max(0, -destY, -srcY); int endX = MathF.Min(width, this.width, target.width - destX, this.width - srcX); int endY = MathF.Min(height, this.height, target.height - destY, this.height - srcY); if (endX - beginX < 1) return; if (endY - beginY < 1) return; ColorRgba clrSource; ColorRgba clrTarget; System.Threading.Tasks.Parallel.For(beginX, endX, i => //for (int i = beginX; i < endX; i++) { for (int j = beginY; j < endY; j++) { int sourceN = srcX + i + this.width * (srcY + j); int targetN = destX + i + target.width * (destY + j); clrSource = this.data[sourceN] * colorTint; if (blend == BlendMode.Solid) { target.data[targetN] = clrSource; } else if (blend == BlendMode.Mask) { if (clrSource.A >= 0) target.data[targetN] = this.data[sourceN]; } else if (blend == BlendMode.Add) { clrTarget = target.data[targetN]; float alphaTemp = (float)clrSource.A / 255.0f; target.data[targetN].R = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrTarget.R + clrSource.R * alphaTemp))); target.data[targetN].G = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrTarget.G + clrSource.G * alphaTemp))); target.data[targetN].B = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrTarget.B + clrSource.B * alphaTemp))); target.data[targetN].A = (byte)Math.Min(255, Math.Max(0, (int)clrTarget.A + (int)clrSource.A)); } else if (blend == BlendMode.Alpha) { clrTarget = target.data[targetN]; float alphaTemp = (float)clrSource.A / 255.0f; target.data[targetN].R = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrTarget.R * (1.0f - alphaTemp) + clrSource.R * alphaTemp))); target.data[targetN].G = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrTarget.G * (1.0f - alphaTemp) + clrSource.G * alphaTemp))); target.data[targetN].B = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrTarget.B * (1.0f - alphaTemp) + clrSource.B * alphaTemp))); target.data[targetN].A = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrTarget.A * (1.0f - alphaTemp) + clrSource.A))); } else if (blend == BlendMode.Multiply) { clrTarget = target.data[targetN]; float clrTempR = (float)clrTarget.R / 255.0f; float clrTempG = (float)clrTarget.G / 255.0f; float clrTempB = (float)clrTarget.B / 255.0f; float clrTempA = (float)clrTarget.A / 255.0f; target.data[targetN].R = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrSource.R * clrTempR))); target.data[targetN].G = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrSource.G * clrTempG))); target.data[targetN].B = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrSource.B * clrTempB))); target.data[targetN].A = (byte)Math.Min(255, Math.Max(0, (int)clrTarget.A + (int)clrSource.A)); } else if (blend == BlendMode.Light) { clrTarget = target.data[targetN]; float clrTempR = (float)clrTarget.R / 255.0f; float clrTempG = (float)clrTarget.G / 255.0f; float clrTempB = (float)clrTarget.B / 255.0f; float clrTempA = (float)clrTarget.A / 255.0f; target.data[targetN].R = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrSource.R * clrTempR + clrTarget.R))); target.data[targetN].G = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrSource.G * clrTempG + clrTarget.G))); target.data[targetN].B = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrSource.B * clrTempB + clrTarget.B))); target.data[targetN].A = (byte)Math.Min(255, Math.Max(0, (int)clrTarget.A + (int)clrSource.A)); } else if (blend == BlendMode.Invert) { clrTarget = target.data[targetN]; float clrTempR = (float)clrTarget.R / 255.0f; float clrTempG = (float)clrTarget.G / 255.0f; float clrTempB = (float)clrTarget.B / 255.0f; float clrTempA = (float)clrTarget.A / 255.0f; float clrTempR2 = (float)clrSource.R / 255.0f; float clrTempG2 = (float)clrSource.G / 255.0f; float clrTempB2 = (float)clrSource.B / 255.0f; float clrTempA2 = (float)clrSource.A / 255.0f; target.data[targetN].R = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrSource.R * (1.0f - clrTempR) + clrTarget.R * (1.0f - clrTempR2)))); target.data[targetN].G = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrSource.G * (1.0f - clrTempG) + clrTarget.G * (1.0f - clrTempG2)))); target.data[targetN].B = (byte)Math.Min(255, Math.Max(0, (int)Math.Round(clrSource.B * (1.0f - clrTempB) + clrTarget.B * (1.0f - clrTempB2)))); target.data[targetN].A = (byte)Math.Min(255, Math.Max(0, (int)(clrTarget.A + clrSource.A))); } } }); }
private void DrawShape(Canvas canvas, Transform transform, ChainShapeInfo shape, ColorRgba fillColor, ColorRgba outlineColor) { this.DrawPolygonOutline(canvas, transform, shape.Vertices, outlineColor, false); }
public ColorChangeElement(ColorRgba color) { this.color = color; }
private void DrawShape(Canvas canvas, Transform transform, PolyShapeInfo shape, ColorRgba fillColor, ColorRgba outlineColor) { if (shape.ConvexPolygons != null) { // Fill each convex polygon individually foreach (Vector2[] polygon in shape.ConvexPolygons) { this.FillPolygon(canvas, transform, polygon, fillColor); } // Draw all convex polygon edges that are not outlines canvas.State.ZOffset = this.depthOffset - 0.05f; this.DrawPolygonInternals(canvas, transform, shape.Vertices, shape.ConvexPolygons, outlineColor); canvas.State.ZOffset = this.depthOffset; } // Draw the polygon outline canvas.State.ZOffset = this.depthOffset - 0.1f; this.DrawPolygonOutline(canvas, transform, shape.Vertices, outlineColor, true); canvas.State.ZOffset = this.depthOffset; }
public RenderState(RenderState other) { this.parent = other.parent; this.vertTextIndex = other.vertTextIndex.Clone() as int[]; this.vertIconIndex = other.vertIconIndex; this.offset = other.offset; this.elemIndex = other.elemIndex; this.lineIndex = other.lineIndex; this.fontIndex = other.fontIndex; this.font = other.font; this.color = other.color; this.lineBeginX = other.lineBeginX; this.lineWidth = other.lineWidth; this.lineAvailWidth = other.lineAvailWidth; this.lineHeight = other.lineHeight; this.lineBaseLine = other.lineBaseLine; this.lineAlign = other.lineAlign; this.curElemOffset = other.curElemOffset; this.curElemVertTextIndex = other.curElemVertTextIndex; this.curElemVertIconIndex = other.curElemVertIconIndex; this.curElemWrapIndex = other.curElemWrapIndex; this.curElemText = other.curElemText; }
private void DrawShape(Canvas canvas, Transform transform, CircleShapeInfo shape, ColorRgba fillColor, ColorRgba outlineColor) { Vector3 objPos = transform.Pos; float objAngle = transform.Angle; float objScale = transform.Scale; Vector2 circlePos = shape.Position * objScale; MathF.TransformCoord(ref circlePos.X, ref circlePos.Y, objAngle); if (fillColor.A > 0) { canvas.State.ColorTint = fillColor; canvas.FillCircle( objPos.X + circlePos.X, objPos.Y + circlePos.Y, 0.0f, shape.Radius * objScale); } float outlineWidth = this.GetScreenConstantScale(canvas, this.shapeOutlineWidth); canvas.State.ColorTint = outlineColor; canvas.State.ZOffset = this.depthOffset - 0.1f; canvas.FillCircleSegment( objPos.X + circlePos.X, objPos.Y + circlePos.Y, 0.0f, shape.Radius * objScale, 0.0f, MathF.RadAngle360, outlineWidth); canvas.State.ZOffset = this.depthOffset; }
/// <summary> /// Returns a format string for changing the current text color to the specified one. /// </summary> /// <returns></returns> public static string FormatColor(ColorRgba color) { int intClr = color.ToIntRgba(); return string.Format("{1}{0:X8}", intClr, FormatColorTag); }
private void FillPolygon(Canvas canvas, Transform transform, Vector2[] polygon, ColorRgba fillColor) { Vector3 objPos = transform.Pos; float objAngle = transform.Angle; float objScale = transform.Scale; canvas.State.ColorTint = fillColor; canvas.State.TransformAngle = objAngle; canvas.State.TransformScale = new Vector2(objScale, objScale); canvas.FillPolygon(polygon, objPos.X, objPos.Y, 0.0f); canvas.State.TransformAngle = 0.0f; canvas.State.TransformScale = Vector2.One; }
/// <summary> /// Emits sets of vertices for glyphs and icons based on this formatted text. To render it, use each set of vertices combined with /// the corresponding Fonts <see cref="Material"/>. /// </summary> /// <param name="vertText">One set of vertices for each Font that is available to this ForattedText.</param> /// <param name="vertIcons">A set of icon vertices.</param> /// <param name="x">An X-Offset applied to the position of each emitted vertex.</param> /// <param name="y">An Y-Offset applied to the position of each emitted vertex.</param> /// <param name="z">An Z-Offset applied to the position of each emitted vertex.</param> /// <param name="clr">The color value that is applied to each emitted vertex.</param> /// <param name="xDot">Dot product base for the transformed vertices.</param> /// <param name="yDot">Dot product base for the transformed vertices.</param> /// <returns> /// Returns an array of vertex counts for each emitted vertex array. /// Index 0 represents the number of emitted icon vertices, Index n represents the number of vertices emitted using Font n - 1. /// </returns> public int[] EmitVertices(ref VertexC1P3T2[][] vertText, ref VertexC1P3T2[] vertIcons, float x, float y, float z, ColorRgba clr, Vector2 xDot, Vector2 yDot) { int[] vertLen = this.EmitVertices(ref vertText, ref vertIcons); Vector3 offset = new Vector3(x, y, z); if (clr == ColorRgba.White) { for (int i = 0; i < vertText.Length; i++) { for (int j = 0; j < vertLen[i + 1]; j++) { MathF.TransformDotVec(ref vertText[i][j].Pos, ref xDot, ref yDot); Vector3.Add(ref vertText[i][j].Pos, ref offset, out vertText[i][j].Pos); } } for (int i = 0; i < vertLen[0]; i++) { MathF.TransformDotVec(ref vertIcons[i].Pos, ref xDot, ref yDot); Vector3.Add(ref vertIcons[i].Pos, ref offset, out vertIcons[i].Pos); } } else { for (int i = 0; i < vertText.Length; i++) { for (int j = 0; j < vertLen[i + 1]; j++) { MathF.TransformDotVec(ref vertText[i][j].Pos, ref xDot, ref yDot); Vector3.Add(ref vertText[i][j].Pos, ref offset, out vertText[i][j].Pos); ColorRgba.Multiply(ref vertText[i][j].Color, ref clr, out vertText[i][j].Color); } } for (int i = 0; i < vertLen[0]; i++) { MathF.TransformDotVec(ref vertIcons[i].Pos, ref xDot, ref yDot); Vector3.Add(ref vertIcons[i].Pos, ref offset, out vertIcons[i].Pos); ColorRgba.Multiply(ref vertIcons[i].Color, ref clr, out vertIcons[i].Color); } } return vertLen; }
private void DrawPolygonOutline(Canvas canvas, Transform transform, Vector2[] polygon, ColorRgba outlineColor, bool closedLoop) { Vector3 objPos = transform.Pos; float objAngle = transform.Angle; float objScale = transform.Scale; canvas.State.TransformAngle = objAngle; canvas.State.TransformScale = new Vector2(objScale, objScale); canvas.State.ColorTint = outlineColor; float outlineWidth = this.GetScreenConstantScale(canvas, this.shapeOutlineWidth); outlineWidth /= objScale; if (closedLoop) { canvas.FillPolygonOutline(polygon, outlineWidth, objPos.X, objPos.Y, 0.0f); } else { canvas.FillThickLineStrip(polygon, outlineWidth, objPos.X, objPos.Y, 0.0f); } canvas.State.TransformAngle = 0.0f; canvas.State.TransformScale = Vector2.One; }
public Pass(Pass copyFrom, BatchInfo inputOverride) { this.input = inputOverride; this.output = copyFrom.output; this.clearColor = copyFrom.clearColor; this.clearDepth = copyFrom.clearDepth; this.clearFlags = copyFrom.clearFlags; this.matrixMode = copyFrom.matrixMode; this.visibilityMask = copyFrom.visibilityMask; this.MakeAvailable(); }
private void DrawPolygonInternals(Canvas canvas, Transform transform, Vector2[] hullVertices, IReadOnlyList <Vector2[]> convexPolygons, ColorRgba outlineColor) { if (convexPolygons.Count <= 1) { return; } Vector3 objPos = transform.Pos; float objAngle = transform.Angle; float objScale = transform.Scale; Vector2 xDot; Vector2 yDot; MathF.GetTransformDotVec(objAngle, objScale, out xDot, out yDot); float dashPatternLength = this.GetScreenConstantScale(canvas, this.shapeOutlineWidth * 0.5f); // Generate a lookup of drawn vertex indices, so we can // avoid drawing the same edge twice. Every item is a combination // of two indices. HashSet <uint> drawnEdges = new HashSet <uint>(); for (int i = 0; i < hullVertices.Length; i++) { int currentHullIndex = i; int nextHullIndex = (i + 1) % hullVertices.Length; uint edgeId = (currentHullIndex > nextHullIndex) ? ((uint)currentHullIndex << 16) | (uint)nextHullIndex : ((uint)nextHullIndex << 16) | (uint)currentHullIndex; drawnEdges.Add(edgeId); } canvas.State.ColorTint = outlineColor; foreach (Vector2[] polygon in convexPolygons) { if (polygon.Length < 2) { continue; } int currentHullIndex; int nextHullIndex = VertexListIndex(hullVertices, polygon[0]); for (int i = 0; i < polygon.Length; i++) { int nextIndex = (i + 1) % polygon.Length; currentHullIndex = nextHullIndex; nextHullIndex = VertexListIndex(hullVertices, polygon[nextIndex]); // Filter out edges that have already been drawn if (currentHullIndex >= 0 && nextHullIndex >= 0) { uint edgeId = (currentHullIndex > nextHullIndex) ? ((uint)currentHullIndex << 16) | (uint)nextHullIndex : ((uint)nextHullIndex << 16) | (uint)currentHullIndex; if (!drawnEdges.Add(edgeId)) { continue; } } Vector2 lineStart = new Vector2( polygon[i].X, polygon[i].Y); Vector2 lineEnd = new Vector2( polygon[nextIndex].X, polygon[nextIndex].Y); MathF.TransformDotVec(ref lineStart, ref xDot, ref yDot); MathF.TransformDotVec(ref lineEnd, ref xDot, ref yDot); canvas.DrawDashLine( objPos.X + lineStart.X, objPos.Y + lineStart.Y, 0.0f, objPos.X + lineEnd.X, objPos.Y + lineEnd.Y, 0.0f, DashPattern.Dash, 1.0f / dashPatternLength); } } }