From f29f0def4377e9b809147d774c81959ea2e5300a Mon Sep 17 00:00:00 2001 From: Random <28494085+Random06457@users.noreply.github.com> Date: Fri, 26 Mar 2021 00:53:26 +0100 Subject: [PATCH] Add TextDrawer + Add lazy alpha test + move rdp vertex bomswap to vertex shader --- Z64Utils/F3DZEX/Render/RdpVertexDrawer.cs | 3 +- Z64Utils/F3DZEX/Render/Renderer.cs | 20 +- Z64Utils/F3DZEX/Render/TextDrawer.cs | 233 ++++++++++++++++++ .../F3DZEX/Render/TexturedVertexDrawer.cs | 37 +++ Z64Utils/F3DZEX/Render/VertexAttribs.cs | 7 +- Z64Utils/Forms/SkeletonViewerForm.cs | 1 + Z64Utils/Shaders/rdpVtx.frag | 19 +- Z64Utils/Shaders/rdpVtx.vert | 24 +- Z64Utils/Shaders/texturedVtx.frag | 17 ++ Z64Utils/Shaders/texturedVtx.vert | 16 ++ Z64Utils/Z64Utils.csproj | 6 + 11 files changed, 371 insertions(+), 12 deletions(-) create mode 100644 Z64Utils/F3DZEX/Render/TextDrawer.cs create mode 100644 Z64Utils/F3DZEX/Render/TexturedVertexDrawer.cs create mode 100644 Z64Utils/Shaders/texturedVtx.frag create mode 100644 Z64Utils/Shaders/texturedVtx.vert diff --git a/Z64Utils/F3DZEX/Render/RdpVertexDrawer.cs b/Z64Utils/F3DZEX/Render/RdpVertexDrawer.cs index 9607d9e..1d5706f 100644 --- a/Z64Utils/F3DZEX/Render/RdpVertexDrawer.cs +++ b/Z64Utils/F3DZEX/Render/RdpVertexDrawer.cs @@ -14,7 +14,8 @@ namespace F3DZEX.Render _shader = new ShaderHandler("Shaders/rdpVtx.vert", "Shaders/rdpVtx.frag"); _attrs = new VertexAttribs(); // position - _attrs.LayoutAddFloat(3, VertexAttribPointerType.Short, false); + //_attrs.LayoutAddFloat(3, VertexAttribPointerType.Short, false); + _attrs.LayoutAddInt(3, VertexAttribIntegerType.UnsignedShort); //flag _attrs.LayoutAddInt(1, VertexAttribIntegerType.UnsignedShort); // tex coords diff --git a/Z64Utils/F3DZEX/Render/Renderer.cs b/Z64Utils/F3DZEX/Render/Renderer.cs index d197e9c..4c01ac1 100644 --- a/Z64Utils/F3DZEX/Render/Renderer.cs +++ b/Z64Utils/F3DZEX/Render/Renderer.cs @@ -64,6 +64,7 @@ namespace F3DZEX.Render RdpVertexDrawer _rdpVtxDrawer; SimpleVertexDrawer _gridDrawer; ColoredVertexDrawer _axisDrawer; + TextDrawer _textDrawer; TextureHandler _curTex; Stack _mtxStack = new Stack(); @@ -150,6 +151,7 @@ namespace F3DZEX.Render _rdpVtxDrawer = new RdpVertexDrawer(); _gridDrawer = new SimpleVertexDrawer(); _axisDrawer = new ColoredVertexDrawer(); + _textDrawer = new TextDrawer(); float[] vertices = RenderHelper.GenerateGridVertices(CurrentConfig.GridScale, 6, false); _gridDrawer.SetData(vertices, BufferUsageHint.StaticDraw); @@ -180,9 +182,12 @@ namespace F3DZEX.Render _mtxStack = new Stack(); PushMatrix(Matrix4.Identity); + _gridDrawer.SendProjViewMatrices(ref proj, ref view); _axisDrawer.SendProjViewMatrices(ref proj, ref view); _rdpVtxDrawer.SendProjViewMatrices(ref proj, ref view); + Matrix4 id = Matrix4.Identity; + _textDrawer.SendProjViewMatrices(ref id, ref id); SendHighlightColor(Color.Transparent); @@ -217,6 +222,13 @@ namespace F3DZEX.Render if (CurrentConfig.ShowAxis) RenderHelper.DrawAxis(_axisDrawer); + _textDrawer.DrawString( + //$"Extensions: {GL.GetString(StringName.Extensions)}\n" + + $"Shading Language Version: {GL.GetString(StringName.ShadingLanguageVersion)}\n" + + $"Version: {GL.GetString(StringName.Version)}\n" + + $"Renderer: {GL.GetString(StringName.Renderer)}\n" + + $"Vendor: {GL.GetString(StringName.Vendor)}"); + CheckGLErros(); } @@ -407,8 +419,12 @@ namespace F3DZEX.Render } else { - byte[] indices = new byte[] { cmd.v00, cmd.v01, cmd.v02, cmd.v00, cmd.v10, cmd.v11, cmd.v12, cmd.v10 }; - _rdpVtxDrawer.Draw(PrimitiveType.LineStrip, indices); + //byte[] indices = new byte[] { cmd.v00, cmd.v01, cmd.v02, cmd.v00, cmd.v10, cmd.v11, cmd.v12, cmd.v10 }; + //_rdpVtxDrawer.Draw(PrimitiveType.LineStrip, indices); + byte[] indices = new byte[] { cmd.v00, cmd.v01, cmd.v02 }; + _rdpVtxDrawer.Draw(PrimitiveType.LineLoop, indices); + indices = new byte[] { cmd.v10, cmd.v11, cmd.v12 }; + _rdpVtxDrawer.Draw(PrimitiveType.LineLoop, indices); } } break; diff --git a/Z64Utils/F3DZEX/Render/TextDrawer.cs b/Z64Utils/F3DZEX/Render/TextDrawer.cs new file mode 100644 index 0000000..86dcdd2 --- /dev/null +++ b/Z64Utils/F3DZEX/Render/TextDrawer.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenTK; +using System.Drawing; +using System.Linq; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using OpenTK.Graphics.OpenGL; + +namespace F3DZEX.Render +{ + public class TextDrawer + { + TexturedVertexDrawer _vtxDrawer; + TextureHandler _tex; + Font _font; + Color _color; + //float _scale; + byte[] _texData; + int _texWidth; + int _texHeight; + RectangleF[] _charSpaces; + string _lastStr; + float[] _lastVertices; + + public Vector2 Position { get; set; } + public Font TextFont { + get => _font; + set { _font = value; GenerateAlphabetTexture(); } + } + public Color Color + { + get => _color; + set { _color = value; SendColor(_color); } + } + + public float Scale { get; set; } + public int TextHSpace { get; set; } + public int TextVSpace { get; set; } + + + public TextDrawer() + { + _vtxDrawer = new TexturedVertexDrawer(); + _tex = new TextureHandler(); + TextFont = new Font("Arial", 50); + _lastStr = null; + Scale = 0.4f; + Color = Color.White; + TextHSpace = -15; + TextVSpace = -5; + } + + public float GetTextWidth(string text) + { + using (var g = Graphics.FromImage(new Bitmap(1, 1))) + return g.MeasureString(text, TextFont).Width; + } + + private SizeF GetCharSize(char c) + { + using (Graphics g = Graphics.FromImage(new Bitmap(1, 1))) + { + return g.MeasureString(c.ToString(), TextFont); + } + } + + private RectangleF[] GetCharRange(string text) + { + RectangleF[] ret = new RectangleF[text.Length]; + + using (var g = Graphics.FromImage(new Bitmap(1, 1))) + { + float x = 0; + for (int i = 0; i < text.Length; i++) + { + var size = g.MeasureString(text[i].ToString(), _font); + + ret[i] = new RectangleF(x, 0, size.Width, size.Height); + x += size.Width; + } + + return ret; + + + /*CharacterRange[] charRanges = new CharacterRange[text.Length]; + for (int i = 0; i < text.Length-1; i++) + charRanges[i] = new CharacterRange(i, 1); +*/ + /* + CharacterRange[] charRanges = new CharacterRange[] { new CharacterRange(0, text.Length) }; + + StringFormat strFmt = new StringFormat(); + strFmt.FormatFlags = StringFormatFlags.NoClip; + strFmt.SetMeasurableCharacterRanges(charRanges); + + var region = g.MeasureCharacterRanges(text, TextFont, new RectangleF(0, 0, 100, 100), strFmt); + List ret = new List(); + region.ToList().ForEach(r => ret.Add(r.GetBounds(g))); + return ret;*/ + } + } + + private void GenerateAlphabetTexture() + { + string alphabet = GetAlphabet(); + _charSpaces = GetCharRange(alphabet); + + // calculate texture size + _texWidth = (int)(_charSpaces.Last().X + _charSpaces.Last().Width); + _texHeight = 0; + for (int i = 0; i < alphabet.Length; i++) + _texHeight = Math.Max(_texHeight, (int)_charSpaces[i].Height); + + // draw alphabet + Bitmap bmp = new Bitmap(_texWidth, _texHeight); + using (var g = Graphics.FromImage(bmp)) + for (int i = 0; i < alphabet.Length; i++) + g.DrawString(alphabet[i].ToString(), _font, new SolidBrush(Color.White), _charSpaces[i].X, 0); + //g.DrawString(alphabet, _font, new SolidBrush(Color.White), new PointF(0, 0)); + + _texData = new byte[bmp.Width * bmp.Height * 4]; + var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + Marshal.Copy(bmpData.Scan0, _texData, 0, _texData.Length); + + bmp.UnlockBits(bmpData); + + _tex.SetDataRGBA(_texData, _texWidth, _texHeight); + } + + private static string GetAlphabet() + { + string ret = ""; + for (int i = 0; i < 0x100; i++) + ret += (char)i; + return ret; + } + + public float[] GenerateVertices(string text) + { + int stride = 3 + 2; + float[] vertices = new float[stride * 4 * text.Replace("\n", "").Length]; + + float x = 0; + float y = 0; + int vtxIdx = 0; + for (int i = 0; i < text.Length; i++) + { + if (text[i] == '\n') + { + y -= _texHeight + TextVSpace; + x = 0; + continue; + } + + RectangleF rec = _charSpaces[text[i] >= 0x100 ? 0 : text[i]]; + + // top left + vertices[vtxIdx++] = x; + vertices[vtxIdx++] = y; + vertices[vtxIdx++] = 0; + vertices[vtxIdx++] = rec.X / _texWidth; + vertices[vtxIdx++] = -(rec.Y / _texHeight); + + // top right + vertices[vtxIdx++] = x + rec.Width; + vertices[vtxIdx++] = y; + vertices[vtxIdx++] = 0; + vertices[vtxIdx++] = (rec.X + rec.Width) / _texWidth; + vertices[vtxIdx++] = -(rec.Y / _texHeight); + + // bottom right + vertices[vtxIdx++] = x + rec.Width; + vertices[vtxIdx++] = y + rec.Height; + vertices[vtxIdx++] = 0; + vertices[vtxIdx++] = (rec.X + rec.Width) / _texWidth; + vertices[vtxIdx++] = -((rec.Y + rec.Height) / _texHeight); + + // bottom left + vertices[vtxIdx++] = x; + vertices[vtxIdx++] = y + rec.Height; + vertices[vtxIdx++] = 0; + vertices[vtxIdx++] = rec.X / _texWidth; + vertices[vtxIdx++] = -((rec.Y + rec.Height) / _texHeight); + + + x += rec.Width; + if (text[i] != ' ') + x += TextHSpace; + } + + return vertices; + } + + public void DrawString(string str) + { + _tex.Use(); + if (str != _lastStr) + { + _lastStr = str; + _lastVertices = GenerateVertices(str); + _vtxDrawer.SetData(_lastVertices, BufferUsageHint.DynamicDraw); + } + + _vtxDrawer.SendModelMatrix(GetMatrix()); + _vtxDrawer.Draw(PrimitiveType.Quads); + } + + public Matrix4 GetMatrix() + { + GL.GetFloat(GetPName.Viewport, out Vector4 view); + + Vector3 pos = new Vector3(Position); + pos.X -= 1; + pos.Y += 1 - ((float)_texHeight / 2 / view.W); + + return Matrix4.CreateScale(Scale / view.Z, Scale / view.W, 1) * Matrix4.CreateTranslation(pos); + } + + public void SendColor(Color color) + { + _vtxDrawer.SendColor(color); + } + + + public void SendProjViewMatrices(ref Matrix4 proj, ref Matrix4 view) + { + _vtxDrawer.SendProjViewMatrices(ref proj, ref view); + } + } +} diff --git a/Z64Utils/F3DZEX/Render/TexturedVertexDrawer.cs b/Z64Utils/F3DZEX/Render/TexturedVertexDrawer.cs new file mode 100644 index 0000000..1a9611e --- /dev/null +++ b/Z64Utils/F3DZEX/Render/TexturedVertexDrawer.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Text; +using OpenTK.Graphics.OpenGL; +using OpenTK; + +namespace F3DZEX.Render +{ + public class TexturedVertexDrawer : VertexDrawer + { + public TexturedVertexDrawer() + { + _shader = new ShaderHandler("Shaders/texturedVtx.vert", "Shaders/texturedVtx.frag"); + _attrs = new VertexAttribs(); + + // pos + _attrs.LayoutAddFloat(3, VertexAttribPointerType.Float, false); + // texture coordinates + _attrs.LayoutAddFloat(2, VertexAttribPointerType.Float, false); + } + + public void SendColor(Color color) + { + _shader.Send("u_Color", color); + } + + public void SetData(float[] data, BufferUsageHint hint) => SetVertexData(data, data.Length * sizeof(float), hint); + + public void SendProjViewMatrices(ref Matrix4 proj, ref Matrix4 view) + { + _shader.Send("u_Projection", proj); + _shader.Send("u_View", view); + } + public void SendModelMatrix(Matrix4 model) => _shader.Send("u_Model", model); + } +} diff --git a/Z64Utils/F3DZEX/Render/VertexAttribs.cs b/Z64Utils/F3DZEX/Render/VertexAttribs.cs index edbcc48..bae995a 100644 --- a/Z64Utils/F3DZEX/Render/VertexAttribs.cs +++ b/Z64Utils/F3DZEX/Render/VertexAttribs.cs @@ -147,6 +147,7 @@ namespace F3DZEX.Render private void BomSwap(byte[] buffer) { + /* int off = 0; while (off < buffer.Length) { @@ -162,6 +163,7 @@ namespace F3DZEX.Render } } } + */ } public void SetSubData(byte[] data, int off, bool bigEndian) @@ -169,8 +171,10 @@ namespace F3DZEX.Render if (!_built) BuildLayout(); + /* if (bigEndian) BomSwap(data); + */ GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); GL.BufferSubData(BufferTarget.ArrayBuffer, new IntPtr(off), data.Length, data); @@ -180,9 +184,10 @@ namespace F3DZEX.Render { if (!_built) BuildLayout(); - + /* if (bigEndian) BomSwap(data); + */ GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); GL.BufferData(BufferTarget.ArrayBuffer, data.Length, data, hint); diff --git a/Z64Utils/Forms/SkeletonViewerForm.cs b/Z64Utils/Forms/SkeletonViewerForm.cs index 18f5a3d..8beb831 100644 --- a/Z64Utils/Forms/SkeletonViewerForm.cs +++ b/Z64Utils/Forms/SkeletonViewerForm.cs @@ -102,6 +102,7 @@ namespace Z64.Forms { _renderer.RenderStart(proj, view); RenderLimb(0); + /* GL.PointSize(10.0f); GL.LineWidth(2.0f); diff --git a/Z64Utils/Shaders/rdpVtx.frag b/Z64Utils/Shaders/rdpVtx.frag index 2383521..d8ed7c4 100644 --- a/Z64Utils/Shaders/rdpVtx.frag +++ b/Z64Utils/Shaders/rdpVtx.frag @@ -12,10 +12,22 @@ uniform bool u_TexEnabled; void main() { + /* texture */ - gl_FragColor = u_TexEnabled - ? texture(u_Tex, v_VtxTexCoords) - : vec4(0, 0, 0, 1); + if (u_TexEnabled) + { + vec4 color = texture(u_Tex, v_VtxTexCoords); + + /* lazy alpha check */ + if (color.a < 0.1) + discard; + + gl_FragColor = color; + } + else + { + gl_FragColor = vec4(0, 0, 0, 1); + } /* blending */ // FragColor *= v_VtxColor; @@ -42,5 +54,4 @@ void main() z -= 0.4; gl_FragColor *= vec4(vec3(z), 1.0); */ - } \ No newline at end of file diff --git a/Z64Utils/Shaders/rdpVtx.vert b/Z64Utils/Shaders/rdpVtx.vert index 5e9da0e..61aa2e7 100644 --- a/Z64Utils/Shaders/rdpVtx.vert +++ b/Z64Utils/Shaders/rdpVtx.vert @@ -1,6 +1,6 @@ #version 330 core -layout(location = 0) in vec3 pos; +layout(location = 0) in ivec3 pos; layout(location = 1) in int flag; layout(location = 2) in ivec2 texCoords; layout(location = 3) in vec4 color; @@ -19,19 +19,35 @@ float S105ToFloat(int fp) return fp >> 5; } +int bomSwap16(int x) +{ + return (((x >> 0) & 0xFF) << 24) >> 16 | + ((x >> 8) & 0xFF); +} + vec2 decodeTexCoords(sampler2D tex, ivec2 coords) { ivec2 size = textureSize(tex, 0); return vec2(S105ToFloat(coords.x) / size.x, S105ToFloat(coords.y) / size.y); } +vec2 getTexCoords() +{ + return decodeTexCoords(u_Tex, ivec2(bomSwap16(texCoords.x), bomSwap16(texCoords.y))); +} + +vec3 getPos() +{ + return vec3(float(bomSwap16(pos.x)), float(bomSwap16(pos.y)), float(bomSwap16(pos.z))); +} + + void main() { v_VtxId = gl_VertexID; /* The vertices coordinates are multiplied by the model view matrix during the G_VTX command processing */ - gl_Position = u_Projection * u_View /* u_Model*/ * vec4(pos, 1); - v_VtxTexCoords = decodeTexCoords(u_Tex, texCoords); + gl_Position = u_Projection * u_View /* u_Model*/ * vec4(getPos(), 1); + v_VtxTexCoords = getTexCoords(); v_VtxColor = color; - } \ No newline at end of file diff --git a/Z64Utils/Shaders/texturedVtx.frag b/Z64Utils/Shaders/texturedVtx.frag new file mode 100644 index 0000000..b6b26df --- /dev/null +++ b/Z64Utils/Shaders/texturedVtx.frag @@ -0,0 +1,17 @@ +#version 330 core + +uniform sampler2D u_Tex; +uniform vec4 u_Color; + +in vec2 v_TexCoords; + +void main() +{ + vec4 color = texture(u_Tex, v_TexCoords) * u_Color; + if (color.a < 0.1) + discard; + gl_FragColor = color; + //gl_FragColor = vec4(1, v_TexCoords.y, 0, 1); + //gl_FragColor = vec4(v_TexCoords.x, 1, 0, 1); + //gl_FragColor = vec4(1, 0, 0, 1); +} \ No newline at end of file diff --git a/Z64Utils/Shaders/texturedVtx.vert b/Z64Utils/Shaders/texturedVtx.vert new file mode 100644 index 0000000..cc60112 --- /dev/null +++ b/Z64Utils/Shaders/texturedVtx.vert @@ -0,0 +1,16 @@ +#version 330 core + +uniform mat4 u_Projection; +uniform mat4 u_View; +uniform mat4 u_Model; + +layout (location = 0) in vec3 coords; +layout (location = 1) in vec2 texCoords; + +out vec2 v_TexCoords; + +void main() +{ + gl_Position = u_Projection * u_View * u_Model * vec4(coords, 1); + v_TexCoords = texCoords; +} \ No newline at end of file diff --git a/Z64Utils/Z64Utils.csproj b/Z64Utils/Z64Utils.csproj index d3d57de..f6a9888 100644 --- a/Z64Utils/Z64Utils.csproj +++ b/Z64Utils/Z64Utils.csproj @@ -62,6 +62,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + kaeton.ico