float ReadRedAverage(HemicubeFramebuffer fbo)
        {
            TextureGL texture = framebuffer[(int)fbo][FramebufferAttachment.ColorAttachment0];

            texture.GenerateMipmap();

            // TODO AccessViolatonException
            bool found = false;

            while (
                (found == false) &&
                (smallestMipmapLevel >= 0)
                )
            {
                try
                {
                    framebuffer[(int)fbo].AttachTextureLevel(FramebufferAttachment.ColorAttachment0, smallestMipmapLevel);
                    found = true;
                }
                catch (Exception)
                {
                    System.Diagnostics.Trace.TraceWarning("TODO");
                    --smallestMipmapLevel;
                }
                if (smallestMipmapLevel == -1)
                {
                    System.Diagnostics.Trace.TraceWarning("TODO");
                    return(0);
                }
            }
            float[] pixels = new float[4];
            float[] depths = new float[4];
            GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
            GL.ReadPixels <float>(0, 0, 1, 1, PixelFormat.Red, PixelType.Float, pixels);
            framebuffer[(int)fbo].AttachTextureLevel(FramebufferAttachment.ColorAttachment0, 0);

            return(pixels[0]);
        }
        private void Render(
            HemicubeFramebuffer fbo,
            HemicubeOrientation orientation,
            Matrix4 cameraRotation,
            Vector3 positionInWorld
            )
        {
            //  Select and activate framebuffer
            framebuffer[(int)fbo].Begin();
            framebuffer[(int)fbo].Check();

            //  Set camera orientation
            int     i            = (int)orientation;
            Matrix4 localToWorld = cameraRotation * faceOrientation[i];

            localToWorld._03       = positionInWorld.X;
            localToWorld._13       = positionInWorld.Y;
            localToWorld._23       = positionInWorld.Z;
            camera[i].Frame.Parent = null;
            camera[i].Frame.LocalToParent.Set(localToWorld);
            camera[i].Frame.LocalToWorld.Set(localToWorld);
            renderer.Requested.Camera = camera[i];
            //camera[i].Frame.UpdateHierarchical();

            //  Set viewport
            renderer.Requested.Viewport = viewport[i];
#if false
            switch (i)
            {
            case (int)HemicubeOrientation.PosX: GL.ClearColor(1.0f, 0.5f, 0.5f, 1.0f); break;     // red

            case (int)HemicubeOrientation.NegX: GL.ClearColor(1.0f, 1.0f, 0.5f, 1.0f); break;     // yellow

            case (int)HemicubeOrientation.PosY: GL.ClearColor(0.5f, 1.0f, 0.5f, 1.0f); break;     // green

            case (int)HemicubeOrientation.NegY: GL.ClearColor(0.5f, 1.0f, 1.0f, 1.0f); break;     // cyan

            case (int)HemicubeOrientation.NegZ: GL.ClearColor(0.5f, 0.5f, 1.0f, 1.0f); break;     // blue
            }
#endif
            GL.Scissor(
                (int)renderer.Requested.Viewport.X,
                (int)renderer.Requested.Viewport.Y,
                (int)renderer.Requested.Viewport.Width,
                (int)renderer.Requested.Viewport.Height
                );
            GL.Enable(EnableCap.ScissorTest);
            GL.Viewport(
                (int)renderer.Requested.Viewport.X,
                (int)renderer.Requested.Viewport.Y,
                (int)renderer.Requested.Viewport.Width,
                (int)renderer.Requested.Viewport.Height
                );

            //  Clear and render
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.Disable(EnableCap.ScissorTest);

            renderer.Requested.Material = MaterialOverride;
            //renderer.Requested.Program  = ProgramOverride;
            renderer.Requested.MeshMode = MeshMode.PolygonFill;
            renderer.RenderGroup();

            framebuffer[(int)fbo].End();
        }