public void DrawTexture(TextureStylePainterParameters painterParams) { Rect screenRect = painterParams.rect; Rect sourceRect = painterParams.uv != Rect.zero ? painterParams.uv : new Rect(0, 0, 1, 1); Texture texture = painterParams.texture; Color color = painterParams.color * UIElementsUtility.editorPlayModeTintColor; ScaleMode scaleMode = painterParams.scaleMode; int sliceLeft = painterParams.sliceLeft; int sliceTop = painterParams.sliceTop; int sliceRight = painterParams.sliceRight; int sliceBottom = painterParams.sliceBottom; bool usePremultiplyAlpha = painterParams.usePremultiplyAlpha; Rect textureRect = screenRect; // Comparing aspects ratio is error-prone because the <c>screenRect</c> may end up being scaled by the // transform and the corners will end up being pixel aligned, possibly resulting in blurriness. float srcAspect = (texture.width * sourceRect.width) / (texture.height * sourceRect.height); float destAspect = screenRect.width / screenRect.height; switch (scaleMode) { case ScaleMode.StretchToFill: break; case ScaleMode.ScaleAndCrop: if (destAspect > srcAspect) { float stretch = sourceRect.height * (srcAspect / destAspect); float crop = (sourceRect.height - stretch) * 0.5f; sourceRect = new Rect(sourceRect.x, sourceRect.y + crop, sourceRect.width, stretch); } else { float stretch = sourceRect.width * (destAspect / srcAspect); float crop = (sourceRect.width - stretch) * 0.5f; sourceRect = new Rect(sourceRect.x + crop, sourceRect.y, stretch, sourceRect.height); } break; case ScaleMode.ScaleToFit: if (destAspect > srcAspect) { float stretch = srcAspect / destAspect; textureRect = new Rect(screenRect.xMin + screenRect.width * (1.0f - stretch) * .5f, screenRect.yMin, stretch * screenRect.width, screenRect.height); } else { float stretch = destAspect / srcAspect; textureRect = new Rect(screenRect.xMin, screenRect.yMin + screenRect.height * (1.0f - stretch) * .5f, screenRect.width, stretch * screenRect.height); } break; } var borderWidths = painterParams.border.GetWidths(); var borderRadiuses = painterParams.border.GetRadiuses(); DrawTexture(textureRect, texture, sourceRect, color * m_OpacityColor, borderWidths, borderRadiuses, sliceLeft, sliceTop, sliceRight, sliceBottom, usePremultiplyAlpha); }
internal static void DrawBackground(this IStylePainter painter, VisualElement ve) { IStyle style = ve.style; if (style.backgroundColor != Color.clear) { RectStylePainterParameters defaultRectParameters = painter.GetDefaultRectParameters(ve); defaultRectParameters.border.SetWidth(0f); painter.DrawRect(defaultRectParameters); } if (style.backgroundImage.value != null) { TextureStylePainterParameters defaultTextureParameters = painter.GetDefaultTextureParameters(ve); defaultTextureParameters.border.SetWidth(0f); painter.DrawTexture(defaultTextureParameters); } }
internal override void DoRepaint(IStylePainter painter) { if (this.image == null) { Debug.LogWarning("null texture passed to GUI.DrawTexture"); } else { TextureStylePainterParameters painterParams = new TextureStylePainterParameters { layout = base.contentRect, texture = this.image, color = GUI.color, scaleMode = this.scaleMode }; painter.DrawTexture(painterParams); } }
public void DrawBackground() { IStyle style = currentElement.style; if (style.backgroundColor != Color.clear) { var painterParams = RectStylePainterParameters.GetDefault(currentElement); painterParams.border.SetWidth(0.0f); DrawRect(painterParams); } if (style.backgroundImage.value != null) { var painterParams = TextureStylePainterParameters.GetDefault(currentElement); painterParams.border.SetWidth(0.0f); DrawTexture(painterParams); } }
public static TextureStylePainterParameters GetDefault(VisualElement ve) { IStyle style = ve.style; var painterParams = new TextureStylePainterParameters { rect = GUIUtility.AlignRectToDevice(ve.rect), uv = new Rect(0, 0, 1, 1), color = (Color)Color.white, texture = style.backgroundImage, scaleMode = style.backgroundScaleMode, sliceLeft = style.sliceLeft, sliceTop = style.sliceTop, sliceRight = style.sliceRight, sliceBottom = style.sliceBottom }; BorderParameters.SetFromStyle(ref painterParams.border, style); return(painterParams); }
internal static TextureStylePainterParameters GetDefaultTextureParameters(this IStylePainter painter, VisualElement ve) { IStyle style = ve.style; TextureStylePainterParameters result = new TextureStylePainterParameters { rect = ve.rect, uv = new Rect(0f, 0f, 1f, 1f), color = Color.white, texture = style.backgroundImage, scaleMode = style.backgroundSize, sliceLeft = style.sliceLeft, sliceTop = style.sliceTop, sliceRight = style.sliceRight, sliceBottom = style.sliceBottom }; painter.SetBorderFromStyle(ref result.border, style); return(result); }
protected override void DoRepaint(IStylePainter painter) { Texture current = image.GetSpecifiedValueOrDefault(null); if (current == null) { return; } var painterParams = new TextureStylePainterParameters { rect = contentRect, uv = uv, texture = current, color = GUI.color, scaleMode = scaleMode }; var stylePainter = (IStylePainterInternal)painter; stylePainter.DrawTexture(painterParams); }
public static TextureStylePainterParameters GetDefault(VisualElement ve) { IStyle style = ve.style; var painterParams = new TextureStylePainterParameters { rect = GUIUtility.AlignRectToDevice(ve.rect), uv = new Rect(0, 0, 1, 1), // When the background color is not clear, we have to embed it into the texture... // whereas if the color is clear, the white color is used... color = (style.backgroundColor != Color.clear) ? (Color)style.backgroundColor : (Color)Color.white, texture = style.backgroundImage, scaleMode = style.backgroundScaleMode, sliceLeft = style.sliceLeft, sliceTop = style.sliceTop, sliceRight = style.sliceRight, sliceBottom = style.sliceBottom }; BorderParameters.SetFromStyle(ref painterParams.border, style); return(painterParams); }
internal override void DoRepaint(IStylePainter painter) { base.DoRepaint(painter); Texture specifiedValueOrDefault = this.image.GetSpecifiedValueOrDefault(null); if (specifiedValueOrDefault == null) { Debug.LogWarning("null texture passed to GUI.DrawTexture"); } else { TextureStylePainterParameters painterParams = new TextureStylePainterParameters { rect = base.contentRect, uv = this.uv, texture = specifiedValueOrDefault, color = GUI.color, scaleMode = this.scaleMode }; painter.DrawTexture(painterParams); } }
internal override void DoRepaint(IStylePainter painter) { //we paint the bg color, borders, etc base.DoRepaint(painter); Texture current = image.GetSpecifiedValueOrDefault(null); if (current == null) { Debug.LogWarning("null texture passed to GUI.DrawTexture"); return; } var painterParams = new TextureStylePainterParameters { rect = contentRect, uv = uv, texture = current, color = GUI.color, scaleMode = scaleMode }; painter.DrawTexture(painterParams); }
private void PaintSubTree(Event e, VisualElement root, Matrix4x4 offset, VisualElement.ClippingOptions clippingOption, Rect currentGlobalClip) { if (root == null || root.panel != this) { return; } if (root.visible == false || root.style.opacity.GetSpecifiedValueOrDefault(1.0f) < Mathf.Epsilon) { return; } // update clip if (root.clippingOptions != VisualElement.ClippingOptions.NoClipping) { var worldBound = ComputeAAAlignedBound(root.rect, offset * root.worldTransform); // are we and our children clipped? if (!worldBound.Overlaps(currentGlobalClip)) { return; } float x1 = Mathf.Max(worldBound.x, currentGlobalClip.x); float x2 = Mathf.Min(worldBound.xMax, currentGlobalClip.xMax); float y1 = Mathf.Max(worldBound.y, currentGlobalClip.y); float y2 = Mathf.Min(worldBound.yMax, currentGlobalClip.yMax); // new global clip and hierarchical clip space option. currentGlobalClip = new Rect(x1, y1, x2 - x1, y2 - y1); clippingOption = root.clippingOptions; } else { //since our children are not clipped, there is no early out. } // Check for the rotated space - clipping issue. if (!whinedOnceAboutRotatedClipSpaceThisFrame && clippingOption == VisualElement.ClippingOptions.ClipContents && DoesMatrixHaveUnsupportedRotation(root.worldTransform)) { Debug.LogError("Panel.PaintSubTree - Rotated clip-spaces are only supported by the VisualElement.ClippingOptions.ClipAndCacheContents mode. First offending Panel:'" + root.name + "'."); whinedOnceAboutRotatedClipSpaceThisFrame = true; } if (ShouldUsePixelCache(root)) { // now actually paint the texture to previous group IStylePainter painter = stylePainter; // validate cache texture size first var worldBound = root.worldBound; Rect alignedRect; int textureWidth, textureHeight; painter.currentWorldClip = currentGlobalClip; painter.currentTransform = offset * root.worldTransform; using (new GUIClip.ParentClipScope(painter.currentTransform, currentGlobalClip)) { alignedRect = GUIUtility.AlignRectToDevice(root.rect, out textureWidth, out textureHeight); } // Prevent the texture size from going empty, which may occur if the element has a sub-pixel size textureWidth = Math.Max(textureWidth, 1); textureHeight = Math.Max(textureHeight, 1); var cache = root.renderData.pixelCache; if (cache != null && (cache.width != textureWidth || cache.height != textureHeight) && (!keepPixelCacheOnWorldBoundChange || root.IsDirty(ChangeType.Repaint))) { Object.DestroyImmediate(cache); cache = root.renderData.pixelCache = null; } // if the child node world transforms are not up to date due to changes below the pixel cache this is fine. if (root.IsDirty(ChangeType.Repaint) || root.renderData.pixelCache == null || !root.renderData.pixelCache.IsCreated()) { // Recreate as needed if (cache == null) { root.renderData.pixelCache = cache = new RenderTexture( textureWidth, textureHeight, 32, // depth RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); } bool hasRoundedBorderRects = (root.style.borderTopLeftRadius > 0 || root.style.borderTopRightRadius > 0 || root.style.borderBottomLeftRadius > 0 || root.style.borderBottomRightRadius > 0); RenderTexture temporaryTexture = null; var old = RenderTexture.active; try { // We first render to a temp texture, then blit the result into the result pixelCache again to mask the rounder corners if (hasRoundedBorderRects) { temporaryTexture = cache = RenderTexture.GetTemporary(textureWidth, textureHeight, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); } // render the texture again to clip the round rect borders RenderTexture.active = cache; GL.Clear(true, true, new Color(0, 0, 0, 0)); // Calculate the offset required to translate the origin of the rect to the upper left corner // of the pixel cache. We need to round because the rect will be rounded when rendered. Rect worldAlignedRect = root.LocalToWorld(alignedRect); var childrenOffset = Matrix4x4.Translate(new Vector3(-worldAlignedRect.x, -worldAlignedRect.y, 0)); Matrix4x4 offsetWorldTransform = childrenOffset * root.worldTransform; // reset clipping var textureClip = new Rect(0, 0, worldAlignedRect.width, worldAlignedRect.height); painter.currentTransform = offsetWorldTransform; // Metal ignores the sRGBWrite flag and will always do linear to gamma conversions // when writing to an sRGB buffer. In this situation, we disable the manual sRGB // conversion since it will be done automatically when writing to the framebuffer. bool manualTex2SRGBEnabled = (SystemInfo.graphicsDeviceType != GraphicsDeviceType.Metal); using (new GUIUtility.ManualTex2SRGBScope(manualTex2SRGBEnabled)) using (new GUIClip.ParentClipScope(painter.currentTransform, textureClip)) { // Paint self painter.currentWorldClip = textureClip; stylePainter.opacity = root.style.opacity.GetSpecifiedValueOrDefault(1.0f); root.DoRepaint(painter); stylePainter.opacity = 1.0f; root.ClearDirty(ChangeType.Repaint); PaintSubTreeChildren(e, root, childrenOffset, clippingOption, textureClip); } if (hasRoundedBorderRects) { RenderTexture.active = root.renderData.pixelCache; // Fix up transform for subtree to match texture upper left. painter.currentTransform = Matrix4x4.identity; using (new GUIUtility.ManualTex2SRGBScope(manualTex2SRGBEnabled)) using (new GUIClip.ParentClipScope(painter.currentTransform, textureClip)) { GL.Clear(true, true, new Color(0, 0, 0, 0)); var textureParams = painter.GetDefaultTextureParameters(root); textureParams.texture = cache; textureParams.scaleMode = ScaleMode.StretchToFill; textureParams.rect = textureClip; textureParams.border.SetWidth(0.0f); // The rect of the temporary texture implicitly carries the scale factor of the // transform. Since we are blitting with an identity matrix, we need to scale the // radius manually. // We assume uniform positive scaling without rotations. Vector4 toScale = new Vector4(1, 0, 0, 0); Vector4 scaled = offsetWorldTransform * toScale; float radiusScale = scaled.x; textureParams.border.SetRadius( textureParams.border.topLeftRadius * radiusScale, textureParams.border.topRightRadius * radiusScale, textureParams.border.bottomRightRadius * radiusScale, textureParams.border.bottomLeftRadius * radiusScale); // No border is drawn but the rounded corners are clipped properly. // Use premultiply alpha to avoid blending again. textureParams.usePremultiplyAlpha = true; painter.DrawTexture(textureParams); } // Redraw the border (border was already drawn in first root.DoRepaint call). painter.currentTransform = offsetWorldTransform; using (new GUIUtility.ManualTex2SRGBScope(manualTex2SRGBEnabled)) using (new GUIClip.ParentClipScope(painter.currentTransform, textureClip)) { painter.DrawBorder(root); } } } finally { cache = null; if (temporaryTexture != null) { RenderTexture.ReleaseTemporary(temporaryTexture); } RenderTexture.active = old; } } // now actually paint the texture to previous group painter.currentWorldClip = currentGlobalClip; painter.currentTransform = offset * root.worldTransform; using (new GUIClip.ParentClipScope(painter.currentTransform, currentGlobalClip)) { var painterParams = new TextureStylePainterParameters { rect = GUIUtility.AlignRectToDevice(root.rect), uv = new Rect(0, 0, 1, 1), texture = root.renderData.pixelCache, color = Color.white, scaleMode = ScaleMode.StretchToFill, usePremultiplyAlpha = true }; painter.DrawTexture(painterParams); } } else { stylePainter.currentTransform = offset * root.worldTransform; using (new GUIClip.ParentClipScope(stylePainter.currentTransform, currentGlobalClip)) { stylePainter.currentWorldClip = currentGlobalClip; stylePainter.mousePosition = root.worldTransform.inverse.MultiplyPoint3x4(e.mousePosition); stylePainter.opacity = root.style.opacity.GetSpecifiedValueOrDefault(1.0f); root.DoRepaint(stylePainter); stylePainter.opacity = 1.0f; root.ClearDirty(ChangeType.Repaint); PaintSubTreeChildren(e, root, offset, clippingOption, currentGlobalClip); } } }
private void PaintSubTree(Event e, VisualElement root, Matrix4x4 offset, Rect currentGlobalClip) { if (root != null && root.panel == this) { if ((root.pseudoStates & PseudoStates.Invisible) != PseudoStates.Invisible && root.style.opacity.GetSpecifiedValueOrDefault(1f) >= Mathf.Epsilon) { if (root.clippingOptions != VisualElement.ClippingOptions.NoClipping) { Rect rect = this.ComputeAAAlignedBound(root.rect, offset * root.worldTransform); if (!rect.Overlaps(currentGlobalClip)) { return; } float num = Mathf.Max(rect.x, currentGlobalClip.x); float num2 = Mathf.Min(rect.x + rect.width, currentGlobalClip.x + currentGlobalClip.width); float num3 = Mathf.Max(rect.y, currentGlobalClip.y); float num4 = Mathf.Min(rect.y + rect.height, currentGlobalClip.y + currentGlobalClip.height); currentGlobalClip = new Rect(num, num3, num2 - num, num4 - num3); } if (this.ShouldUsePixelCache(root)) { IStylePainter stylePainter = this.stylePainter; Rect worldBound = root.worldBound; int num5 = Mathf.RoundToInt(worldBound.xMax) - Mathf.RoundToInt(worldBound.xMin); int num6 = Mathf.RoundToInt(worldBound.yMax) - Mathf.RoundToInt(worldBound.yMin); int num7 = Mathf.RoundToInt((float)num5 * GUIUtility.pixelsPerPoint); int num8 = Mathf.RoundToInt((float)num6 * GUIUtility.pixelsPerPoint); num7 = Math.Max(num7, 1); num8 = Math.Max(num8, 1); RenderTexture renderTexture = root.renderData.pixelCache; if (renderTexture != null && (renderTexture.width != num7 || renderTexture.height != num8) && (!this.keepPixelCacheOnWorldBoundChange || root.IsDirty(ChangeType.Repaint))) { UnityEngine.Object.DestroyImmediate(renderTexture); renderTexture = (root.renderData.pixelCache = null); } if (root.IsDirty(ChangeType.Repaint) || root.renderData.pixelCache == null || !root.renderData.pixelCache.IsCreated()) { if (renderTexture == null) { renderTexture = (root.renderData.pixelCache = new RenderTexture(num7, num8, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB)); } bool flag = root.style.borderTopLeftRadius > 0f || root.style.borderTopRightRadius > 0f || root.style.borderBottomLeftRadius > 0f || root.style.borderBottomRightRadius > 0f; RenderTexture renderTexture2 = null; RenderTexture active = RenderTexture.active; try { if (flag) { renderTexture = (renderTexture2 = RenderTexture.GetTemporary(num7, num8, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB)); } RenderTexture.active = renderTexture; GL.Clear(true, true, new Color(0f, 0f, 0f, 0f)); Matrix4x4 matrix4x = Matrix4x4.Translate(new Vector3((float)(-(float)Mathf.RoundToInt(worldBound.x)), (float)(-(float)Mathf.RoundToInt(worldBound.y)), 0f)); Matrix4x4 matrix4x2 = matrix4x * root.worldTransform; Rect rect2 = new Rect(0f, 0f, (float)num5, (float)num6); stylePainter.currentTransform = matrix4x2; bool enabled = SystemInfo.graphicsDeviceType != GraphicsDeviceType.Metal; using (new GUIUtility.ManualTex2SRGBScope(enabled)) { using (new GUIClip.ParentClipScope(stylePainter.currentTransform, rect2)) { stylePainter.currentWorldClip = rect2; root.DoRepaint(stylePainter); root.ClearDirty(ChangeType.Repaint); this.PaintSubTreeChildren(e, root, matrix4x, rect2); } } if (flag) { RenderTexture.active = root.renderData.pixelCache; stylePainter.currentTransform = Matrix4x4.identity; using (new GUIUtility.ManualTex2SRGBScope(enabled)) { using (new GUIClip.ParentClipScope(stylePainter.currentTransform, rect2)) { GL.Clear(true, true, new Color(0f, 0f, 0f, 0f)); TextureStylePainterParameters defaultTextureParameters = stylePainter.GetDefaultTextureParameters(root); defaultTextureParameters.texture = renderTexture; defaultTextureParameters.scaleMode = ScaleMode.StretchToFill; defaultTextureParameters.rect = rect2; defaultTextureParameters.border.SetWidth(0f); Vector4 vector = new Vector4(1f, 0f, 0f, 0f); float x = (matrix4x2 * vector).x; defaultTextureParameters.border.SetRadius(defaultTextureParameters.border.topLeftRadius * x, defaultTextureParameters.border.topRightRadius * x, defaultTextureParameters.border.bottomRightRadius * x, defaultTextureParameters.border.bottomLeftRadius * x); defaultTextureParameters.usePremultiplyAlpha = true; stylePainter.DrawTexture(defaultTextureParameters); } } stylePainter.currentTransform = matrix4x2; using (new GUIUtility.ManualTex2SRGBScope(enabled)) { using (new GUIClip.ParentClipScope(stylePainter.currentTransform, rect2)) { stylePainter.DrawBorder(root); } } } } finally { renderTexture = null; if (renderTexture2 != null) { RenderTexture.ReleaseTemporary(renderTexture2); } RenderTexture.active = active; } } stylePainter.currentWorldClip = currentGlobalClip; stylePainter.currentTransform = offset * root.worldTransform; TextureStylePainterParameters painterParams = new TextureStylePainterParameters { rect = root.rect, uv = new Rect(0f, 0f, 1f, 1f), texture = root.renderData.pixelCache, color = Color.white, scaleMode = ScaleMode.ScaleAndCrop, usePremultiplyAlpha = true }; using (new GUIClip.ParentClipScope(stylePainter.currentTransform, currentGlobalClip)) { stylePainter.DrawTexture(painterParams); } } else { this.stylePainter.currentTransform = offset * root.worldTransform; using (new GUIClip.ParentClipScope(this.stylePainter.currentTransform, currentGlobalClip)) { this.stylePainter.currentWorldClip = currentGlobalClip; this.stylePainter.mousePosition = root.worldTransform.inverse.MultiplyPoint3x4(e.mousePosition); this.stylePainter.opacity = root.style.opacity.GetSpecifiedValueOrDefault(1f); root.DoRepaint(this.stylePainter); this.stylePainter.opacity = 1f; root.ClearDirty(ChangeType.Repaint); this.PaintSubTreeChildren(e, root, offset, currentGlobalClip); } } } } }
public void PaintSubTree(Event e, VisualElement root, Matrix4x4 offset, Rect currentGlobalClip) { if ((root.pseudoStates & PseudoStates.Invisible) != PseudoStates.Invisible) { if (root.clippingOptions != VisualElement.ClippingOptions.NoClipping) { Rect rect = this.ComputeAAAlignedBound(root.layout, offset * root.worldTransform); if (!rect.Overlaps(currentGlobalClip)) { return; } float num = Mathf.Max(rect.x, currentGlobalClip.x); float num2 = Mathf.Min(rect.x + rect.width, currentGlobalClip.x + currentGlobalClip.width); float num3 = Mathf.Max(rect.y, currentGlobalClip.y); float num4 = Mathf.Min(rect.y + rect.height, currentGlobalClip.y + currentGlobalClip.height); currentGlobalClip = new Rect(num, num3, num2 - num, num4 - num3); } if (this.ShouldUsePixelCache(root)) { IStylePainter stylePainter = this.stylePainter; Rect worldBound = root.worldBound; int num5 = (int)worldBound.width; int num6 = (int)worldBound.height; int num7 = (int)(worldBound.width * GUIUtility.pixelsPerPoint); int num8 = (int)(worldBound.height * GUIUtility.pixelsPerPoint); RenderTexture renderTexture = root.renderData.pixelCache; if (renderTexture != null && !this.keepPixelCacheOnWorldBoundChange && (renderTexture.width != num7 || renderTexture.height != num8)) { Object.DestroyImmediate(renderTexture); renderTexture = (root.renderData.pixelCache = null); } float opacity = this.stylePainter.opacity; if (root.IsDirty(ChangeType.Repaint) || root.renderData.pixelCache == null) { if (renderTexture == null) { renderTexture = (root.renderData.pixelCache = new RenderTexture(num7, num8, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear)); } RenderTexture active = RenderTexture.active; RenderTexture.active = renderTexture; GL.Clear(true, true, new Color(0f, 0f, 0f, 0f)); offset = Matrix4x4.Translate(new Vector3(-worldBound.x, -worldBound.y, 0f)); Rect rect2 = new Rect(0f, 0f, (float)num5, (float)num6); stylePainter.currentTransform = offset * root.worldTransform; GUIClip.SetTransform(stylePainter.currentTransform, rect2); stylePainter.currentWorldClip = rect2; root.DoRepaint(stylePainter); root.ClearDirty(ChangeType.Repaint); this.PaintSubTreeChildren(e, root, offset, rect2); RenderTexture.active = active; } stylePainter.currentWorldClip = currentGlobalClip; stylePainter.currentTransform = root.worldTransform; GUIClip.SetTransform(stylePainter.currentTransform, currentGlobalClip); TextureStylePainterParameters painterParams = new TextureStylePainterParameters { layout = root.layout, texture = root.renderData.pixelCache, color = Color.white, scaleMode = ScaleMode.ScaleAndCrop }; stylePainter.DrawTexture(painterParams); } else { this.stylePainter.currentTransform = offset * root.worldTransform; GUIClip.SetTransform(this.stylePainter.currentTransform, currentGlobalClip); this.stylePainter.currentWorldClip = currentGlobalClip; this.stylePainter.mousePosition = root.worldTransform.inverse.MultiplyPoint3x4(e.mousePosition); this.stylePainter.opacity = root.style.opacity.GetSpecifiedValueOrDefault(1f); root.DoRepaint(this.stylePainter); this.stylePainter.opacity = 1f; root.ClearDirty(ChangeType.Repaint); this.PaintSubTreeChildren(e, root, offset, currentGlobalClip); } } }
private void PaintSubTree(VisualElement root, Matrix4x4 offset, bool shouldClip, bool shouldCache, Rect currentGlobalClip) { if (root == null || root.panel != panel) { return; } if (root.visible == false || root.style.opacity.GetSpecifiedValueOrDefault(1.0f) < Mathf.Epsilon) { return; } // update clip if (root.ShouldClip()) { var worldBound = VisualElement.ComputeAAAlignedBound(root.rect, offset * root.worldTransform); // are we and our children clipped? if (!worldBound.Overlaps(currentGlobalClip)) { return; } float x1 = Mathf.Max(worldBound.x, currentGlobalClip.x); float x2 = Mathf.Min(worldBound.xMax, currentGlobalClip.xMax); float y1 = Mathf.Max(worldBound.y, currentGlobalClip.y); float y2 = Mathf.Min(worldBound.yMax, currentGlobalClip.yMax); // new global clip and hierarchical clip space option. currentGlobalClip = new Rect(x1, y1, x2 - x1, y2 - y1); shouldClip = true; shouldCache = root.clippingOptions == VisualElement.ClippingOptions.ClipAndCacheContents; } else { //since our children are not clipped, there is no early out. } // Check for the rotated space - clipping issue. if (!m_WhinedOnceAboutRotatedClipSpaceThisFrame && shouldClip && !shouldCache && DoesMatrixHaveUnsupportedRotation(root.worldTransform)) { Debug.LogError("Panel.PaintSubTree - Rotated clip-spaces are only supported by the VisualElement.ClippingOptions.ClipAndCacheContents mode. First offending Panel:'" + root.name + "'."); m_WhinedOnceAboutRotatedClipSpaceThisFrame = true; } var prevElement = m_StylePainter.currentElement; m_StylePainter.currentElement = root; var repaintData = panel.repaintData; if (ShouldUsePixelCache(root)) { // now actually paint the texture to previous group // validate cache texture size first var worldBound = root.worldBound; Rect alignedRect; int textureWidth, textureHeight; repaintData.currentWorldClip = currentGlobalClip; repaintData.currentOffset = offset; using (new GUIClip.ParentClipScope(offset * root.worldTransform, currentGlobalClip)) { alignedRect = GUIUtility.AlignRectToDevice(root.rect, out textureWidth, out textureHeight); } // Prevent the texture size from going empty, which may occur if the element has a sub-pixel size textureWidth = Math.Max(textureWidth, 1); textureHeight = Math.Max(textureHeight, 1); var cache = root.renderData.pixelCache; if (cache != null && (cache.width != textureWidth || cache.height != textureHeight) && (!panel.keepPixelCacheOnWorldBoundChange || m_RepaintList.Contains(root))) { Object.DestroyImmediate(cache); cache = root.renderData.pixelCache = null; } // if the child node world transforms are not up to date due to changes below the pixel cache this is fine. if (m_RepaintList.Contains(root) || root.renderData.pixelCache == null || !root.renderData.pixelCache.IsCreated()) { // Recreate as needed if (cache == null) { root.renderData.pixelCache = cache = new RenderTexture( textureWidth, textureHeight, 32, // depth RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); } bool hasRoundedBorderRects = (root.style.borderTopLeftRadius > 0 || root.style.borderTopRightRadius > 0 || root.style.borderBottomLeftRadius > 0 || root.style.borderBottomRightRadius > 0); RenderTexture temporaryTexture = null; var old = RenderTexture.active; try { // We first render to a temp texture, then blit the result into the result pixelCache again to mask the rounder corners if (hasRoundedBorderRects) { // This should be an sRGB texture to conform with editor texture guidelines, however // converting the cache to sRGB requires a shader to do it, and this whole pixel cache // thing is slated to go away, so we take a short-cut here and use a linear texture // along with the use of manualTex2SRGBEnabled to get the correct results. temporaryTexture = cache = RenderTexture.GetTemporary(textureWidth, textureHeight, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); } // render the texture again to clip the round rect borders RenderTexture.active = cache; GL.Clear(true, true, new Color(0, 0, 0, 0)); // Calculate the offset required to translate the origin of the rect to the upper left corner // of the pixel cache. We need to round because the rect will be rounded when rendered. Rect worldAlignedRect = root.LocalToWorld(alignedRect); var childrenOffset = Matrix4x4.Translate(new Vector3(-worldAlignedRect.x, -worldAlignedRect.y, 0)); Matrix4x4 offsetWorldTransform = childrenOffset * root.worldTransform; // reset clipping var textureClip = new Rect(0, 0, worldAlignedRect.width, worldAlignedRect.height); repaintData.currentOffset = childrenOffset; using (new GUIClip.ParentClipScope(offsetWorldTransform, textureClip)) { // Paint self repaintData.currentWorldClip = textureClip; m_StylePainter.opacity = root.style.opacity.GetSpecifiedValueOrDefault(1.0f); root.Repaint(m_StylePainter); m_StylePainter.opacity = 1.0f; PaintSubTreeChildren(root, childrenOffset, shouldClip, shouldCache, textureClip); } if (hasRoundedBorderRects) { RenderTexture.active = root.renderData.pixelCache; bool oldManualTex2SRGBEnabled = GUIUtility.manualTex2SRGBEnabled; GUIUtility.manualTex2SRGBEnabled = false; using (new GUIClip.ParentClipScope(Matrix4x4.identity, textureClip)) { GL.Clear(true, true, new Color(0, 0, 0, 0)); var textureParams = TextureStylePainterParameters.GetDefault(root); textureParams.color = Color.white; textureParams.texture = cache; textureParams.scaleMode = ScaleMode.StretchToFill; textureParams.rect = textureClip; textureParams.border.SetWidth(0.0f); // The rect of the temporary texture implicitly carries the scale factor of the // transform. Since we are blitting with an identity matrix, we need to scale the // radius manually. // We assume uniform positive scaling without rotations. Vector4 toScale = new Vector4(1, 0, 0, 0); Vector4 scaled = offsetWorldTransform * toScale; float radiusScale = scaled.x; textureParams.border.SetRadius( textureParams.border.topLeftRadius * radiusScale, textureParams.border.topRightRadius * radiusScale, textureParams.border.bottomRightRadius * radiusScale, textureParams.border.bottomLeftRadius * radiusScale); // No border is drawn but the rounded corners are clipped properly. // Use premultiply alpha to avoid blending again. textureParams.usePremultiplyAlpha = true; m_StylePainter.DrawTexture(textureParams); } // Redraw the border (border was already drawn in first root.DoRepaint call). using (new GUIClip.ParentClipScope(offsetWorldTransform, textureClip)) { m_StylePainter.DrawBorder(); } GUIUtility.manualTex2SRGBEnabled = oldManualTex2SRGBEnabled; } } finally { cache = null; if (temporaryTexture != null) { RenderTexture.ReleaseTemporary(temporaryTexture); } RenderTexture.active = old; } } // now actually paint the texture to previous group repaintData.currentWorldClip = currentGlobalClip; repaintData.currentOffset = offset; bool oldManualTex2SRGBEnabled2 = GUIUtility.manualTex2SRGBEnabled; GUIUtility.manualTex2SRGBEnabled = false; using (new GUIClip.ParentClipScope(offset * root.worldTransform, currentGlobalClip)) { var painterParams = new TextureStylePainterParameters { rect = GUIUtility.AlignRectToDevice(root.rect), uv = new Rect(0, 0, 1, 1), texture = root.renderData.pixelCache, color = Color.white, scaleMode = ScaleMode.StretchToFill, usePremultiplyAlpha = true }; // We must not reapply the editor Play Mode Tint if it was already applied ! var playModeTint = UIElementsUtility.editorPlayModeTintColor; UIElementsUtility.editorPlayModeTintColor = Color.white; m_StylePainter.DrawTexture(painterParams); UIElementsUtility.editorPlayModeTintColor = playModeTint; } GUIUtility.manualTex2SRGBEnabled = oldManualTex2SRGBEnabled2; } else { repaintData.currentOffset = offset; using (new GUIClip.ParentClipScope(offset * root.worldTransform, currentGlobalClip)) { repaintData.currentWorldClip = currentGlobalClip; repaintData.mousePosition = root.worldTransform.inverse.MultiplyPoint3x4(repaintData.repaintEvent.mousePosition); m_StylePainter.opacity = root.style.opacity.GetSpecifiedValueOrDefault(1.0f); root.Repaint(m_StylePainter); m_StylePainter.opacity = 1.0f; PaintSubTreeChildren(root, offset, shouldClip, shouldCache, currentGlobalClip); } } m_StylePainter.currentElement = prevElement; }