private static void MakeFontTexture(GR gr)
        {
            byte[] rgbaBuffer = new byte[128 * 128 * 4];


            // fill in buffer with RGBA version of font pixels
            byte val = (byte)0;
            int  k   = 0;

            for (int j = 0; j < 128; j++)
            {
                for (int i = 0; i < 128; i++)
                {
                    k     = 4 * ((128 * (127 - j)) + i);
                    val   = Courier10FontBitmap[(16 * j) + (i >> 3)];
                    val <<= (i & 0x7); // 0..7
                    if (0 != (val & 0x80))
                    {
                        // opaque white
                        rgbaBuffer[k + 0] = 255; // R
                        rgbaBuffer[k + 1] = 255; // G
                        rgbaBuffer[k + 2] = 255; // B
                        rgbaBuffer[k + 3] = 255; // A
                    }
                    else
                    {
                        // transparent
                        rgbaBuffer[k + 0] = 0; // R
                        rgbaBuffer[k + 1] = 0; // G
                        rgbaBuffer[k + 2] = 0; // B
                        rgbaBuffer[k + 3] = 0; // A
                    }
                }
            }


            // create an OpenGL texture and transfer data to the texture
            int[] temp = new int[1];
            gr.glGenTextures(1, temp);
            mFontTextureName = temp[0];
            gr.glBindTexture(GR.GL_TEXTURE_2D, mFontTextureName);

            gr.glTexParameteri(GR.GL_TEXTURE_2D, GR.GL_TEXTURE_MAG_FILTER, GR.GL_NEAREST);
            gr.glTexParameteri(GR.GL_TEXTURE_2D, GR.GL_TEXTURE_MIN_FILTER, GR.GL_NEAREST);
            gr.glTexImage2D(GR.GL_TEXTURE_2D, 0, GR.GL_RGBA, 128, 128, 0, GR.GL_RGBA, GR.GL_UNSIGNED_BYTE, rgbaBuffer);
        }
        Initialize
        (
            GR gr,
            IntPtr hwndParentWindow
        )
        {
            this.Clear( );

            // Cache the GR instance
            this.mGR = gr;


            this.mTextureDataBGR256x256 = new byte[(256 * (256 * 3))];


            this.mSTVideoCapture = new STVideoCapture();

            int capturePeriodMilliseconds = 33; // 33 milliseconds --> 30 frames per second (max)

            // Attempt to initialize video capture
            bool videoCaptureInitializationResult = false;

            videoCaptureInitializationResult =
                this.mSTVideoCapture.Initialize
                (
                    hwndParentWindow,
                    STVideoCapture.STVideoCaptureFormat.BGR320x240,
                    capturePeriodMilliseconds,
                    new STVideoCapture.DelegateClientCaptureCallback(this.ClientCaptureCallback)
                );

            if (false == videoCaptureInitializationResult)
            {
                return(false);
            }



            // Create OpenGL texture object
            int[] temp = new int[1];
            gr.glGenTextures(1, temp);
            this.mTextureOpenGLHandleBGR256x256 = temp[0];


            // Fill the OpenGL texture with initial data
            gr.glBindTexture
            (
                GR.GL_TEXTURE_2D,
                this.mTextureOpenGLHandleBGR256x256
            );

            gr.glTexImage2D
            (
                GR.GL_TEXTURE_2D,
                0,
                3,
                256,
                256,
                0,
                GR.GL_BGR_EXT,
                GR.GL_UNSIGNED_BYTE,
                this.mTextureDataBGR256x256
            );

            // Set texture mapping mode and filtering modes
            gr.glTexParameteri(GR.GL_TEXTURE_2D, GR.GL_TEXTURE_WRAP_S, GR.GL_REPEAT);
            gr.glTexParameteri(GR.GL_TEXTURE_2D, GR.GL_TEXTURE_WRAP_T, GR.GL_REPEAT);

            gr.glTexParameterf(GR.GL_TEXTURE_2D, GR.GL_TEXTURE_MIN_FILTER, GR.GL_LINEAR);
            gr.glTexParameterf(GR.GL_TEXTURE_2D, GR.GL_TEXTURE_MAG_FILTER, GR.GL_LINEAR);


            // deselect the current texture
            gr.glBindTexture(GR.GL_TEXTURE_2D, 0);


            return(true);
        }