0

I am working on a 2D menu for a game using OpenTK in C#. At the moment, the menu is separated in 3 different texture quads, or 'layers', which looks like this.

Layer 1: The base appearance of the buttons.

Layer 2: The appearance of the 'continue' button when the mouse hovers over it.

Layer 3: A 'gear' which holds the buttons, as well as their text/name.

Each of these layers consists of a semi-transparent (32-bit .png) texture bound to a Quad. When drawing only layers 1 & 3, the textures seem to work properly, but when I want to show Layer 2 as well, layer 3 disappears from my screen, as seen here. In this image, only my base buttons (layer 1) and highlighted 'continue' button (layer 2) are drawn.

I believe this is an issue with my blend function, and the fact that I am drawing more than 2 sprites. I am relatively new to OpenTK/OpenGL, and I was hoping someone here could help me fix this problem. I will add some of my code below:

When the game starts, I set up some GL properties:

 GL.Enable(EnableCap.DepthTest);
 GL.Enable(EnableCap.CullFace);
 GL.Enable(EnableCap.Texture2D);

 GL.Enable(EnableCap.Blend); //I migh t be missing something here, like textEnv?
 GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

This part of the code draws my 2D elements. I took it from a tutorial on OpenTK.

public void DrawHUD()
    {
        // Clear only the depth buffer, so that everything
        //  we draw for the HUD will appear in front of the
        //  world objects.
        GL.Clear(ClearBufferMask.DepthBufferBit);

        // Reset the ModelView matrix so the following
        //  objects are not affected by the camera position
        GL.LoadIdentity();

        ////draw 3d hud elements (weapon in the main game)

        // Disable lighting for the HUD graphics
        // GL.Disable(EnableCap.Lighting);

        // Save the current perspective projection
        GL.MatrixMode(MatrixMode.Projection);
        GL.PushMatrix();

        // Switch to orthogonal view
        GL.LoadIdentity();
        GL.Ortho(0, Width, 0, Height, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)

        // Go back to working with the ModelView
        GL.MatrixMode(MatrixMode.Modelview);

        //// Draw the HUD elements
        GameEngine.Draw2D();

        // Switch back to perspective view
        GL.MatrixMode(MatrixMode.Projection);
        GL.PopMatrix();
        GL.MatrixMode(MatrixMode.Modelview);

        // Turn lighting back on
        // GL.Enable(EnableCap.Lighting);
    }

I add the menu 'layers' to an arraylist, which I then use to draw using Graphic, a class which holds the position/texture info of my 'layer'

 public virtual void Draw2D()
    {
        Vector2 pos;
        int Z = 0; //to fight z-fighting? this fixed an issue where drawing a 2nd sprite would also make the 1st one dissapear partially
        foreach (Graphic G in _2DList)
        {
            if (G.visible())
            {
                pos = G.position();
                Renderer.DrawHUDSprite(pos.X, pos.Y, Z, G.W(), G.H(), G.Texture());
                Z++;
            }
        }
    }

Finally, my draw function for hudsprites looks like this:

public static void DrawHUDSprite(float x, float y, float z, float width, float height, int textID)
    {
        // Save the ModelView matrix
        GL.PushMatrix();

        // Move to the correct location on screen
        GL.Translate(x, y, z);

        GL.BindTexture(TextureTarget.Texture2D, textID);

        // Setup for drawing the texture
        GL.Color3(Color.White);

        // Draw a flat rectangle
        GL.Begin(PrimitiveType.Quads);
        GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(0, 0, 0);
        GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(width, 0, 0);
        GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(width, height, 0);
        GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(0, height, 0);
        GL.End();

        // Restore the ModelView matrix
        GL.BindTexture(TextureTarget.Texture2D, 0);
        GL.PopMatrix();
    }

If this has anything to do with the way I load my textures, I will add the code for this as well.

NyteQuist
  • 11
  • 3

1 Answers1

0

I managed to solve my issue on my own: The problem lies with my draw2D() function, where I use a Z coordinate to prevent clipping issues. The Z-coordinate when drawing in 2D could only be in the range of [0..1].

My earlier solution which increments Z by 1 (Z++) would cause issues with more than 2 textures/Graphics (Z>1, meaning the quad is not displayed). The fixed version looks like this:

    public virtual void Draw2D()
    {
        if (_2DList.Count > 0) { //pervents dividing by 0, and skips memory allocation if we have no Graphics
            Vector2 pos;
            float Z = 0; //to fight z-fighting, the sprites ar drawn in the order they were added.
            float step = 1.0f / _2DList.Count; //limiting the Z between [0..1]
            foreach (Graphic G in _2DList)
            {
                if (G.visible())
                {
                    pos = G.position();
                    Renderer.DrawHUDSprite(pos.X, pos.Y, Z, G.W(), G.H(), G.Texture());
                    Z += step; //with z starting at 0, it will never be 1.
                }
            }
        }
    }
NyteQuist
  • 11
  • 3