atsv's picture

Simple blending example

Hi, guys!

Sorry if the topic has been raised already, but I didn't find anything on it, no examples in the bundle.
I'm trying to use blending in my app, and it doesn't work.
Here is the code:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private void glControl1_Load(object sender, EventArgs e)
        {
            GL.Enable(EnableCap.Blend);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
            GL.Disable(EnableCap.DepthTest);
        }
 
        private void glControl1_Paint(object sender, PaintEventArgs e)
        {
            GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.Ortho(0, 3, 3, 0, -1.0, 1.0);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadIdentity();
            GL.ClearColor(0, 0, 0, 0);
            GL.Clear(ClearBufferMask.ColorBufferBit);
            GL.Color4(0, 0, 1, 0.5);
            GL.Begin(BeginMode.Polygon);
            GL.Vertex2(0, 0);
            GL.Vertex2(0, 2);
            GL.Vertex2(2, 2);
            GL.Vertex2(2, 0);
            GL.End();
            GL.Color4(1, 0, 0, 0.5);
            GL.Begin(BeginMode.Polygon);
            GL.Vertex2(1, 1);
            GL.Vertex2(1, 3);
            GL.Vertex2(3, 3);
            GL.Vertex2(3, 1);
            GL.End();
            glControl1.SwapBuffers();
        }
    }
}

All I see is the red quad above the blue one, no blending.
I'm using OpenTK 0.9.7 with VS-2008 on WinXP on an EeePC-901.
The Redbook Alpha example from the TaoFramework works ok.

Thanks,
Alex


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
kanato's picture

Try moving the calls to GL.BlendFunc and GL.Enable into the paint event handler.

atsv's picture

Thanks, that helped!
However, is it ok that all GL code (the viewport and enable things) needs to be called on every paint event?
Will there be more code examples for the next release?

the Fiddler's picture

Can you make a little test? Try moving the setup code back to the Load event, but place a call to glControl1.CreateControl() above it. Does it work now?

The idea is that you need an OpenGL context (GraphicsContext) before using any OpenGL function. The GLControl is responsible for creating this context, and it is actually supposed to create it before the parent Form's load event. There may be a bug in the implementation - I'll have to check this code again.

You can place the viewport code in the GLControl.Resize event to ensure it is called whenever the control is resized. Bugs notwithstanding, the rest of the initialization belongs to the Load event. It is generally not a problem to change state (e.g. set up blending) in the Paint event. Imagine, for example, that you have > 1 drawables that require different blend modes. There is no way to avoid changing blend modes inside the Paint handler - this won't be a problem as long as you don't overdo it (i.e. try sorting by blend mode if you have a lot of drawables).

As an aside, you can use the GraphicsContext.CurrentContext property to see whether a context is current (i.e. exists) in the calling thread. If this returns null, it is an error to use any OpenGL functions.

The upcoming release is still focused on core improvements, so I doubt it will contain any new examples. However, it will come with an improved example browser that includes documentation and source code, while existing examples will be cleaned up. There are new examples down the pipeline, but their focus is GLSL: lighting, shadows, cube mapping, reflections, bloom, HDR and things like that.

Is there any specific example you'd like to see?

atsv's picture

Got it about the OpenGL context creation.
Thank you for your work! I'll come up with improvement suggesions/help if I think out some.

carga's picture

I did not succeed with blending, so I feel the topic is a little bit tricky after all. So I'd like to share with you simple straightforward example... (As you may notice looking at class attribute and namespace I even suggest it to be included in official examples... ;-) )

using System;
using System.Drawing;
 
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics.OpenGL;
 
namespace Examples.Tutorial
{
    [Example("Simple Blending", ExampleCategory.OpenTK, "GameWindowBlending", 1, Documentation = "GameWindowSimpleBlending")]
    public class SimpleWindowBlending : GameWindow
    {
		private const double width = 0.1;
 
		private double x1=-0.2;
		private double x2=+0.2;
		private System.Diagnostics.Stopwatch timer = System.Diagnostics.Stopwatch.StartNew();
 
        public SimpleWindowBlending() : base(800, 600)
        {
			Keyboard.KeyRepeat = true;
			Keyboard.KeyDown -= Keyboard_KeyDown;
            Keyboard.KeyDown += Keyboard_KeyDown;
        }
 
        #region Keyboard_KeyDown
 
        /// <summary>
        /// Occurs when a key is pressed.
        /// </summary>
        /// <param name="sender">The KeyboardDevice which generated this event.</param>
        /// <param name="e">The key that was pressed.</param>
        void Keyboard_KeyDown(object sender, KeyboardKeyEventArgs e)
        {
            if (e.Key == Key.Escape)
                this.Exit();
 
            if (e.Key == Key.F11)
                if (this.WindowState == WindowState.Fullscreen)
                    this.WindowState = WindowState.Normal;
                else
                    this.WindowState = WindowState.Fullscreen;
        }
 
        #endregion
 
        protected override void OnLoad(EventArgs e)
        {
            GL.ClearColor(Color.FromArgb(20, Color.LightGray));
			GL.Enable(EnableCap.Blend);
		}
 
        #region OnResize
        protected override void OnResize(EventArgs e)
        {
            GL.Viewport(0, 0, Width, Height);
 
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.Ortho(-1.0, 1.0, -1.0, 1.0, 0.0, 4.0);
        }
        #endregion
 
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            x1 = -0.2 + 0.4*Math.Sin(timer.Elapsed.TotalSeconds);
			x2 = +0.2 - 0.4*Math.Sin(timer.Elapsed.TotalSeconds);
        }
 
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            GL.Clear(ClearBufferMask.ColorBufferBit);
 
            GL.Begin(BeginMode.Quads);
 
            GL.Color4(Color.FromArgb(10, Color.MidnightBlue));
            GL.Vertex2(x1-width, -2*width);
			GL.Vertex2(x1-width, width);
            GL.Vertex2(x1+width, width);
			GL.Vertex2(x1+width, -2*width);
 
            GL.Color4(Color.FromArgb(50, Color.LightPink));
            GL.Vertex2(x2-width, -width);
			GL.Vertex2(x2-width, 2*width);
            GL.Vertex2(x2+width, 2*width);
			GL.Vertex2(x2+width, -width);
 
            GL.End();
 
            this.SwapBuffers();
        }
 
        [STAThread]
        public static void Main()
        {
            using (SimpleWindowBlending example = new SimpleWindowBlending())
            {
                // Get the title and category  of this example using reflection.
                Utilities.SetWindowTitle(example);
                example.Run();
            }
        }
    }
}

What do I see? 2 moving solid rectangles. No blending at all!

What is expected?

  1. Colors of both rectangles are "grayer" than originals (since theirs alphas are very small, both rectangles should be almost transparent in fact).
  2. When overlapped, both pink and blue colors should mix and produce some 3rd color in overlapped region

What methods should be called (and at what places) to produce the result I wish?

Have a fast code!
Anton.
http://kyta.spb.ru

carga's picture

Well, to make it working one have to specify blending function. So OnLoad() function should look like this:

protected override void OnLoad(EventArgs e)
{
       GL.ClearColor(Color.FromArgb(20, Color.LightGray));
       GL.Enable(EnableCap.Blend);
       //GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcColor);
       GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
}

Also in other sample I have made a mistake, trying to specify color with Color3 function like this GL.Color3(Color.FromArgb(50, Color.LightPink));. Predictably enough alpha channel was stripped off the color and no blending had happened.

Have a fast code!
Anton.
http://kyta.spb.ru