<commit_before>﻿using System;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Media.Media3D;
using Color = System.Windows.Media.Color;

namespace csmacnz.Monocle
{
    public class RayTracer
    {
        public static void RenderSection(Rectangle region, Scene scene, SceneOutput output)
        {
            Vector3D directionUnit = (scene.CameraFacingAt - scene.CameraPosition);
            directionUnit.Normalize();

            var pixelHeight = scene.ViewPortHeight / output.Height;
            var pixelWidth = pixelHeight;
            var halfWidth = (output.Width / 2.0);
            var halfHeight = (output.Height / 2.0);

            foreach (var y in Enumerable.Range(region.Y, region.Height))
            {
                foreach (var x in Enumerable.Range(region.X, region.Width))
                {
                    Thread.Sleep(0);
                    Thread.Sleep(0);
                    Thread.Sleep(0);

                    var point = new Vector3D(
                        ((x + 0.5) - halfWidth)*pixelWidth,
                        ((y + 0.5) - halfHeight)*pixelHeight, 0);
                    var direction = point - scene.CameraPosition;
                    direction.Normalize();
                    var pixelColor = RenderPoint(scene, point, direction);
                    output.SetPixel(x, y, pixelColor);

                    Thread.Sleep(0);
                    Thread.Sleep(0);
                    Thread.Sleep(0);
                }
            }
        }

        private static Color RenderPoint(Scene scene, Vector3D renderPoint, Vector3D direction)
        {
            var firstHit = scene.Spheres
                .Select(s=>Tuple.Create(s,s.Test(renderPoint, direction)))
                .Where(h=>h.Item2.HasValue)
                .OrderBy(h=>h.Item2.Value)
                .FirstOrDefault();

            if (firstHit?.Item2 != null)
            {
                var sphere = firstHit.Item1;
                var t = firstHit.Item2.Value;
                var intersectionPoint = renderPoint + direction * t;

                var lighting = scene.AmbientLight * sphere.DiffuseColor;

                var directionToEye = -direction;
                directionToEye.Normalize(); //should be anyway?

                LightStrength additionalLighting = LightStrength.Zero;
                foreach (var light in scene.Lights)
                {
                    additionalLighting += CalculateLighting(scene.Spheres, directionToEye, sphere, intersectionPoint, light);
                }
                return (lighting+ additionalLighting*sphere.DiffuseColor).Clamped().ToColor();

            }

            return scene.DefaultColor;
        }

        private static LightStrength CalculateLighting(Sphere[] spheres, Vector3D directionToEye, Sphere sphere, Vector3D intersectionPoint, Light light)
        {
            var directionToLight = light.CenterPoint - intersectionPoint;
            directionToLight.Normalize();
            var lightT = (light.CenterPoint.X - intersectionPoint.X)/directionToLight.X;
            var blocked = spheres.Any(s => ObscuresLight(s, intersectionPoint, directionToLight, lightT));
            if (blocked)
            {
                return LightStrength.Zero;
            }

            var surfaceNormal = sphere.NormalAt(intersectionPoint);

            var ldotn = Math.Max(0.0,Vector3D.DotProduct(surfaceNormal, directionToLight));
            var diffuse = light.Brightness*ldotn;
            var H = directionToLight + directionToEye;
            H.Normalize();
            var ndoth = Math.Max(0.0,Vector3D.DotProduct(surfaceNormal, H));
            var specular = sphere.SpecularColor*Math.Pow(ndoth, sphere.Shinyness);
            var x = diffuse + specular;
            return x.Clamped();
        }

        private static bool ObscuresLight(Sphere s, Vector3D intersectionPoint, Vector3D directionToLight, double lightT)
        {
            var test = s.Test(intersectionPoint+(directionToLight*0.001), directionToLight);<commit_msg>Adjusted lighting for colour bounding.<commit_after>﻿using System;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Media.Media3D;
using Color = System.Windows.Media.Color;

namespace csmacnz.Monocle
{
    public class RayTracer
    {
        public static void RenderSection(Rectangle region, Scene scene, SceneOutput output)
        {
            Vector3D directionUnit = (scene.CameraFacingAt - scene.CameraPosition);
            directionUnit.Normalize();

            var pixelHeight = scene.ViewPortHeight / output.Height;
            var pixelWidth = pixelHeight;
            var halfWidth = (output.Width / 2.0);
            var halfHeight = (output.Height / 2.0);

            foreach (var y in Enumerable.Range(region.Y, region.Height))
            {
                foreach (var x in Enumerable.Range(region.X, region.Width))
                {
                    Thread.Sleep(0);
                    Thread.Sleep(0);
                    Thread.Sleep(0);

                    var point = new Vector3D(
                        ((x + 0.5) - halfWidth)*pixelWidth,
                        ((y + 0.5) - halfHeight)*pixelHeight, 0);
                    var direction = point - scene.CameraPosition;
                    direction.Normalize();
                    var pixelColor = RenderPoint(scene, point, direction);
                    output.SetPixel(x, y, pixelColor);

                    Thread.Sleep(0);
                    Thread.Sleep(0);
                    Thread.Sleep(0);
                }
            }
        }

        private static Color RenderPoint(Scene scene, Vector3D renderPoint, Vector3D direction)
        {
            var firstHit = scene.Spheres
                .Select(s=>Tuple.Create(s,s.Test(renderPoint, direction)))
                .Where(h=>h.Item2.HasValue)
                .OrderBy(h=>h.Item2.Value)
                .FirstOrDefault();

            if (firstHit?.Item2 != null)
            {
                var sphere = firstHit.Item1;
                var t = firstHit.Item2.Value;
                var intersectionPoint = renderPoint + direction * t;

                var directionToEye = -direction;
                directionToEye.Normalize(); //should be anyway?

                LightStrength additionalLighting = LightStrength.Zero;
                double specular = 0.0;
                foreach (var light in scene.Lights)
                {
                    var lighting = CalculateLighting(scene.Spheres, directionToEye, sphere, intersectionPoint, light);
                    additionalLighting += lighting.Item1;
                    specular += lighting.Item2;
                }
                return (((scene.AmbientLight+ additionalLighting).Clamped() * sphere.DiffuseColor)+(Math.Min(1.0,specular)*sphere.SpecularColor)).ToColor();

            }

            return scene.DefaultColor;
        }

        private static Tuple<LightStrength, double> CalculateLighting(Sphere[] spheres, Vector3D directionToEye, Sphere sphere, Vector3D intersectionPoint, Light light)
        {
            var directionToLight = light.CenterPoint - intersectionPoint;
            directionToLight.Normalize();
            var lightT = (light.CenterPoint.X - intersectionPoint.X)/directionToLight.X;
            var blocked = spheres.Any(s => ObscuresLight(s, intersectionPoint, directionToLight, lightT));
            if (blocked)
            {
                return Tuple.Create(LightStrength.Zero,0.0);
            }

            var surfaceNormal = sphere.NormalAt(intersectionPoint);

            var ldotn = Math.Max(0.0,Vector3D.DotProduct(surfaceNormal, directionToLight));
            var diffuse = light.Brightness*ldotn;
            var H = directionToLight + directionToEye;
            H.Normalize();
            var ndoth = Math.Max(0.0,Vector3D.DotProduct(surfaceNormal, H));
            var specular = Math.Pow(ndoth, sphere.Shinyness);
            return Tuple.Create(diffuse, specular);
        }

        private static bool ObscuresLight(Sphere s, Vector3D intersectionPoint, Vector3D directionToLight, double lightT)
        {
            var test = s.Test(intersectionPoint+(directionToLight*0.001), directionToLight);
{'fraction_non_alphanumeric': 0.09204970442755459, 'fraction_numerical': 0.010375196042948487, 'mean_word_length': 1.7912457912457913, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4101285', 'n_tokens_mistral': 2240, 'n_tokens_neox': 2072, 'n_words': 460}