Example #1
0
        private static int GetOrSetTextureUnit(Text text, int index)
        {
            if (string.IsNullOrWhiteSpace(text?.Content))
            {
                return(-1);
            }

            if (SpriteRendererPanel.TextureUnits.ContainsKey(Tuple.Create(TextureType.Text, text.GetCharKey(index))))
            {
                return(SpriteRendererPanel.TextureUnits[Tuple.Create(TextureType.Text, text.GetCharKey(index))].ToInt());
            }
            else
            {
                // If at 16, will have already drawn batch
                if (SpriteRendererPanel.TextureUnits.Count >= SpriteRendererPanel.UsedTextureUnits - 1)
                {
                    SpriteRendererPanel.TextureUnits.Clear();
                }
                if (SpriteRendererPanel.TextTextures.ContainsKey(text.GetCharKey(index)) || SpriteRendererPanel.LoadTextTextures(text))
                {
                    var unitNumber  = SpriteRendererPanel.TextureUnits.Count;
                    var usedUnit    = unitNumber.ToTextureUnit();
                    var usedTexture = SpriteRendererPanel.TextTextures[text.GetCharKey(index)];
                    usedTexture.Use(usedUnit);
                    SpriteRendererPanel.Shader.SetInt($"textureArrays[{unitNumber}]", unitNumber);
                    SpriteRendererPanel.Shader.SetInt($"sheetW[{unitNumber}]", usedTexture.Width);
                    SpriteRendererPanel.Shader.SetInt($"sheetH[{unitNumber}]", usedTexture.Height);
                    SpriteRendererPanel.TextureUnits[Tuple.Create(TextureType.Text, text.GetCharKey(index))] = usedUnit;
                    return(unitNumber);
                }
                else
                {
                    return(-1);
                }
            }
        }
Example #2
0
 private void GLControlOnLoad(object sender, EventArgs e)
 {
     SpriteRendererPanel.Initialize();
     this.projection = Matrix4.CreateScale(2.0f / this.Width, -2.0f / this.Height, 1);
 }
Example #3
0
        public void Render()
        {
            if (this.initialScaleX.HasValue)
            {
                this.RenderScaleX  = this.initialScaleX.Value;
                this.initialScaleX = null;
            }

            if (this.initialScaleY.HasValue)
            {
                this.RenderScaleY  = this.initialScaleY.Value;
                this.initialScaleY = null;
            }

            lock (SpriteRendererPanel.RenderLock)
            {
                this.MakeCurrent();

                if (this.viewportUpdate)
                {
                    GL.Viewport(0, 0, this.Width, this.Height);
                    this.viewportUpdate = false;
                }

                if (this.backgroundTile == null)
                {
                    GL.ClearColor(this.backgroundColor);
                }

                GL.Clear(ClearBufferMask.ColorBufferBit);

                GL.BindVertexArray(vertexArrayObject);
                SpriteRendererPanel.Shader.Use();

                GL.BindVertexArray(vertexArrayObject);
                SpriteRendererPanel.Shader.SetVector2("origin", this.origin);
                SpriteRendererPanel.Shader.SetMatrix4("projection", this.projection);

                SpriteRendererPanel.Shader.SetInt($"drawType", 2);
                if (this.backgroundTile != null)
                {
                    var textureName  = this.backgroundTile.Texture;
                    var textureIndex = this.GetOrSetTextureUnit(textureName);
                    if (textureIndex != -1)
                    {
                        var textureSize = SpriteRendererPanel.SpriteSheets[textureName].Size;
                        var bgTiles     = new Size(2 + this.Width / this.backgroundTile.TileWidth, 2 + this.Height / textureSize.Height);
                        var texX        = this.backgroundTile.TextureFrame * this.backgroundTile.TileWidth;
                        SpriteRendererPanel.Shader.SetFloat($"spriteX[0]", this.backgroundTile.OffsetX - this.backgroundTile.TileWidth / 2);
                        SpriteRendererPanel.Shader.SetFloat($"spriteY[0]", this.backgroundTile.OffsetY - textureSize.Height / 2);
                        SpriteRendererPanel.Shader.SetInt($"spriteW[0]", this.backgroundTile.TileWidth);
                        SpriteRendererPanel.Shader.SetInt($"spriteW[1]", bgTiles.Width);
                        SpriteRendererPanel.Shader.SetInt($"spriteH[0]", textureSize.Height);
                        SpriteRendererPanel.Shader.SetInt($"spriteH[1]", bgTiles.Height);
                        SpriteRendererPanel.Shader.SetInt($"spriteTX[0]", texX);
                        SpriteRendererPanel.Shader.SetInt($"spriteTY[0]", 0);
                        SpriteRendererPanel.Shader.SetInt($"spriteTI[0]", textureIndex);
                        SpriteRendererPanel.Shader.SetVector2($"spriteScale[0]", Vector2.One);
                        SpriteRendererPanel.Shader.SetFloat($"spriteRotate[0]", 0);
                        SpriteRendererPanel.Shader.SetVector4($"colorModulation[0]", Vector4.One);
                        GL.DrawElementsInstanced(PrimitiveType.Triangles, Indices.Length, DrawElementsType.UnsignedInt, (IntPtr)0, bgTiles.Width * bgTiles.Height);
                    }
                }

                foreach (var kvp in this.renderedObjects.OrderBy(kvp => kvp.Key))
                {
                    var renderPass   = kvp.Key;
                    var levels       = kvp.Value.Levels;
                    var sprites      = kvp.Value.Sprites;
                    var texts        = kvp.Value.Texts;
                    var fillQuads    = kvp.Value.Quads.Where(q => q.Type.HasFlag(DrawType.Fill)).ToList();
                    var outlineQuads = kvp.Value.Quads.Where(q => q.Type.HasFlag(DrawType.Outline)).ToList();
                    var batchSize    = 0;

                    SpriteRendererPanel.Shader.SetInt($"drawType", 1);
                    for (int i = 0; i < levels.Count; i++)
                    {
                        var textureName  = levels[i].Texture;
                        var textureIndex = this.GetOrSetTextureUnit(textureName);
                        var textureSize  = textureIndex != -1 ? SpriteRendererPanel.SpriteSheets[textureName].Size : new Size(2000, 2000);
                        if (textureIndex == -1)
                        {
                            continue;
                        }

                        // Notable speed improvement over multiple $"[{batchSize}]"
                        var batchIndex = "[" + batchSize + "]";
                        SpriteRendererPanel.Shader.SetFloat("spriteX" + batchIndex, levels[i].X + textureSize.Width / 2);
                        SpriteRendererPanel.Shader.SetFloat("spriteY" + batchIndex, levels[i].Y + textureSize.Height / 2);
                        SpriteRendererPanel.Shader.SetInt("spriteW" + batchIndex, textureSize.Width);
                        SpriteRendererPanel.Shader.SetInt("spriteH" + batchIndex, textureSize.Height);
                        SpriteRendererPanel.Shader.SetInt("spriteTX" + batchIndex, 0);
                        SpriteRendererPanel.Shader.SetInt("spriteTY" + batchIndex, 0);
                        SpriteRendererPanel.Shader.SetInt("spriteTI" + batchIndex, textureIndex);
                        SpriteRendererPanel.Shader.SetVector2("spriteScale" + batchIndex, Vector2.One);
                        SpriteRendererPanel.Shader.SetFloat("spriteRotate" + batchIndex, 0);
                        SpriteRendererPanel.Shader.SetVector4("colorModulation" + batchIndex, Vector4.One);
                        batchSize++;
                        if (batchSize == SpriteRendererPanel.DrawBatchSize ||
                            i + 1 == levels.Count ||
                            (SpriteRendererPanel.TextureUnits.Count == SpriteRendererPanel.UsedTextureUnits - 1 && !SpriteRendererPanel.TextureUnits.ContainsKey(Tuple.Create(TextureType.Spritesheet, levels[i + 1].Texture))))
                        {
                            GL.DrawElementsInstanced(PrimitiveType.Triangles, SpriteRendererPanel.Indices.Length, DrawElementsType.UnsignedInt, (IntPtr)0, batchSize);
                            batchSize = 0;
                        }
                    }

                    SpriteRendererPanel.Shader.SetInt($"drawType", 4);
                    for (int i = 0; i < fillQuads.Count; i++)
                    {
                        var batchIndex = "[" + batchSize + "]";
                        SpriteRendererPanel.Shader.SetFloat($"spriteX" + batchIndex, fillQuads[i].A.X);
                        SpriteRendererPanel.Shader.SetFloat($"spriteY" + batchIndex, fillQuads[i].A.Y);
                        SpriteRendererPanel.Shader.SetInt($"spriteW" + batchIndex, fillQuads[i].B.X);
                        SpriteRendererPanel.Shader.SetInt($"spriteH" + batchIndex, fillQuads[i].B.Y);
                        SpriteRendererPanel.Shader.SetInt($"spriteTX" + batchIndex, fillQuads[i].C.X);
                        SpriteRendererPanel.Shader.SetInt($"spriteTY" + batchIndex, fillQuads[i].C.Y);
                        SpriteRendererPanel.Shader.SetInt($"spriteTI" + batchIndex, fillQuads[i].Color.ToArgb());
                        SpriteRendererPanel.Shader.SetVector2($"spriteScale" + batchIndex, new Vector2(fillQuads[i].D.X, fillQuads[i].D.Y));
                        SpriteRendererPanel.Shader.SetVector4($"colorModulation" + batchIndex, Vector4.One);
                        batchSize++;
                        if (batchSize == SpriteRendererPanel.DrawBatchSize || i + 1 == fillQuads.Count)
                        {
                            GL.DrawElementsInstanced(PrimitiveType.Triangles, SpriteRendererPanel.Indices.Length, DrawElementsType.UnsignedInt, (IntPtr)0, batchSize);
                            batchSize = 0;
                        }
                    }

                    SpriteRendererPanel.Shader.SetInt($"drawType", 4);
                    for (int i = 0; i < outlineQuads.Count; i++)
                    {
                        var batchIndex = "[" + batchSize + "]";
                        SpriteRendererPanel.Shader.SetFloat($"spriteX" + batchIndex, outlineQuads[i].A.X);
                        SpriteRendererPanel.Shader.SetFloat($"spriteY" + batchIndex, outlineQuads[i].A.Y);
                        SpriteRendererPanel.Shader.SetInt($"spriteW" + batchIndex, outlineQuads[i].B.X);
                        SpriteRendererPanel.Shader.SetInt($"spriteH" + batchIndex, outlineQuads[i].B.Y);
                        SpriteRendererPanel.Shader.SetInt($"spriteTX" + batchIndex, outlineQuads[i].C.X);
                        SpriteRendererPanel.Shader.SetInt($"spriteTY" + batchIndex, outlineQuads[i].C.Y);
                        SpriteRendererPanel.Shader.SetInt($"spriteTI" + batchIndex, outlineQuads[i].Color.ToArgb());
                        SpriteRendererPanel.Shader.SetVector2($"spriteScale" + batchIndex, new Vector2(outlineQuads[i].D.X, outlineQuads[i].D.Y));
                        SpriteRendererPanel.Shader.SetVector4($"colorModulation" + batchIndex, Vector4.One);
                        batchSize++;
                        if (batchSize == SpriteRendererPanel.DrawBatchSize || i + 1 == outlineQuads.Count)
                        {
                            GL.DrawElementsInstanced(PrimitiveType.LineStrip, SpriteRendererPanel.Indices.Length, DrawElementsType.UnsignedInt, (IntPtr)0, batchSize);
                            batchSize = 0;
                        }
                    }

                    SpriteRendererPanel.Shader.SetInt($"drawType", 0);
                    for (int i = 0; i < sprites.Count; i++)
                    {
                        var textureName  = sprites[i].Texture;
                        var textureIndex = this.GetOrSetTextureUnit(textureName);
                        if (textureIndex == -1)
                        {
                            continue;
                        }

                        // Manually clips texture since CLAMP_TO_EDGE didn't do anything on one test computer
                        var textureRect = new Rectangle(new Point(), this.GetTextureSize(textureName) ?? new Size(2000, 2000));
                        var spriteRect  = new Rectangle(sprites[i].TexX, sprites[i].TexY, sprites[i].Width, sprites[i].Height);
                        if (!textureRect.Contains(spriteRect))
                        {
                            spriteRect.Intersect(textureRect);
                            sprites[i].TexX   = spriteRect.Left;
                            sprites[i].TexY   = spriteRect.Top;
                            sprites[i].Width  = spriteRect.Width;
                            sprites[i].Height = spriteRect.Height;
                        }

                        var spriteColorModulation = default(Vector4);
                        if (!SpriteRendererPanel.CachedColorModulation.TryGetValue(sprites[i].ColorModulation, out spriteColorModulation))
                        {
                            spriteColorModulation = new Vector4(
                                sprites[i].ColorModulation.R / 255.0f,
                                sprites[i].ColorModulation.G / 255.0f,
                                sprites[i].ColorModulation.B / 255.0f,
                                sprites[i].ColorModulation.A / 255.0f);
                            SpriteRendererPanel.CachedColorModulation[sprites[i].ColorModulation] = spriteColorModulation;
                        }

                        var batchIndex = "[" + batchSize + "]";
                        SpriteRendererPanel.Shader.SetFloat($"spriteX" + batchIndex, sprites[i].X);
                        SpriteRendererPanel.Shader.SetFloat($"spriteY" + batchIndex, sprites[i].Y);
                        SpriteRendererPanel.Shader.SetInt($"spriteW" + batchIndex, sprites[i].Width);
                        SpriteRendererPanel.Shader.SetInt($"spriteH" + batchIndex, sprites[i].Height);
                        SpriteRendererPanel.Shader.SetInt($"spriteTX" + batchIndex, sprites[i].TexX);
                        SpriteRendererPanel.Shader.SetInt($"spriteTY" + batchIndex, sprites[i].TexY);
                        SpriteRendererPanel.Shader.SetInt($"spriteTI" + batchIndex, textureIndex);
                        var tkScaleVector = new Vector2(sprites[i].Scale.X, sprites[i].Scale.Y);
                        SpriteRendererPanel.Shader.SetVector2($"spriteScale" + batchIndex, tkScaleVector);
                        SpriteRendererPanel.Shader.SetFloat($"spriteRotate" + batchIndex, sprites[i].Rotate);
                        SpriteRendererPanel.Shader.SetVector4($"colorModulation" + batchIndex, spriteColorModulation);
                        batchSize++;
                        if (batchSize == SpriteRendererPanel.DrawBatchSize ||
                            i + 1 == sprites.Count ||
                            (SpriteRendererPanel.TextureUnits.Count == SpriteRendererPanel.UsedTextureUnits - 1 && !SpriteRendererPanel.TextureUnits.ContainsKey(Tuple.Create(TextureType.Spritesheet, sprites[i + 1].Texture))))
                        {
                            GL.DrawElementsInstanced(PrimitiveType.Triangles, SpriteRendererPanel.Indices.Length, DrawElementsType.UnsignedInt, (IntPtr)0, batchSize);
                            batchSize = 0;
                        }
                    }

                    SpriteRendererPanel.Shader.SetInt($"drawType", 0);
                    foreach (var text in texts)
                    {
                        var offset = 0.0;
                        for (var i = 0; i < text.Content.Length; i++)
                        {
                            var textureIndex = SpriteRendererPanel.GetOrSetTextureUnit(text, i);
                            if (textureIndex == -1 || !SpriteRendererPanel.TextTextures.ContainsKey(text.GetCharKey(i)))
                            {
                                continue;
                            }

                            var texture = SpriteRendererPanel.TextTextures[text.GetCharKey(i)];
                            var metrics = FontGlyphs.TextMetrics[text.GetCharKey(i)];

                            var face       = FontGlyphs.TextFaces[text.Font];
                            var faceHeight = FontGlyphs.TextFaceHeights[text.Font];

                            var adjustedPosition = new PointF(
                                text.Position.X + (float)(offset + metrics.HorizontalBearingX + (metrics.Width / 2.0)),
                                text.Position.Y + (float)(faceHeight - metrics.HorizontalBearingY + (metrics.Height / 2.0)));

                            var advance = metrics.HorizontalAdvance;

                            var textColorModulation = default(Vector4);
                            if (!SpriteRendererPanel.CachedColorModulation.TryGetValue(text.Color, out textColorModulation))
                            {
                                textColorModulation = new Vector4(text.Color.R / 255.0f, text.Color.G / 255.0f, text.Color.B / 255.0f, text.Color.A / 255.0f);
                                SpriteRendererPanel.CachedColorModulation[text.Color] = textColorModulation;
                            }
                            SpriteRendererPanel.Shader.SetFloat($"spriteX[0]", adjustedPosition.X);
                            SpriteRendererPanel.Shader.SetFloat($"spriteY[0]", adjustedPosition.Y);
                            SpriteRendererPanel.Shader.SetInt($"spriteW[0]", texture.Width);
                            SpriteRendererPanel.Shader.SetInt($"spriteH[0]", texture.Height);
                            SpriteRendererPanel.Shader.SetInt($"spriteTX[0]", 0);
                            SpriteRendererPanel.Shader.SetInt($"spriteTY[0]", 0);
                            SpriteRendererPanel.Shader.SetInt($"spriteTI[0]", textureIndex);
                            SpriteRendererPanel.Shader.SetVector2($"spriteScale[0]", Vector2.One);
                            SpriteRendererPanel.Shader.SetFloat($"spriteRotate[0]", 0);
                            SpriteRendererPanel.Shader.SetVector4($"colorModulation[0]", textColorModulation);

                            GL.DrawElementsInstanced(PrimitiveType.Triangles, SpriteRendererPanel.Indices.Length, DrawElementsType.UnsignedInt, (IntPtr)0, 1);

                            offset += advance;
                        }
                    }
                }
                this.backgroundTile = null;
                this.renderedObjects.Clear();

                this.SwapBuffers();

                // TODO: Figure out what messes with textureunits between renders
                SpriteRendererPanel.TextureUnits.Clear();
            }
        }