Beispiel #1
0
        public PlayerAvatarElement(float x, float y, string playerUsername, int avatarIndex, LabelStyle labelStyle, Action onClick = null, float spriteSize = 128f)
            : base(Mathf.Ceiling(spriteSize), Mathf.Ceiling(spriteSize) * 2)
        {
            bounds = new Rectangle(x, y, spriteSize, spriteSize * 2f);
            this.playerUsername = playerUsername;
            this.onClick       += onClick;
            this.labelStyle     = labelStyle;

            var playerAvatarPath = "data/sprites/avatars/";

            if (avatarIndex < 5)
            {
                playerAvatarPath += $"female_{avatarIndex + 1}_";
            }
            else
            {
                playerAvatarPath += $"male_{avatarIndex - 4}_";
            }
            if (Math.Abs(spriteSize - 128f) < 0.00001f)
            {
                playerAvatarPath += "128.png";
            }
            else
            {
                playerAvatarPath += "64.png";
            }
            playerAvatar = new game.Sprite(playerAvatarPath, true, false);
            SetXY(x, y);
            Draw();
        }
        string WrappedText(out int numOfLines)
        {
            float w = _easy.TextWidth(_text);

            numOfLines = Mathf.Ceiling(w / (_easy.width - 2 * _paddingX));

            string[]      words = _text.Split(' ');
            List <string> lines = new List <string>();

            string line = "";

            for (int i = 0; i < words.Length; i++)
            {
                string tempLine = line + words[i];
                w = _easy.TextWidth(tempLine);

                if (w > (_easy.width - 2 * _paddingX))
                {
                    lines.Add(line.Trim());
                    line = words[i] + " ";
                }
                else
                {
                    line += words[i] + " ";
                }
            }

            if (!string.IsNullOrWhiteSpace(line))
            {
                lines.Add(line);
            }

            return(string.Join(Environment.NewLine, lines));
        }
Beispiel #3
0
        // Starts a transfer of raw data from the host to a device buffer
        public unsafe static void PushBuffer(byte *src, uint length, Vk.Buffer dst, uint dstOffset)
        {
            // Calculate transfer information
            uint blockCount = (uint)Mathf.Ceiling(length / (float)DEFAULT_BUFFER_SIZE);

            // Iterate over the transfer blocks
            for (uint bidx = 0; bidx < blockCount; ++bidx)
            {
                // Calculate offsets and block sizes
                uint  blockOff      = bidx * DEFAULT_BUFFER_SIZE;
                byte *currSrc       = src + blockOff;
                uint  currDstOffset = dstOffset + blockOff;
                uint  currLength    = Math.Min(length - blockOff, DEFAULT_BUFFER_SIZE);

                // Wait on the previous transfer
                s_pushFence.Wait();
                s_pushFence.Reset();

                // Map the staging buffer, and copy the memory
                IntPtr mapped = s_pushMemory.Map(0, currLength);
                System.Buffer.MemoryCopy(currSrc, mapped.ToPointer(), currLength, currLength);
                s_pushMemory.Unmap();

                // Start recording
                s_pushCommands.Begin(ONE_TIME_SUBMIT_INFO);

                // Add the transfer command
                Vk.BufferCopy bc = new Vk.BufferCopy(currLength, 0, currDstOffset);
                s_pushCommands.CmdCopyBuffer(s_pushBuffer, dst, bc);

                // End recording, and submit
                s_pushCommands.End();
                s_queue.Submit(s_pushSubmitInfo, fence: s_pushFence);
            }
        }
Beispiel #4
0
 public Label(float x, float y, float width, float height, string labelText, LabelStyle labelStyle)
     : base(Mathf.Ceiling(width), Mathf.Ceiling(height), false)
 {
     bounds          = new Rectangle(x, y, width, height);
     LabelText       = labelText;
     this.labelStyle = labelStyle;
     Draw();
     SetXY(x, y);
 }
Beispiel #5
0
 public RectangleElement(float x, float y, float width, float height, Color fillColor, Color strokeColor, float strokeWeight)
     : base(Mathf.Ceiling(width), Mathf.Ceiling(height), false)
 {
     bounds            = new Rectangle(x, y, width, height);
     this.FillColor    = fillColor;
     this.strokeColor  = strokeColor;
     this.strokeWeight = strokeWeight;
     SetXY(x, y);
     Draw();
 }
Beispiel #6
0
        /// <summary>
        /// Uploads general structured data into the buffer on the graphics card.
        /// </summary>
        /// <typeparam name="T">The type of the source data.</typeparam>
        /// <param name="data">The data to upload.</param>
        /// <param name="length">
        /// The length of the source data to copy, in <typeparamref name="T"/>s. A value of <see cref="UInt32.MaxValue"/>
        /// will auto-calculate the proper length to fill the buffer, taking into account the offset into the buffer.
        /// </param>
        /// <param name="srcOffset">The optional offset into the source data, in <typeparamref name="T"/>s.</param>
        /// <param name="dstOffset">The optional offset into the buffer, in <typeparamref name="T"/>s.</param>
        public void SetData <T>(T[] data, uint length = UInt32.MaxValue, uint srcOffset = 0, uint dstOffset = 0)
            where T : struct
        {
            uint typeSize = (uint)Marshal.SizeOf <T>();

            if (length == UInt32.MaxValue)
            {
                length = (uint)Mathf.Ceiling((Size - dstOffset) / (float)typeSize);
            }

            SetDataInternal(data, length, srcOffset, dstOffset * typeSize);
        }
Beispiel #7
0
        IEnumerator SpawnBullets()
        {
            while (true)
            {
                // wait
                float delay = Mathf.Ceiling(0.5f - _elapsedTime * 0.01f);
                yield return(Delay(delay));

                // spawn bullet
                float    PADDING   = 10.0f;
                Vector2f bulletPos = new Vector2f(Mathf.Random(PADDING, Graphics.Width - PADDING), Graphics.Height + PADDING);
                AddBullet(bulletPos, false);
            }
        }
        public Button(float x, float y, float width, float height, string buttonText, ButtonStyle buttonStyle, Action onClick = null, Action onMouseEnter = null, Action onMouseLeave = null, Action onMousePress = null, Action onMouseRelease = null)
            : base(Mathf.Ceiling(width), Mathf.Ceiling(height), false)
        {
            bounds           = new Rectangle(x, y, width, height);
            ButtonText       = buttonText;
            this.buttonStyle = buttonStyle;

            OnClick        += onClick;
            OnMouseEnter   += onMouseEnter;
            OnMouseLeave   += onMouseLeave;
            OnMousePress   += onMousePress;
            OnMouseRelease += onMouseRelease;

            SetXY(x, y);
            Draw();
        }
        //--------------------------------------------------------------------------------------------
        // REGION: public static utility methods, related to creating and placing GXPEngine objects
        // based on data from Tiled Objects.
        //--------------------------------------------------------------------------------------------

        /// <summary>
        /// Creates an EasyDraw for displaying text, based on the configuration parameters of a
        /// Tiled object. (Including font, text alignment, color)
        /// </summary>
        /// <param name="obj">The Tiled (text) object</param>
        /// <returns></returns>
        public static EasyDraw CreateTextField(TiledObject obj, bool addCollider = true, bool highQualityText = true)
        {
            float    scaleMultiplier = highQualityText ? 2 : 1;          // 1=as is. 2=better antialiasing, but 4 x size
            EasyDraw message         = new EasyDraw((int)Mathf.Ceiling(obj.Width * scaleMultiplier), (int)Mathf.Ceiling(obj.Height * scaleMultiplier), addCollider);
            // TODO: Cache fonts?

            // Set Font:
            FontStyle f = FontStyle.Regular;

            if (obj.textField.bold == 1 && obj.textField.italic == 1)
            {
                f = FontStyle.Bold | FontStyle.Italic;
            }
            else if (obj.textField.bold == 0 && obj.textField.italic == 1)
            {
                f = FontStyle.Italic;
            }
            else if (obj.textField.bold == 1 && obj.textField.italic == 0)
            {
                f = FontStyle.Bold;
            }
            message.TextFont(new Font(obj.textField.font, Mathf.Round(obj.textField.fontSize * scaleMultiplier), f, GraphicsUnit.Pixel));
            message.graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;             //AntiAlias;

            // Set text alignment:
            message.TextAlign(
                obj.textField.horizontalAlign == "left" ? CenterMode.Min : (obj.textField.horizontalAlign == "right" ? CenterMode.Max : CenterMode.Center),
                obj.textField.verticalAlign == "top" ? CenterMode.Min : (obj.textField.verticalAlign == "bottom" ? CenterMode.Max : CenterMode.Center)
                );

            // Set color:
            uint col = obj.textField.Color;

            message.Fill(Color.FromArgb((int)(col & 255), (int)((col >> 24) & 255), (int)((col >> 16) & 255), (int)((col >> 8) & 255)), (int)(col & 255));

            return(message);
        }
Beispiel #10
0
    private Brush GetHealthBrushColor()
    {
        // more than 75% and lower or equal than 100%;
        if (_player.GetHealth() > (Mathf.Ceiling(Convert.ToSingle(_player.GetMaxHealth()) / 100 * 75)) && _player.GetHealth() <= _player.GetMaxHealth())
        {
            _healthBrushColor = Brushes.Green;


            // more or equal than 25% and less than 75%
        }
        else if (_player.GetHealth() > (Mathf.Ceiling(Convert.ToSingle(_player.GetMaxHealth()) / 100 * 25)) && _player.GetHealth() <= (Mathf.Floor(Convert.ToSingle(_player.GetMaxHealth()) / 100 * 75)))
        {
            _healthBrushColor = Brushes.OrangeRed;
            _playerInfo.graphics.DrawImage(Image.FromFile("assets\\faces\\face2.png"), 15, 15, 100, 100);

            // more or equal than 0% and less than 25%
        }
        else if (_player.GetHealth() >= (Convert.ToSingle(_player.GetMaxHealth()) - _player.GetMaxHealth()) && _player.GetHealth() <= (Mathf.Floor(Convert.ToSingle(_player.GetMaxHealth()) / 100 * 25)))
        {
            _healthBrushColor = Brushes.Red;
            _playerInfo.graphics.DrawImage(Image.FromFile("assets\\faces\\face3.png"), 15, 15, 100, 100);
        }
        return(_healthBrushColor);
    }
Beispiel #11
0
        void    BuildFont()
        {
            string charSet = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~éèêëôöàçÔÖÂÊÉœûüù";

            m_fontRectangles = new Rectangle[charSet.Length];
            for (int charIndex = 0; charIndex < charSet.Length; charIndex++)
            {
                char C     = charSet[charIndex];
                int  index = (int)C;
                m_char2Index[index] = charIndex;
            }

#if BUILD_FONTS
            using (Font F = new Font(this.Font.FontFamily, 36.0f)) {
                // Build small bitmap and write each character
                int width     = 0;
                int maxheight = 0;
                using (Bitmap B = new Bitmap(70, 70, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) {
                    using (Graphics G = Graphics.FromImage(B)) {
                        for (int i = 0; i < charSet.Length; i++)
                        {
                            string s = charSet.Substring(i, 1);
//                          G.FillRectangle( Brushes.Black, 0, 0, B.Width, B.Height );
//                          G.DrawString( s, F, Brushes.White, new PointF( 0, 0 ) );

                            SizeF tempSize = G.MeasureString(s, F);
                            m_fontRectangles[i] = new Rectangle(width, 0, (int)Mathf.Ceiling(tempSize.Width), (int)Mathf.Ceiling(tempSize.Height));
                            if (m_fontRectangles[i].Width > B.Width || m_fontRectangles[i].Height > B.Height)
                            {
                                throw new Exception("Fonts are too big, expand bitmap size or reduce font size!");
                            }

                            width    += m_fontRectangles[i].Width;
                            maxheight = Math.Max(maxheight, m_fontRectangles[i].Height);
                        }
                    }
                }

                // Build the final bitmap
                using (Bitmap B = new Bitmap(width, maxheight, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) {
                    using (Graphics G = Graphics.FromImage(B)) {
                        G.FillRectangle(Brushes.Black, 0, 0, B.Width, B.Height);

                        for (int i = 0; i < charSet.Length; i++)
                        {
                            string s = charSet.Substring(i, 1);
                            G.DrawString(s, F, Brushes.White, new PointF(m_fontRectangles[i].X, m_fontRectangles[i].Y));
                        }

                        using (ImageUtility.ImageFile file = new ImageUtility.ImageFile(B, new ImageUtility.ColorProfile(ImageUtility.ColorProfile.STANDARD_PROFILE.sRGB))) {
                            file.Save(new FileInfo("Atlas.png"), ImageUtility.ImageFile.FILE_FORMAT.PNG);
                        }
                    }
                }
            }

            // Write char sizes
            using (FileStream S = new FileInfo("Atlas.rect").Create())
                using (BinaryWriter W = new BinaryWriter(S)) {
                    for (int i = 0; i < m_fontRectangles.Length; i++)
                    {
                        W.Write(m_fontRectangles[i].X);
                        W.Write(m_fontRectangles[i].Y);
                        W.Write(m_fontRectangles[i].Width);
                        W.Write(m_fontRectangles[i].Height);
                    }
                }
#endif

            // Load atlas & rectangles
            using (ImageUtility.ImageFile file = new ImageUtility.ImageFile(new FileInfo("Atlas.png"))) {
                ImageUtility.ImageFile file2 = new ImageUtility.ImageFile(file, ImageUtility.PIXEL_FORMAT.RGBA8);
                using (ImageUtility.ImagesMatrix M = new ImageUtility.ImagesMatrix(file2, ImageUtility.ImagesMatrix.IMAGE_TYPE.sRGB)) {
                    m_tex_FontAtlas = new Texture2D(m_device, M, ImageUtility.COMPONENT_FORMAT.UNORM_sRGB);
                }
            }

            using (FileStream S = new FileInfo("Atlas.rect").OpenRead())
                using (BinaryReader R = new BinaryReader(S)) {
                    // Read both CPU and GPU versions
                    float recW = 1.0f / m_tex_FontAtlas.Width;
                    float recH = 1.0f / m_tex_FontAtlas.Height;
                    using (PixelsBuffer content = new PixelsBuffer((uint)(16 * m_fontRectangles.Length))) {
                        using (BinaryWriter W = content.OpenStreamWrite()) {
                            for (int i = 0; i < m_fontRectangles.Length; i++)
                            {
                                m_fontRectangles[i].X      = R.ReadInt32();
                                m_fontRectangles[i].Y      = R.ReadInt32();
                                m_fontRectangles[i].Width  = R.ReadInt32();
                                m_fontRectangles[i].Height = R.ReadInt32();

                                W.Write(recW * (float)m_fontRectangles[i].X);
                                W.Write(recH * (float)m_fontRectangles[i].Y);
                                W.Write(recW * (float)m_fontRectangles[i].Width);
                                W.Write(recH * (float)m_fontRectangles[i].Height);
                            }
                        }

                        m_tex_FontRectangle = new Texture2D(m_device, (uint)m_fontRectangles.Length, 1, 1, 1, ImageUtility.PIXEL_FORMAT.RGBA32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content });
                    }
                }
        }
Beispiel #12
0
        private void buttonStepSimulation_Click(object sender, EventArgs e)
        {
            if (m_simulationIteration < 0)
            {
                buttonResetSimulation_Click(sender, e);
            }

            m_simulationIteration++;

            if (radioButtonSearchAlgo0.Checked)
            {
                //////////////////////////////////////////////////////////////////////////
                // Local search: Select second highest value from last search position
                float largestValue = 0.0f;
                float secondLargestValue = 0.0f;
                int   sX = m_simulationX, sY = m_simulationY;
                int   X = m_simulationX, Y = m_simulationY;

                for (int i = 0; i < 8; i++)
                {
                    int tempX = m_simulationX + dXY[i][0];
                    int tempY = m_simulationY + dXY[i][1];
                    if (tempX < 0 || tempX >= GRAPH_SIZE)
                    {
                        continue;
                    }
                    if (tempY < 0 || tempY >= GRAPH_SIZE)
                    {
                        continue;
                    }
                    if (m_visited[tempX, tempY])
                    {
                        continue;                               // Already visited
                    }
                    float value = m_bufferHeat[tempX, tempY].x;
                    if (value <= largestValue)
                    {
                        continue;
                    }

                    sX = X; sY = Y;
                    secondLargestValue = largestValue;
                    X            = tempX; Y = tempY;
                    largestValue = value;
                }

//sX = X; sY = Y;

                // Write a single pixel
                m_bufferSearchResults[sX, sY] = 0x000000FFU;
                m_visited[sX, sY]             = true;
                m_visited[X, Y] = true; // Also mark maximum as visited to avoid getting trapped

                m_simulationX = sX;
                m_simulationY = sY;
            }
            else if (radioButtonSearchAlgo1.Checked)
            {
                //////////////////////////////////////////////////////////////////////////
                // Global search: the search radius is increased and we examine all pixels within the radius and select the one with the highest value
                m_simulationRadius += 1.0f;

                Point center = m_simulationHotSpots[integerTrackbarControlStartPosition.Value];

                // Walk the circle and find the largest value
                float largestValue = 0.0f;
                int   X = 0, Y = 0;
                uint  pixelsCount = (uint)Mathf.Ceiling(Mathf.TWOPI * m_simulationRadius);
                for (uint pixelIndex = 0; pixelIndex < pixelsCount; pixelIndex++)
                {
                    float angle = pixelIndex * Mathf.TWOPI / pixelsCount;
                    int   tempX = center.X + (int)Mathf.Floor(m_simulationRadius * Mathf.Cos(angle));
                    int   tempY = center.Y + (int)Mathf.Floor(m_simulationRadius * Mathf.Sin(angle));
                    if (tempX < 0 || tempX >= GRAPH_SIZE)
                    {
                        continue;
                    }
                    if (tempY < 0 || tempY >= GRAPH_SIZE)
                    {
                        continue;
                    }

                    float heat = m_bufferHeat[tempX, tempY].x;
                    if (heat <= largestValue)
                    {
                        continue;
                    }

                    largestValue = heat;
                    X            = tempX;
                    Y            = tempY;
                }

                // Write a single pixel
                m_bufferSearchResults[X, Y] = 0x000000FFU;
            }

            // Update search results texture
            if (sender != null)
            {
                UpdateSearchResults();
            }
        }
 public Image(float x, float y, float width, float height, Sprite image) : base(Mathf.Ceiling(width), Mathf.Ceiling(height), false)
 {
     bounds    = new Rectangle(x, y, width, height);
     useSprite = true;
     sprite    = image;
     Draw();
     SetXY(x, y);
 }
 /// <summary>
 /// Gets the size of the format in terms of binding slots in a shader.
 /// </summary>
 /// <param name="fmt">The format to get the size for.</param>
 /// <param name="arrSize">The number of elements in the array, if the type is an array.</param>
 /// <returns>The size of the format, in shader binding slots.</returns>
 /// <remarks>A shader binding slot is 16 bytes on basically all hardware.</remarks>
 public static uint GetBindingSize(this VertexElementFormat fmt, uint arrSize = 1) => (uint)Mathf.Ceiling(GetSize(fmt, arrSize) / 16.0f);
Beispiel #15
0
        public void             Compute(uint _X, uint _Y)
        {
            float2 __Position     = new float2(0.5f + _X, 0.5f + _Y);
            float2 UV             = __Position / m_resolution;
            uint   pixelPositionX = (uint)Mathf.Floor(__Position.x);
            uint   pixelPositionY = (uint)Mathf.Floor(__Position.y);
            float  noise          = 0.0f;    //_tex_blueNoise[pixelPosition & 0x3F];


//PerformIntegrationTest();


            // Setup camera ray
            float3 csView     = BuildCameraRay(UV);
            float  Z2Distance = csView.Length;

            csView /= Z2Distance;
            float3 wsView = (new float4(csView, 0.0f) * m_camera2World).xyz;

            // Read back depth, normal & central radiance value from last frame
            float Z = FetchDepth(__Position, 0.0f);

            Z -= 1e-2f;                 // Prevent acnea by offseting the central depth closer

//			float	distance = Z * Z2Distance;
            float3 wsNormal = m_arrayNormal[0][pixelPositionX, pixelPositionY].xyz.Normalized;

            // Read back last frame's radiance value that we always can use as a default for neighbor areas
            float3 centralRadiance = m_arrayIrradiance[0][pixelPositionX, pixelPositionY].xyz;

            // Compute local camera-space
            float3 wsPos   = m_camera2World[3].xyz + Z * Z2Distance * wsView;
            float3 wsRight = wsView.Cross(m_camera2World[1].xyz).Normalized;
            float3 wsUp    = wsRight.Cross(wsView);
            float3 wsAt    = -wsView;

            float4x4 localCamera2World = new float4x4(new float4(wsRight, 0), new float4(wsUp, 0), new float4(wsAt, 0), new float4(wsPos, 1));

            // Compute local camera-space normal
            float3 N = new float3(wsNormal.Dot(wsRight), wsNormal.Dot(wsUp), wsNormal.Dot(wsAt));

            N.z = Math.Max(1e-4f, N.z);                                 // Make sure it's never 0!

//			float3	T, B;
//			BuildOrthonormalBasis( N, T, B );

            // Compute screen radius of gather sphere
            float screenSize_m        = 2.0f * Z * TAN_HALF_FOV;        // Vertical size of the screen in meters when extended to distance Z
            float sphereRadius_pixels = m_resolution.y * m_gatherSphereMaxRadius_m / screenSize_m;

            sphereRadius_pixels = Mathf.Min(GATHER_SPHERE_MAX_RADIUS_P, sphereRadius_pixels);                                                           // Prevent it to grow larger than our fixed limit
            float radiusStepSize_pixels = Mathf.Max(1.0f, sphereRadius_pixels / MAX_SAMPLES);                                                           // This gives us our radial step size in pixels
            uint  samplesCount          = Mathf.Clamp((uint)Mathf.Ceiling(sphereRadius_pixels / radiusStepSize_pixels), 1, MAX_SAMPLES);                // Reduce samples count if possible
            float radiusStepSize_meters = sphereRadius_pixels * screenSize_m / (samplesCount * m_resolution.y);                                         // This gives us our radial step size in meters

            // Start gathering radiance and bent normal by subdividing the screen-space disk around our pixel into Z slices
            float4 GATHER_DEBUG        = float4.Zero;
            float3 sumIrradiance       = float3.Zero;
            float3 csAverageBentNormal = float3.Zero;
//          float	averageConeAngle = 0.0f;
//          float	varianceConeAngle = 0.0f;
            float sumAO = 0.0f;

            for (uint angleIndex = 0; angleIndex < MAX_ANGLES; angleIndex++)
            {
                float phi = (angleIndex + noise) * Mathf.PI / MAX_ANGLES;

//phi = 0.0f;

                float2 csDirection;
                csDirection.x = Mathf.Cos(phi);
                csDirection.y = Mathf.Sin(phi);

                // Gather irradiance and average cone direction for that slice
                float3 csBentNormal;
                float2 coneAngles;
                float  AO;
                sumIrradiance += GatherIrradiance(csDirection, localCamera2World, N, radiusStepSize_meters, samplesCount, Z, centralRadiance, out csBentNormal, out coneAngles, out AO, ref GATHER_DEBUG);

// if ( AO < -0.01f || AO > 1.01f )
//  throw new Exception( "MERDE!" );

                csAverageBentNormal += csBentNormal;
                sumAO += AO;

//              // We're using running variance computation from https://www.johndcook.com/blog/standard_deviation/
//              //	Avg(N) = Avg(N-1) + [V(N) - Avg(N-1)] / N
//              //	S(N) = S(N-1) + [V(N) - Avg(N-1)] * [V(N) - Avg(N)]
//              // And variance = S(finalN) / (finalN-1)
//              //
//              float	previousAverageConeAngle = averageConeAngle;
//              averageConeAngle += (coneAngles.x - averageConeAngle) / (2*angleIndex+1);
//              varianceConeAngle += (coneAngles.x - previousAverageConeAngle) * (coneAngles.x - averageConeAngle);
//
//              previousAverageConeAngle = averageConeAngle;
//              averageConeAngle += (coneAngles.y - averageConeAngle) / (2*angleIndex+2);
//              varianceConeAngle += (coneAngles.y - previousAverageConeAngle) * (coneAngles.y - averageConeAngle);
            }

            // Finalize bent cone & irradiance
            csAverageBentNormal = csAverageBentNormal.Normalized;

//csAverageBentNormal *= Mathf.PI / MAX_ANGLES;

            sumIrradiance *= Mathf.PI / MAX_ANGLES;

//          varianceConeAngle /= 2.0f*MAX_ANGLES - 1.0f;
//          float	stdDeviation = Mathf.Sqrt( varianceConeAngle );

            sumAO /= 2.0f * MAX_ANGLES;
//if ( sumAO < 0.0f || sumAO > 1.0f )
//	throw new Exception( "MERDE!" );

            float averageConeAngle  = Mathf.Acos(1.0f - sumAO);
            float varianceConeAngle = 0.0f;                     // Unfortunately, we don't have a proper value for the variance anymore... :'(
            float stdDeviation      = Mathf.Sqrt(varianceConeAngle);

            sumIrradiance.Max(float3.Zero);

            //////////////////////////////////////////////////////////////////////////
            // Finalize results
            m_sumIrradiance = new float4(sumIrradiance, 0);
            m_bentCone      = new float4(Mathf.Max(0.01f, Mathf.Cos(averageConeAngle)) * csAverageBentNormal, 1.0f - stdDeviation / (0.5f * Mathf.PI));


            float3 DEBUG_VALUE = new float3(1, 0, 1);

            DEBUG_VALUE = csAverageBentNormal;
            DEBUG_VALUE = csAverageBentNormal.x * wsRight - csAverageBentNormal.y * wsUp - csAverageBentNormal.z * wsAt; // World-space normal
//DEBUG_VALUE = cos( averageConeAngle );
//DEBUG_VALUE = dot( ssAverageBentNormal, N );
//DEBUG_VALUE = 0.01 * Z;
//DEBUG_VALUE = sphereRadius_pixels / GATHER_SPHERE_MAX_RADIUS_P;
//DEBUG_VALUE = 0.1 * (radiusStepSize_pixels-1);
//DEBUG_VALUE = 0.5 * float(samplesCount) / MAX_SAMPLES;
//DEBUG_VALUE = varianceConeAngle;
//DEBUG_VALUE = stdDeviation;
//DEBUG_VALUE = float3( GATHER_DEBUG.xy, 0 );
//DEBUG_VALUE = float3( GATHER_DEBUG.zw, 0 );
            DEBUG_VALUE = GATHER_DEBUG.xyz;
//DEBUG_VALUE = N;
//m_bentCone = float4( DEBUG_VALUE, 1 );

            //////////////////////////////////////////////////////////////////////////
            // Finalize bent code debug info
            m_wsConePosition  = wsPos;
            m_wsConeDirection = csAverageBentNormal.x * wsRight + csAverageBentNormal.y * wsUp + csAverageBentNormal.z * wsAt;
//m_wsConeDirection = wsNormal;
            m_averageConeAngle = averageConeAngle;
            m_stdDeviation     = stdDeviation;
        }