Last active
October 30, 2021 06:02
-
-
Save shanecelis/7407d0809c114be5d20f089dfe3aa47a to your computer and use it in GitHub Desktop.
Render a triangle element in addition to the regular rectangular visual element.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Original code[1] Copyright (c) 2021 Shane Celis[1] | |
Licensed under the MIT License[1] | |
This comment generated by code-cite[1]. | |
[1]: https://gist.github.com/shanecelis/7407d0809c114be5d20f089dfe3aa47a | |
[1]: https://twitter.com/shanecelis | |
[1]: https://opensource.org/licenses/MIT | |
[1]: https://github.com/shanecelis/code-cite | |
*/ | |
using UnityEngine; | |
using UnityEngine.Scripting; | |
using UnityEngine.UIElements; | |
/** Render a triangle element in addition to the regular rectangular visual | |
element. | |
An XML attribute corner allows one to specify which triangle they want. | |
<TriangleElement corner="BottomRight" /> | |
A publicly accessible member called "texture" that can be set | |
programmatically. (Unity hasn't exposed a Texture attribute as far as I | |
know.) | |
Note: Having the texture specifiable in UXML would be preferable. Normally | |
I'd use the background texture. However, this is an additive method. Any | |
texture and color set on the VisualElement will be shown behind the | |
triangle. | |
TODO | |
==== | |
* Make texture specifiable in UXML. | |
* Use snake-case for corner attribute. | |
References | |
========== | |
* https://forum.unity.com/threads/draw-unity-gl-under-ui.914960/#post-5996561 | |
* https://forum.unity.com/threads/ui-builder-and-custom-elements.785129/ | |
*/ | |
public class TriangleElement : VisualElement { | |
/** Set the texture of the triangle (can be a RenderTexture). */ | |
public Texture texture; | |
public enum Corner { | |
TopLeft, | |
TopRight, | |
BottomRight, | |
BottomLeft, | |
} | |
internal Corner corner; | |
public TriangleElement() { | |
generateVisualContent += OnGenerateVisualContent; | |
} | |
static readonly Vertex[] k_Vertices = new Vertex[4]; | |
private static ushort[] k_Indices = new ushort[3]; | |
void OnGenerateVisualContent(MeshGenerationContext mgc) | |
{ | |
Rect r = contentRect; | |
if (r.width < 0.01f || r.height < 0.01f) | |
return; // Skip rendering when too small. | |
Color color = resolvedStyle.unityBackgroundImageTintColor; | |
k_Vertices[0].tint = color; | |
k_Vertices[1].tint = color; | |
k_Vertices[2].tint = color; | |
k_Vertices[3].tint = color; | |
float left = 0; | |
float right = r.width; | |
float top = 0; | |
float bottom = r.height; | |
k_Vertices[0].position = new Vector3(left, bottom, Vertex.nearZ); | |
k_Vertices[1].position = new Vector3(left, top, Vertex.nearZ); | |
k_Vertices[2].position = new Vector3(right, top, Vertex.nearZ); | |
k_Vertices[3].position = new Vector3(right, bottom, Vertex.nearZ); | |
// TopLeft indices: 0, 1, 2 | |
// TopRight indices: 1, 2, 3 | |
// BottomRight indices: 2, 3, 0 | |
// BottomLeft indices: 3, 0, 1 | |
ushort startIndex = (ushort) corner; | |
for (int i = 0; i < 3; i++) | |
k_Indices[i] = (ushort) ((i + startIndex) % 4); | |
MeshWriteData mwd = mgc.Allocate(k_Vertices.Length, | |
k_Indices.Length, | |
texture); | |
Rect uvRegion = mwd.uvRegion; | |
// Rescale the UV to work with the texture atlas. | |
k_Vertices[0].uv = Vector2.zero * uvRegion.size + uvRegion.min; | |
k_Vertices[1].uv = Vector2.up * uvRegion.size + uvRegion.min; | |
k_Vertices[2].uv = Vector2.one * uvRegion.size + uvRegion.min; | |
k_Vertices[3].uv = Vector2.right * uvRegion.size + uvRegion.min; | |
mwd.SetAllVertices(k_Vertices); | |
mwd.SetAllIndices(k_Indices); | |
} | |
[Preserve] | |
public new class UxmlFactory : UxmlFactory<TriangleElement, UxmlTraits> { } | |
[Preserve] | |
public new class UxmlTraits : VisualElement.UxmlTraits { | |
/* TODO: It'd be nice if UxmlEnumAttributeDescription provided a way to convert the | |
enum's ToString() which is PascalCase "BottomRight" to snake-case "bottom-right". */ | |
private UxmlEnumAttributeDescription<Corner> corner | |
= new UxmlEnumAttributeDescription<Corner> { name = "corner", | |
defaultValue = Corner.TopLeft }; | |
// https://forum.unity.com/threads/ui-builder-and-custom-elements.785129/ | |
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) { | |
base.Init(ve, bag, cc); | |
var te = ve as TriangleElement; | |
te.Clear(); | |
te.corner = this.corner.GetValueFromBag(bag, cc); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment