public void UpdateTransformRecursive(ref WorldSpaceRect parentLocalToWorldSpaceRect, WorldSpaceMask currentMask, Entity entity, float2 scale) { if (DisabledFromEntity.Exists(entity)) { return; } var childTransform = RectTransformFromEntity[entity]; var childLocalToWorld = RectTransformUtils.CalculateWorldSpaceRect(parentLocalToWorldSpaceRect, scale, childTransform); WorldSpaceRectFromEntity[entity] = childLocalToWorld; ElementScaleFromEntity[entity] = new ElementScale() { Value = scale }; UpdateRectMask(entity, childLocalToWorld, ref currentMask); WorldSpaceMaskFromEntity[entity] = currentMask; if (RebuildFlagFromEntity.Exists(entity)) { RebuildFlagFromEntity[entity] = new RebuildElementMeshFlag() { Rebuild = true } } ; if (ChildrenFromEntity.Exists(entity)) { var children = ChildrenFromEntity[entity]; for (int i = 0; i < children.Length; i++) { UpdateTransformRecursive(ref childLocalToWorld, currentMask, children[i].Value, scale); } } }
public static void UpdateTransformRecursive(ref WorldSpaceRect parentLocalToWorldSpaceRect, WorldSpaceMask currentMask, Entity entity, float2 scale, ref HierarchyRebuildContext rebuildContext) { var childTransform = rebuildContext.RectTransformFromEntity[entity]; var childLocalToWorld = CalculateWorldSpaceRect(parentLocalToWorldSpaceRect, scale, childTransform); rebuildContext.WorldSpaceRectFromEntity[entity] = childLocalToWorld; rebuildContext.ElementScaleFromEntity[entity] = new ElementScale() { Value = scale }; UpdateRectMask(entity, childLocalToWorld, ref currentMask, ref rebuildContext); rebuildContext.WorldSpaceMaskFromEntity[entity] = currentMask; if (rebuildContext.RebuildFlagFromEntity.Exists(entity)) { rebuildContext.RebuildFlagFromEntity[entity] = new RebuildElementMeshFlag() { Rebuild = true } } ; if (rebuildContext.ChildrenFromEntity.Exists(entity)) { var children = rebuildContext.ChildrenFromEntity[entity]; for (int i = 0; i < children.Length; i++) { UpdateTransformRecursive(ref childLocalToWorld, currentMask, children[i].Value, scale, ref rebuildContext); } } }
public void Execute(ArchetypeChunk chunk, int index, int entityOffset) { var chunkRectTransform = chunk.GetNativeArray(RectTransformType); var entities = chunk.GetNativeArray(EntityType); var chunkChildren = chunk.GetBufferAccessor(ChildType); var canvasSizeArray = chunk.GetNativeArray(CanvasSizeType); NativeArray <CanvasConstantPhysicalSizeScaler> physicalSizeArray = default; bool useConstantPhysicalSize = chunk.Has(ConstantPhysicalScaler); if (useConstantPhysicalSize) { physicalSizeArray = chunk.GetNativeArray(ConstantPhysicalScaler); } //HierarchyRebuildContext rebuildContext = new HierarchyRebuildContext() //{ // ChildrenFromEntity = RebuildContext.ChildrenFromEntity, // ElementScaleFromEntity = RebuildContext.ElementScaleFromEntity, // RebuildFlagFromEntity = RebuildFlagFromEntity, // RectMaskFromEntity = RectMaskFromEntity, // RectTransformFromEntity = RectTransformFromEntity, // WorldSpaceMaskFromEntity = WorldSpaceMaskFromEntity, // WorldSpaceRectFromEntity = WorldSpaceRectFromEntity //}; for (int i = 0; i < chunk.Count; i++) { float2 scale = new float2(1.0f, 1.0f); if (useConstantPhysicalSize) { scale = Dpi * physicalSizeArray[i].Factor; } var canvasRect = new WorldSpaceRect() { Min = float2.zero, //chunkRectTransform[i].Position, Max = canvasSizeArray[i].Value //(chunkRectTransform[i].Position + canvasSizeArray[i].Value) }; RebuildContext.WorldSpaceRectFromEntity[entities[i]] = canvasRect; var children = chunkChildren[i]; var parentLocalToWorld = canvasRect; WorldSpaceMask canvasMask = new WorldSpaceMask() { Min = canvasRect.Min, Max = canvasRect.Max }; for (int j = 0; j < children.Length; j++) { var childTransform = RebuildContext.RectTransformFromEntity[children[j].Value]; RectTransformUtils.UpdateTransformRecursive(ref parentLocalToWorld, canvasMask, children[j].Value, scale, ref RebuildContext); //UpdateTransformRecursive(ref parentLocalToWorld, canvasMask, children[j].Value, scale); } } }
public static RectTransform CalculateInverseTransformWithAnchors(WorldSpaceRect desiredRect, WorldSpaceRect parent, RectTransform currentTransform, float2 scale) { var anchorDiff = currentTransform.AnchorMax - currentTransform.AnchorMin; var parentSizeRelation = parent.Size * anchorDiff; currentTransform.SizeDelta = (desiredRect.Size - parentSizeRelation) / scale; var start = desiredRect.Min + desiredRect.Size * currentTransform.Pivot; currentTransform.Position = (start - math.lerp(parent.Min, parent.Max, math.lerp(currentTransform.AnchorMin, currentTransform.AnchorMax, currentTransform.Pivot))) / scale; return(currentTransform); }
public static float GetAlignedLinePosition(ref WorldSpaceRect rect, float lineWidth, HorizontalAlignmentOptions horizontalAlignment) { if ((horizontalAlignment & HorizontalAlignmentOptions.Right) == HorizontalAlignmentOptions.Right) { return(rect.Min.x + rect.Width - lineWidth); } if ((horizontalAlignment & HorizontalAlignmentOptions.Center) == HorizontalAlignmentOptions.Center) { return(rect.Min.x + rect.Width * 0.5f - lineWidth * 0.5f); } return(rect.Min.x); }
private void UpdateRectMask(Entity entity, WorldSpaceRect elementRect, ref WorldSpaceMask mask) { if (RectMaskFromEntity.Exists(entity)) { float2 newMin = math.max(mask.Min, elementRect.Min); float2 newMax = math.min(mask.Max, elementRect.Max); mask = new WorldSpaceMask { Min = newMin, Max = newMax }; } }
private static void UpdateRectMask(Entity entity, WorldSpaceRect elementRect, ref WorldSpaceMask mask, ref HierarchyRebuildContext rebuildContext) { if (rebuildContext.RectMaskFromEntity.Exists(entity)) { float2 newMin = math.max(mask.Min, elementRect.Min); float2 newMax = math.min(mask.Max, elementRect.Max); mask = new WorldSpaceMask { Min = newMin, Max = newMax }; } }
public void Execute(ArchetypeChunk chunk, int index, int entityOffset) { var chunkRectTransform = chunk.GetNativeArray(RectTransformType); var entities = chunk.GetNativeArray(EntityType); var chunkChildren = chunk.GetBufferAccessor(ChildType); NativeArray <CanvasConstantPhysicalSizeScaler> physicalSizeArray = default; bool useConstantPhysicalSize = chunk.Has(ConstantPhysicalScaler); if (useConstantPhysicalSize) { physicalSizeArray = chunk.GetNativeArray(ConstantPhysicalScaler); } for (int i = 0; i < chunk.Count; i++) { float2 scale = new float2(1.0f, 1.0f); if (useConstantPhysicalSize) { scale = Dpi * physicalSizeArray[i].Factor; } var canvasRect = new WorldSpaceRect() { Min = chunkRectTransform[i].Position, Max = (chunkRectTransform[i].Position + new float2(ScreenWidth, ScreenHeight)) }; LocalToWorldFromEntity[entities[i]] = canvasRect; var children = chunkChildren[i]; var parentLocalToWorld = canvasRect; WorldSpaceMask canvasMask = new WorldSpaceMask() { Min = canvasRect.Min, Max = canvasRect.Max }; for (int j = 0; j < children.Length; j++) { var childTransform = RectTransformFromEntity[children[j].Value]; UpdateTransform(ref parentLocalToWorld, canvasMask, children[j].Value, scale, index); } } }
public static float2 GetAlignedStartPosition(ref WorldSpaceRect rect, ref TextRenderer settings, ref TextFontAsset font, float textBlockHeight, float2 scale) { float startY = 0.0f; VerticalAlignmentOptions vertical = (VerticalAlignmentOptions)settings.Alignment; HorizontalAlignmentOptions horizontal = (HorizontalAlignmentOptions)settings.Alignment; if ((vertical & VerticalAlignmentOptions.Bottom) == VerticalAlignmentOptions.Bottom) { startY = rect.Min.y - font.DescentLine * scale.y + textBlockHeight - font.LineHeight * scale.y; } else if ((vertical & VerticalAlignmentOptions.Middle) == VerticalAlignmentOptions.Middle) { startY = (rect.Min.y + rect.Max.y) * 0.5f - (font.AscentLine) * scale.y + textBlockHeight * 0.5f; } else if ((vertical & VerticalAlignmentOptions.Top) == VerticalAlignmentOptions.Top) { startY = rect.Max.y - (font.AscentLine) * scale.y; } return(new float2(rect.Min.x, startY)); }
private void UpdateTransform(ref WorldSpaceRect parentLocalToWorldSpaceRect, WorldSpaceMask currentMask, Entity entity, float2 scale, int jobIdx) { var childTransform = RectTransformFromEntity[entity]; float2 start = math.lerp(parentLocalToWorldSpaceRect.Min, parentLocalToWorldSpaceRect.Max, math.lerp(childTransform.AnchorMin, childTransform.AnchorMax, childTransform.Pivot)) + childTransform.Position * scale; float2 anchorDiff = childTransform.AnchorMax - childTransform.AnchorMin; float2 size = (parentLocalToWorldSpaceRect.Max - parentLocalToWorldSpaceRect.Min) * anchorDiff + childTransform.SizeDelta * scale; float2 min = start - size * childTransform.Pivot; float2 max = start + size * (new float2(1.0f, 1.0f) - childTransform.Pivot); var childLocalToWorld = new WorldSpaceRect() { Min = min, Max = max, }; LocalToWorldFromEntity[entity] = childLocalToWorld; ElementScaleType[entity] = new ElementScale() { Value = scale }; UpdateRectMask(entity, childLocalToWorld, ref currentMask); WorldSpaceMaskFromEntity[entity] = currentMask; if (RebuildFlagType.Exists(entity)) { RebuildFlagType[entity] = new RebuildElementMeshFlag() { Rebuild = true } } ; if (ChildFromEntity.Exists(entity)) { var children = ChildFromEntity[entity]; for (int i = 0; i < children.Length; i++) { UpdateTransform(ref childLocalToWorld, currentMask, children[i].Value, scale, jobIdx); } } }
public static WorldSpaceRect CalculateWorldSpaceRect(WorldSpaceRect parentRect, float2 scale, RectTransform childTransform) { var start = math.lerp(parentRect.Min, parentRect.Max, math.lerp(childTransform.AnchorMin, childTransform.AnchorMax, childTransform.Pivot)) + childTransform.Position * scale; var anchorDiff = childTransform.AnchorMax - childTransform.AnchorMin; var size = (parentRect.Max - parentRect.Min) * anchorDiff + childTransform.SizeDelta * scale; var min = start - size * childTransform.Pivot; var max = start + size * (new float2(1.0f, 1.0f) - childTransform.Pivot); var childRect = new WorldSpaceRect() { Min = min, Max = max, }; return(childRect); }
public static bool ContainsPoint(this WorldSpaceRect rect, float2 point) { return((point.x >= rect.Min.x && point.x <= rect.Max.x) && (point.y >= rect.Min.y && point.y <= rect.Max.y)); }
private void PopulateMesh(WorldSpaceRect rect, ElementScale scale, WorldSpaceMask mask, TextRenderer settings, float4 color, ref DynamicBuffer <TextData> textBuffer, ref DynamicBuffer <ControlVertexData> vertices, ref DynamicBuffer <ControlVertexIndex> triangles) { _VerticalAlignmentOptions verticalAlignment = (_VerticalAlignmentOptions)settings.Alignment; _HorizontalAlignmentOptions horizontalAlignment = (_HorizontalAlignmentOptions)settings.Alignment; var font = FontAssetFromEntity[settings.Font]; var glyphData = FontGlyphDataFromEntity[settings.Font]; float2 canvasScale = settings.Size * scale.Value / font.PointSize; float stylePadding = 1.25f + (settings.Bold ? font.BoldStyle / 4.0f : font.NormalStyle / 4.0f); float styleSpaceMultiplier = 1.0f + (settings.Bold ? font.BoldSpace * 0.01f : font.NormalSpace * 0.01f); NativeList <TextUtils.TextLineInfo> lines = new NativeList <TextUtils.TextLineInfo>(Allocator.Temp); TextUtils.CalculateLines(ref rect, canvasScale, styleSpaceMultiplier, ref glyphData, ref textBuffer, lines); float textBlockHeight = lines.Length * font.LineHeight * canvasScale.y; float2 alignedStartPosition = TextUtils.GetAlignedStartPosition(ref rect, ref settings, ref font, textBlockHeight, canvasScale); float2 currentCharacter = alignedStartPosition; int lineIdx = 0; for (int i = 0; i < textBuffer.Length; i++) { if (lineIdx < lines.Length && i == lines[lineIdx].CharacterOffset) { currentCharacter = new float2(TextUtils.GetAlignedLinePosition(ref rect, lines[lineIdx].LineWidth, horizontalAlignment), alignedStartPosition.y - font.LineHeight * canvasScale.y * lineIdx); lineIdx++; } var character = textBuffer[i].Value; if (character == (ushort)'\n') { // It's handled in GetLinesOffsets continue; } if (TextUtils.GetGlyph(character, ref glyphData, out FontGlyphData ch)) { int startIndex = vertices.Length; float2 uv2 = new float2(ch.Scale, ch.Scale) * math.select(canvasScale, -canvasScale, settings.Bold); float2 vMin = currentCharacter + new float2(ch.Metrics.horizontalBearingX - stylePadding, ch.Metrics.horizontalBearingY - ch.Metrics.height - stylePadding) * canvasScale; float2 vMax = vMin + new float2(ch.Metrics.width + stylePadding * 2.0f, ch.Metrics.height + stylePadding * 2.0f) * canvasScale; float4 uv = new float4(ch.Rect.x - stylePadding, ch.Rect.y - stylePadding, (ch.Rect.x + ch.Rect.width + stylePadding), (ch.Rect.y + ch.Rect.height + stylePadding)) / new float4(font.AtlasSize, font.AtlasSize); RectMaskCut cut = SpriteUtility.GetRectangleMaskCut(vMin, vMax, uv.xy, uv.zw, ref mask); var cutSize = cut.Max + cut.Min; if (!(cutSize.x > vMax.x - vMin.x) && !(cutSize.y > vMax.y - vMin.y)) { float4 vertexPos = new float4(vMin + cut.Min, vMax - cut.Max); uv.xy = uv.xy + cut.UvMin; uv.zw = uv.zw - cut.UvMax; triangles.Add(new ControlVertexIndex() { Value = startIndex + 2 }); triangles.Add(new ControlVertexIndex() { Value = startIndex + 1 }); triangles.Add(new ControlVertexIndex() { Value = startIndex }); triangles.Add(new ControlVertexIndex() { Value = startIndex + 3 }); triangles.Add(new ControlVertexIndex() { Value = startIndex + 2 }); triangles.Add(new ControlVertexIndex() { Value = startIndex }); vertices.Add(new ControlVertexData() { Position = new float3(vertexPos.xy, 0.0f), Normal = new float3(0.0f, 0.0f, -1.0f), TexCoord0 = uv.xy, TexCoord1 = uv2, Color = color }); vertices.Add(new ControlVertexData() { Position = new float3(vertexPos.zy, 0.0f), Normal = new float3(0.0f, 0.0f, -1.0f), TexCoord0 = uv.zy, TexCoord1 = uv2, Color = color }); vertices.Add(new ControlVertexData() { Position = new float3(vertexPos.zw, 0.0f), Normal = new float3(0.0f, 0.0f, -1.0f), TexCoord0 = uv.zw, TexCoord1 = uv2, Color = color }); vertices.Add(new ControlVertexData() { Position = new float3(vertexPos.xw, 0.0f), Normal = new float3(0.0f, 0.0f, -1.0f), TexCoord0 = uv.xw, TexCoord1 = uv2, Color = color }); } currentCharacter += (new float2(ch.Metrics.horizontalAdvance * styleSpaceMultiplier, 0.0f) * canvasScale); } } }
public static void CalculateLines(ref WorldSpaceRect rect, float2 canvasScale, float styleSpaceMultiplier, ref DynamicBuffer <FontGlyphData> glyphData, ref DynamicBuffer <TextData> textBuffer, NativeList <TextLineInfo> ret) { float maxLineWidth = rect.Max.x - rect.Min.x; CurrentLineData currentLine = default; for (int i = 0; i < textBuffer.Length; i++) { var character = textBuffer[i].Value; if (character == '\n') { ret.Add(new TextLineInfo() { CharacterOffset = currentLine.CharacterOffset, LineWidth = currentLine.LineWidth, }); currentLine.CharacterOffset = i + 1; currentLine.LineWidth = 0.0f; currentLine.LineWordIndex = 0; currentLine.WordCharacterCount = 0; currentLine.WordWidth = 0.0f; continue; } if (character == ' ') { currentLine.LineWordIndex++; currentLine.WordCharacterCount = -1; currentLine.WordWidth = 0.0f; } if (GetGlyph(character, ref glyphData, out var ch)) { if (((ch.Metrics.width * styleSpaceMultiplier * canvasScale.x) < rect.Width)) { currentLine.WordCharacterCount++; float characterWidth = ch.Metrics.horizontalAdvance * styleSpaceMultiplier * canvasScale.x; currentLine.LineWidth += characterWidth; currentLine.WordWidth += characterWidth; if (currentLine.LineWidth > maxLineWidth) { if (currentLine.LineWordIndex != 0) { ret.Add(new TextLineInfo() { CharacterOffset = currentLine.CharacterOffset, LineWidth = currentLine.LineWidth - currentLine.WordWidth, }); currentLine.CharacterOffset = i - currentLine.WordCharacterCount + 1; currentLine.LineWidth = 0.0f; currentLine.WordWidth = 0.0f; i = i - currentLine.WordCharacterCount + 1; currentLine.LineWordIndex = 0; currentLine.WordCharacterCount = 0; } else { ret.Add(new TextLineInfo() { CharacterOffset = currentLine.CharacterOffset, LineWidth = currentLine.LineWidth, }); currentLine.CharacterOffset = i; currentLine.LineWidth = 0.0f; currentLine.WordWidth = 0.0f; currentLine.LineWordIndex = 0; currentLine.WordCharacterCount = 0; } } continue; } ret.Add(new TextLineInfo() { CharacterOffset = currentLine.CharacterOffset, LineWidth = currentLine.LineWidth, }); currentLine.CharacterOffset = i; currentLine.LineWidth = 0.0f; currentLine.WordWidth = 0.0f; currentLine.LineWordIndex = 0; currentLine.WordCharacterCount = 0; } } ret.Add(new TextLineInfo() { CharacterOffset = currentLine.CharacterOffset, LineWidth = currentLine.LineWidth }); }
public static float2 WorldSpaceToLocalPoint(this WorldSpaceRect rect, float2 worldSpacePoint) { return(worldSpacePoint - rect.Min); }
public static float2 WorldSpaceToNormalizedLocalPoint(this WorldSpaceRect rect, float2 worldSpacePoint) { return((worldSpacePoint - rect.Min) / rect.Size); }
public static unsafe void PopulateSpriteVertices(ref WorldSpaceMask rectMask, ref DynamicBuffer <ControlVertexData> vertices, ref DynamicBuffer <ControlVertexIndex> triangles, ref WorldSpaceRect rectData, ref SpriteVertexData spriteVertexData, float4 color) { float pixelsPerUnit = spriteVertexData.PixelsPerUnit / 100.0f; Rect rect = new Rect(rectData.Min, rectData.Max - rectData.Min); float4 adjustedBorders = GetAdjustedBorders(spriteVertexData.Border / pixelsPerUnit, rect); var padding = spriteVertexData.Padding / pixelsPerUnit; float2 *vertScratch = stackalloc float2[4]; float2 *uvScratch = stackalloc float2[4]; vertScratch[0] = new float2(padding.x, padding.y); vertScratch[3] = new float2(rect.width - padding.z, rect.height - padding.w); vertScratch[1].x = adjustedBorders.x; vertScratch[1].y = adjustedBorders.y; vertScratch[2].x = rect.width - adjustedBorders.z; vertScratch[2].y = rect.height - adjustedBorders.w; for (int i = 0; i < 4; ++i) { vertScratch[i].x += rect.x; vertScratch[i].y += rect.y; } uvScratch[0] = new Vector2(spriteVertexData.Outer.x, spriteVertexData.Outer.y); uvScratch[1] = new Vector2(spriteVertexData.Inner.x, spriteVertexData.Inner.y); uvScratch[2] = new Vector2(spriteVertexData.Inner.z, spriteVertexData.Inner.w); uvScratch[3] = new Vector2(spriteVertexData.Outer.z, spriteVertexData.Outer.w); // rect mask support var cut = GetRectangleMaskCut(vertScratch[0], vertScratch[3], ref rectMask); vertScratch[0] = vertScratch[0] + cut.Min - clamp(cut.Max - float2(rect.size), 0.0f, float.PositiveInfinity); vertScratch[1] = vertScratch[1] + math.clamp(cut.Min - adjustedBorders.xy, 0.0f, float.PositiveInfinity) - clamp(cut.Max - (float2(rect.size) - adjustedBorders.xy), 0.0f, float.PositiveInfinity); vertScratch[2] = vertScratch[2] + math.clamp(cut.Min - (float2(rect.size) - adjustedBorders.zw), 0.0f, float.PositiveInfinity) - math.clamp(cut.Max - adjustedBorders.wz, 0.0f, float.PositiveInfinity); vertScratch[3] = vertScratch[3] + clamp(cut.Min - float2(rect.size), 0.0f, float.PositiveInfinity) - cut.Max; int vertexOffset = vertices.Length; for (int x = 0; x < 4; ++x) { for (int y = 0; y < 4; ++y) { vertices.Add(new ControlVertexData() { Position = new float3(vertScratch[x].x, vertScratch[y].y, 0.0f), TexCoord0 = new float2(uvScratch[x].x, uvScratch[y].y), Color = color }); } } for (int x = 0; x < 3; ++x) { int x2 = x + 1; for (int y = 0; y < 3; ++y) { int y2 = y + 1; // Ignore empty if (vertScratch[x2].x - vertScratch[x].x <= 0.0f) { continue; } if (vertScratch[y2].y - vertScratch[y].y <= 0.0f) { continue; } triangles.Add(vertexOffset + x * 4 + y); triangles.Add(vertexOffset + x * 4 + y2); triangles.Add(vertexOffset + x2 * 4 + y); triangles.Add(vertexOffset + x2 * 4 + y2); triangles.Add(vertexOffset + x2 * 4 + y); triangles.Add(vertexOffset + x * 4 + y2); } } // for (int x = 0; x < 3; ++x) // { // int x2 = x + 1; // // for (int y = 0; y < 3; ++y) // { // int y2 = y + 1; // // // AddQuad(ref rectMask, ref vertices, ref triangles, // new float2(vertScratch[x].x, vertScratch[y].y), // new float2(vertScratch[x2].x, vertScratch[y2].y), // color, // new float2(uvScratch[x].x, uvScratch[y].y), // new float2(uvScratch[x2].x, uvScratch[y2].y)); // } // } }