private static void rebuildUV(dfRenderData renderData, RenderOptions options) { var rect = options.spriteInfo.region; var result = renderData.UV; result.Add(new Vector2(rect.x, rect.yMax)); result.Add(new Vector2(rect.xMax, rect.yMax)); result.Add(new Vector2(rect.xMax, rect.y)); result.Add(new Vector2(rect.x, rect.y)); var temp = Vector2.zero; if (options.flip.IsSet(dfSpriteFlip.FlipHorizontal)) { temp = result[1]; result[1] = result[0]; result[0] = temp; temp = result[3]; result[3] = result[2]; result[2] = temp; } if (options.flip.IsSet(dfSpriteFlip.FlipVertical)) { temp = result[0]; result[0] = result[3]; result[3] = temp; temp = result[1]; result[1] = result[2]; result[2] = temp; } }
public override void Render(string text, dfRenderData destination) { textColors.Clear(); textColors.Push(Color.white); this.tokenize(text); dfList <dfFont.LineRenderInfo> list = this.calculateLinebreaks(); int b = 0; int num2 = 0; Vector3 vectorOffset = base.VectorOffset; float num3 = base.TextScale * base.PixelRatio; for (int i = 0; i < list.Count; i++) { dfFont.LineRenderInfo info = list[i]; int count = destination.Vertices.Count; this.renderLine(list[i], textColors, vectorOffset, destination); vectorOffset.y -= base.Font.LineHeight * num3; b = Mathf.Max((int)info.lineWidth, b); num2 += (int)info.lineHeight; if ((info.lineWidth * base.TextScale) > base.MaxSize.x) { this.clipRight(destination, count); } if ((num2 * base.TextScale) > base.MaxSize.y) { this.clipBottom(destination, count); } } base.RenderedSize = (Vector2)(new Vector2(Mathf.Min(base.MaxSize.x, (float)b), Mathf.Min(base.MaxSize.y, (float)num2)) * base.TextScale); }
private void gatherRenderBuffers(dfMarkupBox box, dfList <dfRenderData> buffers) { dfIntersectionType type = this.getViewportIntersection(box); if (type != dfIntersectionType.None) { dfRenderData renderData = box.Render(); if (renderData != null) { if ((renderData.Material == null) && (this.atlas != null)) { renderData.Material = this.atlas.Material; } float num = base.PixelsToUnits(); Vector2 vector = -this.scrollPosition.Scale(1f, -1f).RoundToInt(); Vector3 vector2 = ((Vector3)(vector + box.GetOffset().Scale(1f, -1f))) + base.pivot.TransformToUpperLeft(base.Size); dfList <Vector3> vertices = renderData.Vertices; Matrix4x4 localToWorldMatrix = base.transform.localToWorldMatrix; for (int j = 0; j < renderData.Vertices.Count; j++) { vertices[j] = localToWorldMatrix.MultiplyPoint((Vector3)((vector2 + vertices[j]) * num)); } if (type == dfIntersectionType.Intersecting) { this.clipToViewport(renderData); } buffers.Add(renderData); } for (int i = 0; i < box.Children.Count; i++) { this.gatherRenderBuffers(box.Children[i], buffers); } } }
private void rebuildUV(dfRenderData renderData) { dfList <Vector2> uV = renderData.UV; uV.Add(new Vector2(0f, 1f)); uV.Add(new Vector2(1f, 1f)); uV.Add(new Vector2(1f, 0f)); uV.Add(new Vector2(0f, 0f)); Vector2 zero = Vector2.zero; if (this.flip.IsSet(dfSpriteFlip.FlipHorizontal)) { zero = uV[1]; uV[1] = uV[0]; uV[0] = zero; zero = uV[3]; uV[3] = uV[2]; uV[2] = zero; } if (this.flip.IsSet(dfSpriteFlip.FlipVertical)) { zero = uV[0]; uV[0] = uV[3]; uV[3] = zero; zero = uV[1]; uV[1] = uV[2]; uV[2] = zero; } }
public static void Clip(IList <Plane> planes, dfRenderData source, dfRenderData dest) { dest.EnsureCapacity(dest.Vertices.Count + source.Vertices.Count); for (int i = 0; i < source.Triangles.Count; i = i + 3) { for (int j = 0; j < 3; j++) { int item = source.Triangles[i + j]; Matrix4x4 transform = source.Transform; dfClippingUtil.clipSource[0].corner[j] = transform.MultiplyPoint(source.Vertices[item]); dfClippingUtil.clipSource[0].uv[j] = source.UV[item]; dfClippingUtil.clipSource[0].color[j] = source.Colors[item]; } int plane = 1; for (int k = 0; k < planes.Count; k++) { plane = dfClippingUtil.clipToPlane(planes[k], dfClippingUtil.clipSource, dfClippingUtil.clipDest, plane); dfClippingUtil.ClipTriangle[] clipTriangleArray = dfClippingUtil.clipSource; dfClippingUtil.clipSource = dfClippingUtil.clipDest; dfClippingUtil.clipDest = clipTriangleArray; } for (int l = 0; l < plane; l++) { dfClippingUtil.clipSource[l].CopyTo(dest); } } }
public static void Clip(IList<Plane> planes, dfRenderData source, dfRenderData dest) { dest.EnsureCapacity(dest.Vertices.Count + source.Vertices.Count); for (int i = 0; i < source.Triangles.Count; i = i + 3) { for (int j = 0; j < 3; j++) { int item = source.Triangles[i + j]; Matrix4x4 transform = source.Transform; dfClippingUtil.clipSource[0].corner[j] = transform.MultiplyPoint(source.Vertices[item]); dfClippingUtil.clipSource[0].uv[j] = source.UV[item]; dfClippingUtil.clipSource[0].color[j] = source.Colors[item]; } int plane = 1; for (int k = 0; k < planes.Count; k++) { plane = dfClippingUtil.clipToPlane(planes[k], dfClippingUtil.clipSource, dfClippingUtil.clipDest, plane); dfClippingUtil.ClipTriangle[] clipTriangleArray = dfClippingUtil.clipSource; dfClippingUtil.clipSource = dfClippingUtil.clipDest; dfClippingUtil.clipDest = clipTriangleArray; } for (int l = 0; l < plane; l++) { dfClippingUtil.clipSource[l].CopyTo(dest); } } }
protected void renderDebugBox(dfRenderData renderData) { var v1 = Vector3.zero; var v2 = v1 + Vector3.right * this.Size.x; var v3 = v2 + Vector3.down * this.Size.y; var v4 = v1 + Vector3.down * this.Size.y; renderData.Vertices.Add(v1); renderData.Vertices.Add(v2); renderData.Vertices.Add(v3); renderData.Vertices.Add(v4); renderData.Triangles.AddRange(new int[] { 0, 1, 3, 3, 1, 2 }); renderData.UV.Add(Vector2.zero); renderData.UV.Add(Vector2.zero); renderData.UV.Add(Vector2.zero); renderData.UV.Add(Vector2.zero); var color = Style.BackgroundColor; renderData.Colors.Add(color); renderData.Colors.Add(color); renderData.Colors.Add(color); renderData.Colors.Add(color); }
public override void Render(string text, dfRenderData destination) { dfDynamicFont.DynamicFontRenderer.textColors.Clear(); dfDynamicFont.DynamicFontRenderer.textColors.Push(Color.white); this.tokenize(text); dfList <dfDynamicFont.LineRenderInfo> lineRenderInfos = this.calculateLinebreaks(); int num = 0; int num1 = 0; Vector3 vector3 = (base.VectorOffset / base.PixelRatio).CeilToInt(); for (int i = 0; i < lineRenderInfos.Count; i++) { dfDynamicFont.LineRenderInfo item = lineRenderInfos[i]; int count = destination.Vertices.Count; int num2 = (this.SpriteBuffer == null ? 0 : this.SpriteBuffer.Vertices.Count); this.renderLine(lineRenderInfos[i], dfDynamicFont.DynamicFontRenderer.textColors, vector3, destination); vector3.y = vector3.y - item.lineHeight; num = Mathf.Max((int)item.lineWidth, num); num1 = num1 + Mathf.CeilToInt(item.lineHeight); if (item.lineWidth > base.MaxSize.x) { this.clipRight(destination, count); this.clipRight(this.SpriteBuffer, num2); } this.clipBottom(destination, count); this.clipBottom(this.SpriteBuffer, num2); } Vector2 maxSize = base.MaxSize; float single = Mathf.Min(maxSize.x, (float)num); Vector2 vector2 = base.MaxSize; base.RenderedSize = new Vector2(single, Mathf.Min(vector2.y, (float)num1)) * base.TextScale; }
public override void Render(string text, dfRenderData destination) { dfFont.BitmappedFontRenderer.textColors.Clear(); dfFont.BitmappedFontRenderer.textColors.Push(Color.white); this.tokenize(text); dfList <dfFont.LineRenderInfo> lineRenderInfos = this.calculateLinebreaks(); int num = 0; int num1 = 0; Vector3 vectorOffset = base.VectorOffset; float textScale = base.TextScale * base.PixelRatio; for (int i = 0; i < lineRenderInfos.Count; i++) { dfFont.LineRenderInfo item = lineRenderInfos[i]; int count = destination.Vertices.Count; this.renderLine(lineRenderInfos[i], dfFont.BitmappedFontRenderer.textColors, vectorOffset, destination); vectorOffset.y = vectorOffset.y - (float)base.Font.LineHeight * textScale; num = Mathf.Max((int)item.lineWidth, num); num1 = num1 + (int)item.lineHeight; if (item.lineWidth * base.TextScale > base.MaxSize.x) { this.clipRight(destination, count); } if ((float)num1 * base.TextScale > base.MaxSize.y) { this.clipBottom(destination, count); } } Vector2 maxSize = base.MaxSize; float single = Mathf.Min(maxSize.x, (float)num); Vector2 vector2 = base.MaxSize; base.RenderedSize = new Vector2(single, Mathf.Min(vector2.y, (float)num1)) * base.TextScale; }
public void Merge(dfRenderData buffer, bool transformVertices = true) { int count = this.Vertices.Count; this.Vertices.EnsureCapacity(this.Vertices.Count + buffer.Vertices.Count); if (!transformVertices) { this.Vertices.AddRange(buffer.Vertices); } else { for (int i = 0; i < buffer.Vertices.Count; i++) { dfList <Vector3> vertices = this.Vertices; Matrix4x4 transform = buffer.Transform; vertices.Add(transform.MultiplyPoint(buffer.Vertices[i])); } } this.UV.AddRange(buffer.UV); this.Colors.AddRange(buffer.Colors); this.Normals.AddRange(buffer.Normals); this.Tangents.AddRange(buffer.Tangents); this.Triangles.EnsureCapacity(this.Triangles.Count + buffer.Triangles.Count); for (int j = 0; j < buffer.Triangles.Count; j++) { this.Triangles.Add(buffer.Triangles[j] + count); } }
public static void Clip(IList <Plane> planes, dfRenderData source, dfRenderData dest) { dest.EnsureCapacity(dest.Vertices.Count + source.Vertices.Count); for (int i = 0; i < source.Triangles.Count; i += 3) { for (int j = 0; j < 3; j++) { int num3 = source.Triangles[i + j]; dfClippingUtil.clipSource[0].corner[j] = source.Transform.MultiplyPoint(source.Vertices[num3]); dfClippingUtil.clipSource[0].uv[j] = source.UV[num3]; dfClippingUtil.clipSource[0].color[j] = source.Colors[num3]; } int count = 1; for (int k = 0; k < planes.Count; k++) { count = clipToPlane(planes[k], dfClippingUtil.clipSource, clipDest, count); ClipTriangle[] clipSource = dfClippingUtil.clipSource; dfClippingUtil.clipSource = clipDest; clipDest = clipSource; } for (int m = 0; m < count; m++) { dfClippingUtil.clipSource[m].CopyTo(dest); } } }
private static void rebuildVertices(dfRenderData renderData, RenderOptions options) { float meshLeft = 0; float meshTop = 0; float meshRight = Mathf.Ceil(options.size.x); float meshBottom = Mathf.Ceil(-options.size.y); #region Borders var spriteInfo = options.spriteInfo; float borderLeft = spriteInfo.border.left; float borderTop = spriteInfo.border.top; float borderRight = spriteInfo.border.right; float borderBottom = spriteInfo.border.bottom; if (options.flip.IsSet(dfSpriteFlip.FlipHorizontal)) { float temp = borderRight; borderRight = borderLeft; borderLeft = temp; } if (options.flip.IsSet(dfSpriteFlip.FlipVertical)) { float temp = borderBottom; borderBottom = borderTop; borderTop = temp; } #endregion // Top left corner verts[0] = new Vector3(meshLeft, meshTop, 0) + options.offset; verts[1] = verts[0] + new Vector3(borderLeft, 0, 0); verts[2] = verts[0] + new Vector3(borderLeft, -borderTop, 0); verts[3] = verts[0] + new Vector3(0, -borderTop, 0); // Top right corner verts[4] = new Vector3(meshRight - borderRight, meshTop, 0) + options.offset; verts[5] = verts[4] + new Vector3(borderRight, 0, 0); verts[6] = verts[4] + new Vector3(borderRight, -borderTop, 0); verts[7] = verts[4] + new Vector3(0, -borderTop, 0); // Bottom left corner verts[8] = new Vector3(meshLeft, meshBottom + borderBottom, 0) + options.offset; verts[9] = verts[8] + new Vector3(borderLeft, 0, 0); verts[10] = verts[8] + new Vector3(borderLeft, -borderBottom, 0); verts[11] = verts[8] + new Vector3(0, -borderBottom, 0); // Bottom right corner verts[12] = new Vector3(meshRight - borderRight, meshBottom + borderBottom, 0) + options.offset; verts[13] = verts[12] + new Vector3(borderRight, 0, 0); verts[14] = verts[12] + new Vector3(borderRight, -borderBottom, 0); verts[15] = verts[12] + new Vector3(0, -borderBottom, 0); for (int i = 0; i < verts.Length; i++) { renderData.Vertices.Add((verts[i] * options.pixelsToUnits).Quantize(options.pixelsToUnits)); } }
public void Add( dfRenderData buffer ) { if( Material == null && buffer.Material != null ) Material = buffer.Material; buffers.Add( buffer ); }
private static void rebuildColors(dfRenderData renderData, dfSprite.RenderOptions options) { for (int i = 0; i < 0x10; i++) { renderData.Colors.Add(options.color); } }
private static void rebuildUV(dfRenderData renderData, RenderOptions options) { Rect region = options.spriteInfo.region; dfList <Vector2> uV = renderData.UV; uV.Add(new Vector2(region.x, region.yMax)); uV.Add(new Vector2(region.xMax, region.yMax)); uV.Add(new Vector2(region.xMax, region.y)); uV.Add(new Vector2(region.x, region.y)); Vector2 zero = Vector2.zero; if (options.flip.IsSet(dfSpriteFlip.FlipHorizontal)) { zero = uV[1]; uV[1] = uV[0]; uV[0] = zero; zero = uV[3]; uV[3] = uV[2]; uV[2] = zero; } if (options.flip.IsSet(dfSpriteFlip.FlipVertical)) { zero = uV[0]; uV[0] = uV[3]; uV[3] = zero; zero = uV[1]; uV[1] = uV[2]; uV[2] = zero; } }
internal static new void renderSprite( dfRenderData renderData, RenderOptions options ) { #if UNITY_EDITOR var atlas = options.atlas; if( atlas == null ) throw new NullReferenceException( "The Texture Atlas cannot be null" ); if( atlas.Texture == null ) throw new NullReferenceException( "The Texture Altas has no texture assigned or the texture was deleted" ); if( options.spriteInfo == null ) throw new ArgumentNullException( "The Sprite cannot be null" ); #endif options.baseIndex = renderData.Vertices.Count; rebuildTriangles( renderData, options ); rebuildVertices( renderData, options ); rebuildUV( renderData, options ); rebuildColors( renderData, options ); if( options.fillAmount < 1f ) { doFill( renderData, options ); } }
private void clipQuads(dfRenderData buffer, int startIndex) { dfList <Vector3> vertices = buffer.Vertices; dfList <Vector2> uV = buffer.UV; float num = base.PixelsToUnits(); float a = (base.Pivot.TransformToUpperLeft(base.Size).y - this.listPadding.top) * num; float b = a - ((this.size.y - this.listPadding.vertical) * num); for (int i = startIndex; i < vertices.Count; i += 4) { Vector3 vector = vertices[i]; Vector3 vector2 = vertices[i + 1]; Vector3 vector3 = vertices[i + 2]; Vector3 vector4 = vertices[i + 3]; float num5 = vector.y - vector4.y; if (vector4.y < b) { float t = 1f - (Mathf.Abs((float)(-b + vector.y)) / num5); vector = new Vector3(vector.x, Mathf.Max(vector.y, b), vector2.z); vertices[i] = vector; float y = Mathf.Max(vector2.y, b); vector2 = new Vector3(vector2.x, y, vector2.z); vertices[i + 1] = vector2; float introduced25 = Mathf.Max(vector3.y, b); vector3 = new Vector3(vector3.x, introduced25, vector3.z); vertices[i + 2] = vector3; float introduced26 = Mathf.Max(vector4.y, b); vector4 = new Vector3(vector4.x, introduced26, vector4.z); vertices[i + 3] = vector4; Vector2 vector6 = uV[i + 3]; Vector2 vector7 = uV[i]; float num7 = Mathf.Lerp(vector6.y, vector7.y, t); Vector2 vector8 = uV[i + 3]; uV[i + 3] = new Vector2(vector8.x, num7); Vector2 vector9 = uV[i + 2]; uV[i + 2] = new Vector2(vector9.x, num7); num5 = Mathf.Abs((float)(vector4.y - vector.y)); } if (vector.y > a) { float num8 = Mathf.Abs((float)(a - vector.y)) / num5; float introduced27 = Mathf.Min(a, vector.y); vertices[i] = new Vector3(vector.x, introduced27, vector.z); float introduced28 = Mathf.Min(a, vector2.y); vertices[i + 1] = new Vector3(vector2.x, introduced28, vector2.z); float introduced29 = Mathf.Min(a, vector3.y); vertices[i + 2] = new Vector3(vector3.x, introduced29, vector3.z); float introduced30 = Mathf.Min(a, vector4.y); vertices[i + 3] = new Vector3(vector4.x, introduced30, vector4.z); Vector2 vector10 = uV[i]; Vector2 vector11 = uV[i + 3]; float num9 = Mathf.Lerp(vector10.y, vector11.y, num8); Vector2 vector12 = uV[i]; uV[i] = new Vector2(vector12.x, num9); Vector2 vector13 = uV[i + 1]; uV[i + 1] = new Vector2(vector13.x, num9); } } }
private void clipQuads(dfRenderData buffer, int startIndex) { // Performs a simplified version of triangle clipping, "clipping" vertices // to the vertical limits of the target render area. Simplified clipping // does not split triangles, it simply moves vertices to the corresponding // edge of the clip area and adjusts the UV coordinates to match, which // means that it is faster than regular triangle clipping and does not // allocate any additional memory. var verts = buffer.Vertices; var uv = buffer.UV; var p2u = PixelsToUnits(); var maxY = (Pivot.TransformToUpperLeft(Size).y - listPadding.top) * p2u; var minY = maxY - (size.y - listPadding.vertical) * p2u; for (int i = startIndex; i < verts.Count; i += 4) { var ul = verts[i + 0]; var ur = verts[i + 1]; var br = verts[i + 2]; var bl = verts[i + 3]; var h = ul.y - bl.y; // Bottom of clip rect if (bl.y < minY) { var clip = 1f - (Mathf.Abs(-minY + ul.y) / h); verts[i + 0] = ul = new Vector3(ul.x, Mathf.Max(ul.y, minY), ur.z); verts[i + 1] = ur = new Vector3(ur.x, Mathf.Max(ur.y, minY), ur.z); verts[i + 2] = br = new Vector3(br.x, Mathf.Max(br.y, minY), br.z); verts[i + 3] = bl = new Vector3(bl.x, Mathf.Max(bl.y, minY), bl.z); var uvy = Mathf.Lerp(uv[i + 3].y, uv[i].y, clip); uv[i + 3] = new Vector2(uv[i + 3].x, uvy); uv[i + 2] = new Vector2(uv[i + 2].x, uvy); h = Mathf.Abs(bl.y - ul.y); } // Top of clip rect if (ul.y > maxY) { var clip = Mathf.Abs(maxY - ul.y) / h; verts[i + 0] = new Vector3(ul.x, Mathf.Min(maxY, ul.y), ul.z); verts[i + 1] = new Vector3(ur.x, Mathf.Min(maxY, ur.y), ur.z); verts[i + 2] = new Vector3(br.x, Mathf.Min(maxY, br.y), br.z); verts[i + 3] = new Vector3(bl.x, Mathf.Min(maxY, bl.y), bl.z); var uvy = Mathf.Lerp(uv[i].y, uv[i + 3].y, clip); uv[i] = new Vector2(uv[i].x, uvy); uv[i + 1] = new Vector2(uv[i + 1].x, uvy); } } }
public void CopyTo(dfRenderData buffer) { var baseIndex = buffer.Vertices.Count; buffer.Vertices.AddRange(corner); buffer.UV.AddRange(uv); buffer.Colors.AddRange(color); buffer.Triangles.Add(baseIndex + 0, baseIndex + 1, baseIndex + 2); }
public void Add(dfRenderData buffer) { if (Material == null && buffer.Material != null) { Material = buffer.Material; } buffers.Add(buffer); }
/// <summary> /// Render the given text as mesh data to the given destination buffer /// </summary> /// <param name="text">The text to be rendered</param> /// <param name="destination">The dfRenderData buffer that will hold the /// text mesh information</param> public override void Render(string text, dfRenderData destination) { //@Profiler.BeginSample( "Render dynamic font text" ); textColors.Clear(); textColors.Push(Color.white); // Ensure that the required characters can be found in the dynamic font's // character data. var font = (dfDynamicFont)Font; var fontSize = Mathf.CeilToInt(font.FontSize * TextScale); font.RequestCharacters(text, fontSize, FontStyle.Normal); tokenize(text); var lines = calculateLinebreaks(); destination.EnsureCapacity(getAnticipatedVertCount(tokens)); var maxWidth = 0; var maxHeight = 0; var position = (VectorOffset / PixelRatio).CeilToInt(); for (int i = 0; i < lines.Count; i++) { var line = lines[i]; var lineStartIndex = destination.Vertices.Count; var spriteStartIndex = (SpriteBuffer != null) ? SpriteBuffer.Vertices.Count : 0; renderLine(lines[i], textColors, position, destination); position.y -= line.lineHeight; maxWidth = Mathf.Max((int)line.lineWidth, maxWidth); maxHeight += Mathf.CeilToInt(line.lineHeight); if (line.lineWidth > MaxSize.x) { clipRight(destination, lineStartIndex); clipRight(SpriteBuffer, spriteStartIndex); } clipBottom(destination, lineStartIndex); clipBottom(SpriteBuffer, spriteStartIndex); } this.RenderedSize = new Vector2( Mathf.Min(MaxSize.x, maxWidth), Mathf.Min(MaxSize.y, maxHeight) ) * TextScale; this.tokens.Release(); this.tokens = null; //@Profiler.EndSample(); }
private static void rebuildColors(dfRenderData renderData, RenderOptions options) { var colors = renderData.Colors; colors.Add(options.color); colors.Add(options.color); colors.Add(options.color); colors.Add(options.color); }
private static void rebuildColors(dfRenderData renderData, dfSprite.RenderOptions options) { dfList <Color32> colors = renderData.Colors; colors.Add(options.color); colors.Add(options.color); colors.Add(options.color); colors.Add(options.color); }
private static void rebuildTriangles(dfRenderData renderData, dfSprite.RenderOptions options) { int baseIndex = options.baseIndex; dfList <int> triangles = renderData.Triangles; for (int i = 0; i < triangleIndices.Length; i++) { triangles.Add(baseIndex + triangleIndices[i]); } }
public static void FlushObjectPool() { while (dfRenderData.pool.Count > 0) { dfRenderData dfRenderDatum = dfRenderData.pool.Dequeue(); dfRenderDatum.Vertices.TrimExcess(); dfRenderDatum.Triangles.TrimExcess(); dfRenderDatum.UV.TrimExcess(); dfRenderDatum.Colors.TrimExcess(); } }
private static void rebuildTriangles(dfRenderData renderData, RenderOptions options) { var baseIndex = options.baseIndex; var triangles = renderData.Triangles; for (int i = 0; i < triangleIndices.Length; i++) { triangles.Add(baseIndex + triangleIndices[i]); } }
private static void rebuildTriangles(dfRenderData renderData, RenderOptions options) { int baseIndex = options.baseIndex; dfList <int> triangles = renderData.Triangles; triangles.EnsureCapacity(triangles.Count + TRIANGLE_INDICES.Length); for (int i = 0; i < TRIANGLE_INDICES.Length; i++) { triangles.Add(baseIndex + TRIANGLE_INDICES[i]); } }
public static void FlushObjectPool() { while (pool.Count > 0) { dfRenderData data = pool.Dequeue(); data.Vertices.TrimExcess(); data.Triangles.TrimExcess(); data.UV.TrimExcess(); data.Colors.TrimExcess(); } }
public void CopyTo(dfRenderData buffer) { int count = buffer.Vertices.Count; buffer.Vertices.AddRange(this.corner); buffer.UV.AddRange(this.uv); buffer.Colors.AddRange(this.color); buffer.Triangles.Add(count); buffer.Triangles.Add(count + 1); buffer.Triangles.Add(count + 2); }
internal static void renderSprite(dfRenderData renderData, dfSprite.RenderOptions options) { options.baseIndex = renderData.Vertices.Count; rebuildTriangles(renderData, options); rebuildVertices(renderData, options); rebuildUV(renderData, options); rebuildColors(renderData, options); if (options.fillAmount < 1f) { doFill(renderData, options); } }
internal static new void renderSprite(dfRenderData renderData, dfSprite.RenderOptions options) { options.baseIndex = renderData.Vertices.Count; dfSlicedSprite.rebuildTriangles(renderData, options); dfSlicedSprite.rebuildVertices(renderData, options); dfSlicedSprite.rebuildUV(renderData, options); dfSlicedSprite.rebuildColors(renderData, options); if (options.fillAmount < 1f) { dfSlicedSprite.doFill(renderData, options); } }
internal static void renderSprite(dfRenderData data, RenderOptions options) { options.baseIndex = data.Vertices.Count; rebuildTriangles(data, options); rebuildVertices(data, options); rebuildUV(data, options); rebuildColors(data, options); if ((options.fillAmount > -1f) && (options.fillAmount < 1f)) { doFill(data, options); } }
private void clipQuads(dfRenderData buffer, int startIndex) { dfList<Vector3> vertices = buffer.Vertices; dfList<Vector2> uV = buffer.UV; float units = base.PixelsToUnits(); Vector3 upperLeft = base.Pivot.TransformToUpperLeft(base.Size); float single = (upperLeft.y - (float)this.listPadding.top) * units; float single1 = single - (this.size.y - (float)this.listPadding.vertical) * units; for (int i = startIndex; i < vertices.Count; i = i + 4) { Vector3 item = vertices[i]; Vector3 vector3 = vertices[i + 1]; Vector3 item1 = vertices[i + 2]; Vector3 vector31 = vertices[i + 3]; float single2 = item.y - vector31.y; if (vector31.y < single1) { float single3 = 1f - Mathf.Abs(-single1 + item.y) / single2; item = new Vector3(item.x, Mathf.Max(item.y, single1), vector3.z); vertices[i] = item; vector3 = new Vector3(vector3.x, Mathf.Max(vector3.y, single1), vector3.z); vertices[i + 1] = vector3; item1 = new Vector3(item1.x, Mathf.Max(item1.y, single1), item1.z); vertices[i + 2] = item1; vector31 = new Vector3(vector31.x, Mathf.Max(vector31.y, single1), vector31.z); vertices[i + 3] = vector31; float item2 = uV[i + 3].y; Vector2 vector2 = uV[i]; float single4 = Mathf.Lerp(item2, vector2.y, single3); Vector2 vector21 = uV[i + 3]; uV[i + 3] = new Vector2(vector21.x, single4); Vector2 vector22 = uV[i + 2]; uV[i + 2] = new Vector2(vector22.x, single4); single2 = Mathf.Abs(vector31.y - item.y); } if (item.y > single) { float single5 = Mathf.Abs(single - item.y) / single2; vertices[i] = new Vector3(item.x, Mathf.Min(single, item.y), item.z); vertices[i + 1] = new Vector3(vector3.x, Mathf.Min(single, vector3.y), vector3.z); vertices[i + 2] = new Vector3(item1.x, Mathf.Min(single, item1.y), item1.z); vertices[i + 3] = new Vector3(vector31.x, Mathf.Min(single, vector31.y), vector31.z); float item3 = uV[i].y; Vector2 vector23 = uV[i + 3]; float single6 = Mathf.Lerp(item3, vector23.y, single5); Vector2 item4 = uV[i]; uV[i] = new Vector2(item4.x, single6); Vector2 vector24 = uV[i + 1]; uV[i + 1] = new Vector2(vector24.x, single6); } } }
private void clipToViewport(dfRenderData renderData) { Plane[] clippingPlanes = this.GetClippingPlanes(); Material material = renderData.Material; Matrix4x4 transform = renderData.Transform; dfRichTextLabel.clipBuffer.Clear(); dfClippingUtil.Clip(clippingPlanes, renderData, dfRichTextLabel.clipBuffer); renderData.Clear(); renderData.Merge(dfRichTextLabel.clipBuffer, false); renderData.Material = material; renderData.Transform = transform; }
/// <summary> /// Clips a <see cref="dfRenderData"/> instance containing control rendering data /// against a list of <see cref="Plane"/> objects defined by the current clipping /// region, and outputs the clipped data into <paramref name="dest"/> /// </summary> /// <param name="planes">The list of planes to clip against</param> /// <param name="source">The control rendering data to be clipped</param> /// <param name="dest">The output buffer that will hold the resulting clipped data</param> public static void Clip( IList<Plane> planes, dfRenderData source, dfRenderData dest ) { dest.EnsureCapacity( dest.Vertices.Count + source.Vertices.Count ); var triangleCount = source.Triangles.Count; var vertices = source.Vertices.Items; var triangles = source.Triangles.Items; var uvs = source.UV.Items; var colors = source.Colors.Items; var transform = source.Transform; var planeCount = planes.Count; for( int sourceIndex = 0; sourceIndex < triangleCount; sourceIndex += 3 ) { for( int i = 0; i < 3; i++ ) { var index = triangles[ sourceIndex + i ]; clipSource[ 0 ].corner[ i ] = transform.MultiplyPoint( vertices[ index ] ); clipSource[ 0 ].uv[ i ] = uvs[ index ]; clipSource[ 0 ].color[ i ] = colors[ index ]; } var count = 1; for( int planeIndex = 0; planeIndex < planeCount; planeIndex++ ) { var clipPlane = planes[ planeIndex ]; count = clipToPlane( ref clipPlane, clipSource, clipDest, count ); var temp = clipSource; clipSource = clipDest; clipDest = temp; } for( int i = 0; i < count; i++ ) { clipSource[ i ].CopyTo( dest ); } } }
private void clipToViewport( dfRenderData renderData ) { var planes = getViewportClippingPlanes(); var material = renderData.Material; var matrix = renderData.Transform; clipBuffer.Clear(); dfClippingUtil.Clip( planes, renderData, clipBuffer ); renderData.Clear(); renderData.Merge( clipBuffer, false ); renderData.Material = material; renderData.Transform = matrix; }
private void rebuildUV( dfRenderData renderData ) { var result = renderData.UV; result.Add( new Vector2( 0, 1 ) ); result.Add( new Vector2( 1, 1 ) ); result.Add( new Vector2( 1, 0 ) ); result.Add( new Vector2( 0, 0 ) ); var temp = Vector2.zero; if( flip.IsSet( dfSpriteFlip.FlipHorizontal ) ) { temp = result[ 1 ]; result[ 1 ] = result[ 0 ]; result[ 0 ] = temp; temp = result[ 3 ]; result[ 3 ] = result[ 2 ]; result[ 2 ] = temp; } if( flip.IsSet( dfSpriteFlip.FlipVertical ) ) { temp = result[ 0 ]; result[ 0 ] = result[ 3 ]; result[ 3 ] = temp; temp = result[ 1 ]; result[ 1 ] = result[ 2 ]; result[ 2 ] = temp; } }
private static void rebuildVertices( dfRenderData renderData, RenderOptions options ) { float meshLeft = 0; float meshTop = 0; float meshRight = Mathf.Ceil( options.size.x ); float meshBottom = Mathf.Ceil( -options.size.y ); #region Borders var spriteInfo = options.spriteInfo; float borderLeft = spriteInfo.border.left; float borderTop = spriteInfo.border.top; float borderRight = spriteInfo.border.right; float borderBottom = spriteInfo.border.bottom; if( options.flip.IsSet( dfSpriteFlip.FlipHorizontal ) ) { float temp = borderRight; borderRight = borderLeft; borderLeft = temp; } if( options.flip.IsSet( dfSpriteFlip.FlipVertical ) ) { float temp = borderBottom; borderBottom = borderTop; borderTop = temp; } #endregion // Top left corner verts[ 0 ] = new Vector3( meshLeft, meshTop, 0 ) + options.offset; verts[ 1 ] = verts[ 0 ] + new Vector3( borderLeft, 0, 0 ); verts[ 2 ] = verts[ 0 ] + new Vector3( borderLeft, -borderTop, 0 ); verts[ 3 ] = verts[ 0 ] + new Vector3( 0, -borderTop, 0 ); // Top right corner verts[ 4 ] = new Vector3( meshRight - borderRight, meshTop, 0 ) + options.offset; verts[ 5 ] = verts[ 4 ] + new Vector3( borderRight, 0, 0 ); verts[ 6 ] = verts[ 4 ] + new Vector3( borderRight, -borderTop, 0 ); verts[ 7 ] = verts[ 4 ] + new Vector3( 0, -borderTop, 0 ); // Bottom left corner verts[ 8 ] = new Vector3( meshLeft, meshBottom + borderBottom, 0 ) + options.offset; verts[ 9 ] = verts[ 8 ] + new Vector3( borderLeft, 0, 0 ); verts[ 10 ] = verts[ 8 ] + new Vector3( borderLeft, -borderBottom, 0 ); verts[ 11 ] = verts[ 8 ] + new Vector3( 0, -borderBottom, 0 ); // Bottom right corner verts[ 12 ] = new Vector3( meshRight - borderRight, meshBottom + borderBottom, 0 ) + options.offset; verts[ 13 ] = verts[ 12 ] + new Vector3( borderRight, 0, 0 ); verts[ 14 ] = verts[ 12 ] + new Vector3( borderRight, -borderBottom, 0 ); verts[ 15 ] = verts[ 12 ] + new Vector3( 0, -borderBottom, 0 ); for( int i = 0; i < verts.Length; i++ ) { renderData.Vertices.Add( ( verts[ i ] * options.pixelsToUnits ).Quantize( options.pixelsToUnits ) ); } }
public dfList<dfRenderData> RenderMultiple() { if( Atlas == null || Font == null ) return null; if( !isVisible ) { return null; } // Initialize render buffers if needed if( renderData == null ) { renderData = dfRenderData.Obtain(); textRenderData = dfRenderData.Obtain(); isControlInvalidated = true; } // If control is not dirty, update the transforms on the // render buffers (in case control moved) and return // pre-rendered data if( !isControlInvalidated ) { for( int i = 0; i < buffers.Count; i++ ) { buffers[ i ].Transform = transform.localToWorldMatrix; } return buffers; } #region Prepare render buffers buffers.Clear(); renderData.Clear(); renderData.Material = Atlas.Material; renderData.Transform = this.transform.localToWorldMatrix; buffers.Add( renderData ); textRenderData.Clear(); textRenderData.Material = Atlas.Material; textRenderData.Transform = this.transform.localToWorldMatrix; buffers.Add( textRenderData ); #endregion // Render background before anything else, since we're going to // want to keep track of where the background data ends and any // other data begins renderBackground(); // We want to start clipping *after* the background is rendered, so // grab the current number of vertices before rendering other elements var spriteClipStart = renderData.Vertices.Count; // Render other sprites renderHover(); renderSelection(); // Render text items renderItems( textRenderData ); // Perform clipping clipQuads( renderData, spriteClipStart ); clipQuads( textRenderData, 0 ); // Control is no longer in need of rendering isControlInvalidated = false; // Make sure that the collider size always matches the control updateCollider(); return buffers; }
private void clipToViewport( dfRenderData renderData ) { //@Profiler.BeginSample( "Clip markup box to viewport" ); var planes = getViewportClippingPlanes(); var material = renderData.Material; var matrix = renderData.Transform; clipBuffer.Clear(); dfClippingUtil.Clip( planes, renderData, clipBuffer ); renderData.Clear(); renderData.Merge( clipBuffer, false ); renderData.Material = material; renderData.Transform = matrix; Profiler.EndSample(); }
private void renderText( dfRenderData textBuffer ) { var p2u = PixelsToUnits(); var maxSize = new Vector2( size.x - padding.horizontal, this.size.y - padding.vertical ); var pivotOffset = pivot.TransformToUpperLeft( Size ); var origin = new Vector3( pivotOffset.x + padding.left, pivotOffset.y - padding.top, 0 ) * p2u; var displayText = IsPasswordField && !string.IsNullOrEmpty( this.passwordChar ) ? passwordDisplayText() : this.text; var renderColor = IsEnabled ? TextColor : DisabledColor; var scaleMultiplier = getTextScaleMultiplier(); using( var textRenderer = font.ObtainRenderer() ) { textRenderer.WordWrap = false; textRenderer.MaxSize = maxSize; textRenderer.PixelRatio = p2u; textRenderer.TextScale = TextScale * scaleMultiplier; textRenderer.VectorOffset = origin; textRenderer.MultiLine = false; textRenderer.TextAlign = TextAlignment.Left; textRenderer.ProcessMarkup = false; textRenderer.DefaultColor = renderColor; textRenderer.BottomColor = renderColor; textRenderer.OverrideMarkupColors = false; textRenderer.Opacity = this.CalculateOpacity(); textRenderer.Shadow = this.Shadow; textRenderer.ShadowColor = this.ShadowColor; textRenderer.ShadowOffset = this.ShadowOffset; #region Manage the scroll position - Keep cursor in view at all times cursorIndex = Mathf.Min( cursorIndex, displayText.Length ); scrollIndex = Mathf.Min( Mathf.Min( scrollIndex, cursorIndex ), displayText.Length ); charWidths = textRenderer.GetCharacterWidths( displayText ); var maxRenderSize = maxSize * p2u; leftOffset = 0f; if( textAlign == TextAlignment.Left ) { // Measure everything from the current scroll position up to the cursor var renderedWidth = 0f; for( int i = scrollIndex; i < cursorIndex; i++ ) { renderedWidth += charWidths[ i ]; } // Make sure that the cursor can still be viewed while( renderedWidth >= maxRenderSize.x && scrollIndex < cursorIndex ) { renderedWidth -= charWidths[ scrollIndex++ ]; } } else { scrollIndex = Mathf.Max( 0, Mathf.Min( cursorIndex, displayText.Length - 1 ) ); var renderedWidth = 0f; var slop = font.FontSize * 1.25f * p2u; while( scrollIndex > 0 && renderedWidth < maxRenderSize.x - slop ) { renderedWidth += charWidths[ scrollIndex-- ]; } var textSize = ( displayText.Length > 0 ) ? textRenderer.GetCharacterWidths( displayText.Substring( scrollIndex ) ).Sum() : 0; switch( textAlign ) { case TextAlignment.Center: leftOffset = Mathf.Max( 0, ( maxRenderSize.x - textSize ) * 0.5f ); break; case TextAlignment.Right: leftOffset = Mathf.Max( 0, maxRenderSize.x - textSize ); break; } origin.x += leftOffset; textRenderer.VectorOffset = origin; } #endregion if( selectionEnd != selectionStart ) { renderSelection( scrollIndex, charWidths, leftOffset ); } else if( cursorShown ) { renderCursor( scrollIndex, cursorIndex, charWidths, leftOffset ); } textRenderer.Render( displayText.Substring( scrollIndex ), textBuffer ); } }
/// <summary> /// Renders a single line of text /// </summary> private void renderLine( LineRenderInfo line, Stack<Color32> colors, Vector3 position, dfRenderData destination ) { position.x += calculateLineAlignment( line ); for( int i = line.startOffset; i <= line.endOffset; i++ ) { var token = tokens[ i ]; var type = token.TokenType; if( type == dfMarkupTokenType.Text ) { renderText( token, colors.Peek(), position, destination ); } else if( type == dfMarkupTokenType.StartTag ) { if( token.Matches( "sprite" ) && SpriteAtlas != null && SpriteBuffer != null ) { renderSprite( token, colors.Peek(), position, SpriteBuffer ); } else if( token.Matches( "color" ) ) { colors.Push( parseColor( token ) ); } } else if( type == dfMarkupTokenType.EndTag ) { if( token.Matches( "color" ) && colors.Count > 1 ) { colors.Pop(); } } position.x += token.Width; } }
private void renderSprite( dfMarkupToken token, Color32 color, Vector3 position, dfRenderData destination ) { try { //@Profiler.BeginSample( "Render embedded sprite" ); var spriteName = token.GetAttribute( 0 ).Value.Value; var spriteInfo = SpriteAtlas[ spriteName ]; if( spriteInfo == null ) return; var options = new dfSprite.RenderOptions() { atlas = SpriteAtlas, color = color, fillAmount = 1, flip = dfSpriteFlip.None, offset = position, pixelsToUnits = PixelRatio, size = new Vector2( token.Width, token.Height ), spriteInfo = spriteInfo }; dfSprite.renderSprite( SpriteBuffer, options ); } finally { //@Profiler.EndSample(); } }
private void clipBottom( dfRenderData destination, int startIndex ) { if( destination == null ) return; var limit = VectorOffset.y - MaxSize.y * PixelRatio; var verts = destination.Vertices; var uv = destination.UV; var colors = destination.Colors; for( int i = startIndex; i < verts.Count; i += 4 ) { var ul = verts[ i + 0 ]; var ur = verts[ i + 1 ]; var br = verts[ i + 2 ]; var bl = verts[ i + 3 ]; var h = ul.y - bl.y; if( bl.y <= limit ) { var clip = 1f - ( Mathf.Abs( -limit + ul.y ) / h ); verts[ i + 0 ] = ul = new Vector3( ul.x, Mathf.Max( ul.y, limit ), ur.z ); verts[ i + 1 ] = ur = new Vector3( ur.x, Mathf.Max( ur.y, limit ), ur.z ); verts[ i + 2 ] = br = new Vector3( br.x, Mathf.Max( br.y, limit ), br.z ); verts[ i + 3 ] = bl = new Vector3( bl.x, Mathf.Max( bl.y, limit ), bl.z ); uv[ i + 3 ] = Vector2.Lerp( uv[ i + 3 ], uv[ i + 0 ], clip ); uv[ i + 2 ] = Vector2.Lerp( uv[ i + 2 ], uv[ i + 1 ], clip ); var color = Color.Lerp( colors[ i + 3 ], colors[ i ], clip ); colors[ i + 3 ] = color; colors[ i + 2 ] = color; } } }
private void clipQuads( dfRenderData buffer, int startIndex ) { // Performs a simplified version of triangle clipping, "clipping" vertices // to the vertical limits of the target render area. Simplified clipping // does not split triangles, it simply moves vertices to the corresponding // edge of the clip area and adjusts the UV coordinates to match, which // means that it is faster than regular triangle clipping and does not // allocate any additional memory. var verts = buffer.Vertices; var uv = buffer.UV; var p2u = PixelsToUnits(); var maxY = ( Pivot.TransformToUpperLeft( Size ).y - listPadding.top ) * p2u; var minY = maxY - ( size.y - listPadding.vertical ) * p2u; for( int i = startIndex; i < verts.Count; i += 4 ) { var ul = verts[ i + 0 ]; var ur = verts[ i + 1 ]; var br = verts[ i + 2 ]; var bl = verts[ i + 3 ]; var h = ul.y - bl.y; // Bottom of clip rect if( bl.y < minY ) { var clip = 1f - ( Mathf.Abs( -minY + ul.y ) / h ); verts[ i + 0 ] = ul = new Vector3( ul.x, Mathf.Max( ul.y, minY ), ur.z ); verts[ i + 1 ] = ur = new Vector3( ur.x, Mathf.Max( ur.y, minY ), ur.z ); verts[ i + 2 ] = br = new Vector3( br.x, Mathf.Max( br.y, minY ), br.z ); verts[ i + 3 ] = bl = new Vector3( bl.x, Mathf.Max( bl.y, minY ), bl.z ); var uvy = Mathf.Lerp( uv[ i + 3 ].y, uv[ i ].y, clip ); uv[ i + 3 ] = new Vector2( uv[ i + 3 ].x, uvy ); uv[ i + 2 ] = new Vector2( uv[ i + 2 ].x, uvy ); h = Mathf.Abs( bl.y - ul.y ); } // Top of clip rect if( ul.y > maxY ) { var clip = Mathf.Abs( maxY - ul.y ) / h; verts[ i + 0 ] = new Vector3( ul.x, Mathf.Min( maxY, ul.y ), ul.z ); verts[ i + 1 ] = new Vector3( ur.x, Mathf.Min( maxY, ur.y ), ur.z ); verts[ i + 2 ] = new Vector3( br.x, Mathf.Min( maxY, br.y ), br.z ); verts[ i + 3 ] = new Vector3( bl.x, Mathf.Min( maxY, bl.y ), bl.z ); var uvy = Mathf.Lerp( uv[ i ].y, uv[ i + 3 ].y, clip ); uv[ i ] = new Vector2( uv[ i ].x, uvy ); uv[ i + 1 ] = new Vector2( uv[ i + 1 ].x, uvy ); } } }
private void doFill( dfRenderData renderData ) { var verts = renderData.Vertices; var uv = renderData.UV; var ul = 0; var ur = 1; var bl = 3; var br = 2; if( invertFill ) { if( fillDirection == dfFillDirection.Horizontal ) { ul = 1; ur = 0; bl = 2; br = 3; } else { ul = 3; ur = 2; bl = 0; br = 1; } } if( fillDirection == dfFillDirection.Horizontal ) { verts[ ur ] = Vector3.Lerp( verts[ ur ], verts[ ul ], 1f - fillAmount ); verts[ br ] = Vector3.Lerp( verts[ br ], verts[ bl ], 1f - fillAmount ); uv[ ur ] = Vector2.Lerp( uv[ ur ], uv[ ul ], 1f - fillAmount ); uv[ br ] = Vector2.Lerp( uv[ br ], uv[ bl ], 1f - fillAmount ); } else { verts[ bl ] = Vector3.Lerp( verts[ bl ], verts[ ul ], 1f - fillAmount ); verts[ br ] = Vector3.Lerp( verts[ br ], verts[ ur ], 1f - fillAmount ); uv[ bl ] = Vector2.Lerp( uv[ bl ], uv[ ul ], 1f - fillAmount ); uv[ br ] = Vector2.Lerp( uv[ br ], uv[ ur ], 1f - fillAmount ); } }
public dfList<dfRenderData> RenderMultiple() { if( renderData == null ) { renderData = dfRenderData.Obtain(); textRenderData = dfRenderData.Obtain(); isControlInvalidated = true; } var matrix = transform.localToWorldMatrix; if( !isControlInvalidated ) { for( int i = 0; i < buffers.Count; i++ ) { buffers[ i ].Transform = matrix; } return buffers; } isControlInvalidated = false; buffers.Clear(); renderData.Clear(); if( Atlas != null ) { renderData.Material = Atlas.Material; renderData.Transform = matrix; renderBackground(); buffers.Add( renderData ); } var textBuffer = renderText(); if( textBuffer != null && textBuffer != renderData ) { textBuffer.Transform = matrix; buffers.Add( textBuffer ); } // Make sure that the collider size always matches the control updateCollider(); return buffers; }
private void renderItems( dfRenderData buffer ) { if( font == null || items == null || items.Length == 0 ) return; var p2u = PixelsToUnits(); var maxSize = new Vector2( this.size.x - itemPadding.horizontal - listPadding.horizontal, itemHeight - itemPadding.vertical ); var pivotOffset = pivot.TransformToUpperLeft( Size ); var origin = new Vector3( pivotOffset.x + itemPadding.left + listPadding.left, pivotOffset.y - itemPadding.top - listPadding.top, 0 ) * p2u; origin.y += scrollPosition * p2u; var renderColor = IsEnabled ? ItemTextColor : DisabledColor; // TODO: Figure out why the text renderer cannot be re-used for each list item var top = pivotOffset.y * p2u; var bottom = top - size.y * p2u; for( int i = 0; i < items.Length; i++ ) { using( var textRenderer = font.ObtainRenderer() ) { textRenderer.WordWrap = false; textRenderer.MaxSize = maxSize; textRenderer.PixelRatio = p2u; textRenderer.TextScale = ItemTextScale * getTextScaleMultiplier(); textRenderer.VectorOffset = origin; textRenderer.MultiLine = false; textRenderer.TextAlign = this.ItemAlignment; textRenderer.ProcessMarkup = true; textRenderer.DefaultColor = renderColor; textRenderer.OverrideMarkupColors = false; textRenderer.Opacity = this.CalculateOpacity(); textRenderer.Shadow = this.Shadow; textRenderer.ShadowColor = this.ShadowColor; textRenderer.ShadowOffset = this.ShadowOffset; var dynamicFontRenderer = textRenderer as dfDynamicFont.DynamicFontRenderer; if( dynamicFontRenderer != null ) { dynamicFontRenderer.SpriteAtlas = this.Atlas; dynamicFontRenderer.SpriteBuffer = renderData; } if( origin.y - itemHeight * p2u <= top ) { textRenderer.Render( items[ i ], buffer ); } origin.y -= itemHeight * p2u; textRenderer.VectorOffset = origin; if( origin.y < bottom ) break; } } }
private void clipRight( dfRenderData destination, int startIndex ) { if( destination == null ) return; var limit = VectorOffset.x + MaxSize.x * PixelRatio; var verts = destination.Vertices; var uv = destination.UV; for( int i = startIndex; i < verts.Count; i += 4 ) { var ul = verts[ i + 0 ]; var ur = verts[ i + 1 ]; var br = verts[ i + 2 ]; var bl = verts[ i + 3 ]; var w = ur.x - ul.x; if( ur.x > limit ) { var clip = 1f - ( ( limit - ur.x + w ) / w ); verts[ i + 0 ] = ul = new Vector3( Mathf.Min( ul.x, limit ), ul.y, ul.z ); verts[ i + 1 ] = ur = new Vector3( Mathf.Min( ur.x, limit ), ur.y, ur.z ); verts[ i + 2 ] = br = new Vector3( Mathf.Min( br.x, limit ), br.y, br.z ); verts[ i + 3 ] = bl = new Vector3( Mathf.Min( bl.x, limit ), bl.y, bl.z ); var uvx = Mathf.Lerp( uv[ i + 1 ].x, uv[ i ].x, clip ); uv[ i + 1 ] = new Vector2( uvx, uv[ i + 1 ].y ); uv[ i + 2 ] = new Vector2( uvx, uv[ i + 2 ].y ); w = ur.x - ul.x; } } }
private bool isEmptyBuffer( dfRenderData buffer ) { return buffer.Vertices.Count == 0; }
/// <summary> /// Render the given text as mesh data to the given destination buffer /// </summary> /// <param name="text">The text to be rendered</param> /// <param name="destination">The dfRenderData buffer that will hold the /// text mesh information</param> public override void Render( string text, dfRenderData destination ) { //@Profiler.BeginSample( "Render dynamic font text" ); textColors.Clear(); textColors.Push( Color.white ); // Ensure that the required characters can be found in the dynamic font's // character data. var font = (dfDynamicFont)Font; var fontSize = Mathf.CeilToInt( font.FontSize * TextScale ); font.RequestCharacters( text, fontSize, FontStyle.Normal ); tokenize( text ); var lines = calculateLinebreaks(); destination.EnsureCapacity( getAnticipatedVertCount( tokens ) ); var maxWidth = 0; var maxHeight = 0; var position = ( VectorOffset / PixelRatio ).CeilToInt(); for( int i = 0; i < lines.Count; i++ ) { var line = lines[ i ]; var lineStartIndex = destination.Vertices.Count; var spriteStartIndex = ( SpriteBuffer != null ) ? SpriteBuffer.Vertices.Count : 0; renderLine( lines[ i ], textColors, position, destination ); position.y -= line.lineHeight; maxWidth = Mathf.Max( (int)line.lineWidth, maxWidth ); maxHeight += Mathf.CeilToInt( line.lineHeight ); if( line.lineWidth > MaxSize.x ) { clipRight( destination, lineStartIndex ); clipRight( SpriteBuffer, spriteStartIndex ); } clipBottom( destination, lineStartIndex ); clipBottom( SpriteBuffer, spriteStartIndex ); } this.RenderedSize = new Vector2( Mathf.Min( MaxSize.x, maxWidth ), Mathf.Min( MaxSize.y, maxHeight ) ) * TextScale; this.tokens.Release(); this.tokens = null; //@Profiler.EndSample(); }
private bool processRenderData( ref dfRenderData buffer, dfRenderData controlData, ref Bounds bounds, ref Rect screenRect, uint checksum, dfTriangleClippingRegion clipInfo, ref bool wasClipped ) { wasClipped = false; // This shouldn't happen in practice, but need to make certain if( controlData == null || controlData.Material == null || !controlData.IsValid() ) return false; // A new draw call is needed every time the current Material, Texture, or Shader // changes. If the control returned a buffer that is not empty and uses a // different Material, need to grab a new draw call buffer from the object pool. bool needNewDrawcall = false; if( buffer == null ) { needNewDrawcall = true; } else { if( !Material.Equals( controlData.Material, buffer.Material ) ) { needNewDrawcall = true; } else if( !textureEqual( controlData.Material.mainTexture, buffer.Material.mainTexture ) ) { needNewDrawcall = true; } else if( !shaderEqual( buffer.Shader, controlData.Shader ) ) { needNewDrawcall = true; } else if( !this.clipInfo.IsEmpty && drawCallBuffers.Count == 1 ) { needNewDrawcall = true; } } if( needNewDrawcall ) { buffer = getDrawCallBuffer( controlData.Material ); buffer.Material = controlData.Material; buffer.Material.mainTexture = controlData.Material.mainTexture; buffer.Material.shader = controlData.Shader ?? controlData.Material.shader; } if( !Application.isPlaying || clipType == dfClippingMethod.Software ) { // Ensure that the control's render data is properly clipped to the // current clipping region if( clipInfo.PerformClipping( buffer, ref bounds, checksum, controlData ) ) { return true; } // If PerformClipping() returns FALSE, then the control was outside of // the active clipping region wasClipped = true; } else { if( clipRect.IsEmpty() || screenRect.Intersects( clipRect ) ) { buffer.Merge( controlData ); } else { // Control was not inside of the active clipping rectangle wasClipped = true; } } return false; }
private void renderText( dfMarkupToken token, Color32 color, Vector3 position, dfRenderData renderData ) { try { //@Profiler.BeginSample( "Render text token" ); var font = (dfDynamicFont)Font; var fontSize = Mathf.CeilToInt( font.FontSize * TextScale ); var fontStyle = FontStyle.Normal; var glyph = new UnityEngine.CharacterInfo(); var descent = font.Descent; var verts = renderData.Vertices; var triangles = renderData.Triangles; var uvs = renderData.UV; var colors = renderData.Colors; var x = position.x; var y = position.y; // Set the render material in the output buffer *after* requesting // glyph data, which may result in CharacterInfo in the dfDynamicFont's // texture atlas being rebuilt. renderData.Material = font.Material; var topColor = applyOpacity( multiplyColors( color, DefaultColor ) ); var bottomColor = topColor; if( BottomColor.HasValue ) { bottomColor = applyOpacity( multiplyColors( color, BottomColor.Value ) ); } for( int i = 0; i < token.Length; i++ ) { if( i > 0 ) x += CharacterSpacing * TextScale; if( !font.baseFont.GetCharacterInfo( token[ i ], out glyph, fontSize, fontStyle ) ) continue; var yadjust = ( font.FontSize + glyph.vert.y ) - fontSize + descent; var quadLeft = ( x + glyph.vert.x ); var quadTop = ( y + yadjust ); var quadRight = ( quadLeft + glyph.vert.width ); var quadBottom = ( quadTop + glyph.vert.height ); var v0 = new Vector3( quadLeft, quadTop ) * PixelRatio; var v1 = new Vector3( quadRight, quadTop ) * PixelRatio; var v2 = new Vector3( quadRight, quadBottom ) * PixelRatio; var v3 = new Vector3( quadLeft, quadBottom ) * PixelRatio; if( Shadow ) { addTriangleIndices( verts, triangles ); var activeShadowOffset = (Vector3)ShadowOffset * PixelRatio; verts.Add( v0 + activeShadowOffset ); verts.Add( v1 + activeShadowOffset ); verts.Add( v2 + activeShadowOffset ); verts.Add( v3 + activeShadowOffset ); var activeShadowColor = applyOpacity( ShadowColor ); colors.Add( activeShadowColor ); colors.Add( activeShadowColor ); colors.Add( activeShadowColor ); colors.Add( activeShadowColor ); addUVCoords( uvs, glyph ); } if( Outline ) { for( int o = 0; o < OUTLINE_OFFSETS.Length; o++ ) { addTriangleIndices( verts, triangles ); var activeOutlineOffset = (Vector3)OUTLINE_OFFSETS[ o ] * OutlineSize * PixelRatio; verts.Add( v0 + activeOutlineOffset ); verts.Add( v1 + activeOutlineOffset ); verts.Add( v2 + activeOutlineOffset ); verts.Add( v3 + activeOutlineOffset ); var activeOutlineColor = applyOpacity( OutlineColor ); colors.Add( activeOutlineColor ); colors.Add( activeOutlineColor ); colors.Add( activeOutlineColor ); colors.Add( activeOutlineColor ); addUVCoords( uvs, glyph ); } } addTriangleIndices( verts, triangles ); verts.Add( v0 ); verts.Add( v1 ); verts.Add( v2 ); verts.Add( v3 ); colors.Add( topColor ); colors.Add( topColor ); colors.Add( bottomColor ); colors.Add( bottomColor ); addUVCoords( uvs, glyph ); x += Mathf.CeilToInt( glyph.vert.x + glyph.vert.width ); } } finally { //@Profiler.EndSample(); } }
private void renderControl( ref dfRenderData buffer, dfControl control, uint checksum, float opacity ) { // Don't render controls that are not currently active if( !control.enabled || !control.gameObject.activeSelf ) return; // Don't render controls that are invisible. Keeping a running // accumulator for opacity allows us to know a control's final // calculated opacity var effectiveOpacity = opacity * control.Opacity; if( effectiveOpacity <= 0.001f ) { return; } // If this control has a dfRenderGroup component on it, then pass off all // responsibility for rendering that control to the component. var renderGroup = GetRenderGroupForControl( control, true ); if( renderGroup != null && renderGroup != this && renderGroup.enabled ) { renderGroups.Add( renderGroup ); renderGroup.Render( renderCamera, control, groupOccluders, groupControls, checksum, effectiveOpacity ); return; } // Don't render controls that have the IsVisible flag set to FALSE. Note that this is tested // *after* checking for the presence of a dfRenderGroup component, since that component (if // present) will need to update its own internal state if the control's IsVisible property // has changed. if( !control.GetIsVisibleRaw() ) return; // Grab the current clip region information off the stack var clipInfo = clipStack.Peek(); // Update the checksum to include the current control checksum = dfChecksumUtil.Calculate( checksum, control.Version ); // Retrieve the control's bounds, which will be used in intersection testing // and triangle clipping. var bounds = control.GetBounds(); var screenRect = control.GetScreenRect(); var occluder = getControlOccluder( ref screenRect, control ); // Indicates whether the control was not rendered because it fell outside // of the currently-active clipping region var wasClipped = false; if( !( control is IDFMultiRender ) ) { // Ask the control to render itself and return a buffer of the // information needed to render it as a Mesh var controlData = control.Render(); if( controlData != null ) { processRenderData( ref buffer, controlData, ref bounds, ref screenRect, checksum, clipInfo, ref wasClipped ); } } else { // Ask the control to render itself and return as many dfRenderData buffers // as needed to render all elements of the control as a Mesh var childBuffers = ( (IDFMultiRender)control ).RenderMultiple(); if( childBuffers != null ) { var buffers = childBuffers.Items; var bufferCount = childBuffers.Count; for( int i = 0; i < bufferCount; i++ ) { var childBuffer = buffers[ i ]; if( childBuffer != null ) { processRenderData( ref buffer, childBuffer, ref bounds, ref screenRect, checksum, clipInfo, ref wasClipped ); } } } } // Allow control to keep track of its clipping state control.setClippingState( wasClipped ); // Keep track of which controls are rendered, and where they appear on-screen groupOccluders.Add( occluder ); groupControls.Add( control ); // If the control has the "Clip child controls" option set, push // its clip region information onto the stack so that all controls // lower in the hierarchy are clipped against that region. if( control.ClipChildren ) { if( !Application.isPlaying || clipType == dfClippingMethod.Software ) { clipInfo = dfTriangleClippingRegion.Obtain( clipInfo, control ); clipStack.Push( clipInfo ); } else if( this.clipInfo.IsEmpty ) { setClipRegion( control, ref screenRect ); } } // Dereference raw child control list for direct access var childControls = control.Controls.Items; var childCount = control.Controls.Count; // Ensure lists contain enough space for child controls groupControls.EnsureCapacity( groupControls.Count + childCount ); groupOccluders.EnsureCapacity( groupOccluders.Count + childCount ); // Render all child controls for( int i = 0; i < childCount; i++ ) { renderControl( ref buffer, childControls[ i ], checksum, effectiveOpacity ); } // No longer need the current control's clip region information if( control.ClipChildren ) { if( !Application.isPlaying || clipType == dfClippingMethod.Software ) { clipStack.Pop().Release(); } } }
protected void renderDebugBox( dfRenderData renderData ) { var v1 = Vector3.zero; var v2 = v1 + Vector3.right * this.Size.x; var v3 = v2 + Vector3.down * this.Size.y; var v4 = v1 + Vector3.down * this.Size.y; renderData.Vertices.Add( v1 ); renderData.Vertices.Add( v2 ); renderData.Vertices.Add( v3 ); renderData.Vertices.Add( v4 ); renderData.Triangles.AddRange( new int[] { 0, 1, 3, 3, 1, 2 } ); renderData.UV.Add( Vector2.zero ); renderData.UV.Add( Vector2.zero ); renderData.UV.Add( Vector2.zero ); renderData.UV.Add( Vector2.zero ); var color = Style.BackgroundColor; renderData.Colors.Add( color ); renderData.Colors.Add( color ); renderData.Colors.Add( color ); renderData.Colors.Add( color ); }
/// <summary> /// Merges another <see cref="dfRenderData"/> instance with this instance /// </summary> /// <param name="buffer">The render data to be appended to this instance</param> /// <param name="transformVertices">If set to TRUE, the render data in /// <paramref name="buffer"/> will be transformed by its <see cref="Transform"/> /// before being merged with this instance. If set to FALSE, the data will be /// merged without tranforming.</param> public void Merge( dfRenderData buffer ) { Merge( buffer, true ); }
public dfList<dfRenderData> RenderMultiple() { try { //@Profiler.BeginSample( "dfLabel.RenderMultiple()" ); if( Atlas == null || Font == null || !isVisible ) return null; // Initialize render buffers if needed if( renderData == null ) { renderData = dfRenderData.Obtain(); textRenderData = dfRenderData.Obtain(); isControlInvalidated = true; } // If control is not dirty, update the transforms on the // render buffers (in case control moved) and return // pre-rendered data if( !isControlInvalidated ) { //@Profiler.BeginSample( "Re-using existing render buffers" ); for( int i = 0; i < buffers.Count; i++ ) { buffers[ i ].Transform = transform.localToWorldMatrix; } //@Profiler.EndSample(); return buffers; } // Clear the render buffers resetRenderBuffers(); // Render the background sprite, if there is one renderBackground(); if( string.IsNullOrEmpty( this.Text ) ) { if( this.AutoSize || this.AutoHeight ) Height = Mathf.CeilToInt( Font.LineHeight * TextScale ); return buffers; } var sizeIsUninitialized = ( size.sqrMagnitude <= float.Epsilon ); using( var textRenderer = obtainRenderer() ) { textRenderer.Render( text, textRenderData ); if( AutoSize || sizeIsUninitialized ) { Size = ( textRenderer.RenderedSize + new Vector2( padding.horizontal, padding.vertical ) ).CeilToInt(); } else if( AutoHeight ) { Size = new Vector2( size.x, textRenderer.RenderedSize.y + padding.vertical ).CeilToInt(); } } // Make sure that the collider size always matches the control updateCollider(); return buffers; } finally { this.isControlInvalidated = false; //@Profiler.EndSample(); } }
/// <summary> /// Merges another <see cref="dfRenderData"/> instance with this instance /// </summary> /// <param name="buffer">The render data to be appended to this instance</param> /// <param name="transformVertices">If set to TRUE, the render data in /// <paramref name="buffer"/> will be transformed by its <see cref="Transform"/> /// before being merged with this instance. If set to FALSE, the data will be /// merged without tranforming.</param> public void Merge( dfRenderData buffer, bool transformVertices ) { // We need the current currentIndex of vertices before adding any more so that // we have a proper base index for our triangle indices var baseIndex = Vertices.Count; #region Merge vertices Vertices.AddRange( buffer.Vertices ); if( transformVertices ) { var rawVerts = Vertices.Items; var count = buffer.Vertices.Count; var transform = buffer.Transform; for( int i = baseIndex; i < baseIndex + count; i++ ) { rawVerts[ i ] = transform.MultiplyPoint( rawVerts[ i ] ); } } #endregion #region Merge triangles var triangleBaseIndex = Triangles.Count; Triangles.AddRange( buffer.Triangles ); var bufferTriangleCount = buffer.Triangles.Count; var rawTriangles = Triangles.Items; for( int i = triangleBaseIndex; i < triangleBaseIndex + bufferTriangleCount; i++ ) { rawTriangles[ i ] += baseIndex; } #endregion UV.AddRange( buffer.UV ); Colors.AddRange( buffer.Colors ); Normals.AddRange( buffer.Normals ); Tangents.AddRange( buffer.Tangents ); }
public dfList<dfRenderData> RenderMultiple() { if( Atlas == null || Font == null ) return null; if( !isVisible ) { return null; } // Initialize render buffers if needed if( renderData == null ) { renderData = dfRenderData.Obtain(); textRenderData = dfRenderData.Obtain(); isControlInvalidated = true; } var matrix = this.transform.localToWorldMatrix; // If control is not dirty, update the transforms on the // render buffers (in case control moved) and return // pre-rendered data if( !isControlInvalidated ) { for( int i = 0; i < buffers.Count; i++ ) { buffers[ i ].Transform = matrix; } return buffers; } #region Prepare render buffers buffers.Clear(); renderData.Clear(); renderData.Material = Atlas.Material; renderData.Transform = matrix; buffers.Add( renderData ); textRenderData.Clear(); textRenderData.Material = Atlas.Material; textRenderData.Transform = matrix; buffers.Add( textRenderData ); #endregion renderBackground(); renderText( textRenderData ); isControlInvalidated = false; // Make sure that the collider size always matches the control updateCollider(); return buffers; }
private static void rebuildUV( dfRenderData renderData, RenderOptions options ) { var atlas = options.atlas; var textureSize = new Vector2( atlas.Texture.width, atlas.Texture.height ); var spriteInfo = options.spriteInfo; float offsetTop = spriteInfo.border.top / textureSize.y; float offsetBottom = spriteInfo.border.bottom / textureSize.y; float offsetLeft = spriteInfo.border.left / textureSize.x; float offsetRight = spriteInfo.border.right / textureSize.x; var rect = spriteInfo.region; // Top left corner uv[ 0 ] = new Vector2( rect.x, rect.yMax ); uv[ 1 ] = new Vector2( rect.x + offsetLeft, rect.yMax ); uv[ 2 ] = new Vector2( rect.x + offsetLeft, rect.yMax - offsetTop ); uv[ 3 ] = new Vector2( rect.x, rect.yMax - offsetTop ); // Top right corner uv[ 4 ] = new Vector2( rect.xMax - offsetRight, rect.yMax ); uv[ 5 ] = new Vector2( rect.xMax, rect.yMax ); uv[ 6 ] = new Vector2( rect.xMax, rect.yMax - offsetTop ); uv[ 7 ] = new Vector2( rect.xMax - offsetRight, rect.yMax - offsetTop ); // Bottom left corner uv[ 8 ] = new Vector2( rect.x, rect.y + offsetBottom ); uv[ 9 ] = new Vector2( rect.x + offsetLeft, rect.y + offsetBottom ); uv[ 10 ] = new Vector2( rect.x + offsetLeft, rect.y ); uv[ 11 ] = new Vector2( rect.x, rect.y ); // Bottom right corner uv[ 12 ] = new Vector2( rect.xMax - offsetRight, rect.y + offsetBottom ); uv[ 13 ] = new Vector2( rect.xMax, rect.y + offsetBottom ); uv[ 14 ] = new Vector2( rect.xMax, rect.y ); uv[ 15 ] = new Vector2( rect.xMax - offsetRight, rect.y ); #region Flip UV if requested if( options.flip != dfSpriteFlip.None ) { for( int i = 0; i < uv.Length; i += 4 ) { Vector2 temp = Vector2.zero; if( options.flip.IsSet( dfSpriteFlip.FlipHorizontal ) ) { temp = uv[ i + 0 ]; uv[ i + 0 ] = uv[ i + 1 ]; uv[ i + 1 ] = temp; temp = uv[ i + 2 ]; uv[ i + 2 ] = uv[ i + 3 ]; uv[ i + 3 ] = temp; } if( options.flip.IsSet( dfSpriteFlip.FlipVertical ) ) { temp = uv[ i + 0 ]; uv[ i + 0 ] = uv[ i + 3 ]; uv[ i + 3 ] = temp; temp = uv[ i + 1 ]; uv[ i + 1 ] = uv[ i + 2 ]; uv[ i + 2 ] = temp; } } if( options.flip.IsSet( dfSpriteFlip.FlipHorizontal ) ) { var th = new Vector2[ uv.Length ]; Array.Copy( uv, th, uv.Length ); // Swap top-left and top-right corners Array.Copy( uv, 0, uv, 4, 4 ); Array.Copy( th, 4, uv, 0, 4 ); // Swap bottom-left and bottom-right corners Array.Copy( uv, 8, uv, 12, 4 ); Array.Copy( th, 12, uv, 8, 4 ); } if( options.flip.IsSet( dfSpriteFlip.FlipVertical ) ) { var tv = new Vector2[ uv.Length ]; Array.Copy( uv, tv, uv.Length ); // Swap top-left and bottom-left corners Array.Copy( uv, 0, uv, 8, 4 ); Array.Copy( tv, 8, uv, 0, 4 ); // Swap top-right and bottom-right corners Array.Copy( uv, 4, uv, 12, 4 ); Array.Copy( tv, 12, uv, 4, 4 ); } } #endregion for( int i = 0; i < uv.Length; i++ ) { renderData.UV.Add( uv[ i ] ); } }