package traci.render;

import traci.math.Vector;
import traci.model.Scene;
import traci.model.light.PointLight;
import traci.model.material.Color;
import traci.model.material.Finish;
import traci.model.material.pigment.Pigment;
import traci.model.shape.primitive.Primitive;

public class Raytrace
{
    protected static Color raytrace(final Scene scene, final int depth, final Vector p, final Vector dir)
    {
        final Ray ray = scene.rootShape.shootRay(p, dir);

        if (ray == null)
        {
            return scene.backgroundColor;
        }

        final Point hit = ray.first();

        if (hit == null)
        {
            return scene.backgroundColor;
        }

        final double dist = hit.dist;
        final Primitive obj = hit.obj;

        final Vector hitPoint = p.add(dir.mul(dist));
        final Vector normal = obj.getNormalAt(hitPoint, dir);

        final Pigment pigment = obj.getMaterial().texture.pigment;
        final Finish finish = obj.getMaterial().texture.finish;

        final Color hitPointColor = pigment.getColor(hitPoint);

        /**
         * Ambient light
         */
        Color colorTotal;
        if (scene.ambientLight != null)
        {
            colorTotal = hitPointColor.mul(scene.ambientLight.color);
        }
        else
        {
            colorTotal = Color.BLACK;
        }

        for (final PointLight light : scene.pointLights)
        {
            final Vector toLight = light.location.sub(hitPoint);
            final Vector dirToLight = toLight.normalize();

            final Ray lightRay2 = scene.rootShape.shootRay(hitPoint, dirToLight);
            if (lightRay2 != null && lightRay2.first() != null)
            {
                continue;
            }

            final double distToLight = toLight.length();
            final double distCoeff = 1.0 / (distToLight * distToLight);
            final Color lightAtPoint = light.color.mul(distCoeff);

            /**
             * Diffuse light
             */
            final double c = Math.max(dirToLight.dot(normal), 0.0);
            final Color colorDiff = hitPointColor.mul(lightAtPoint.mul(c * finish.diffCoeff));

            colorTotal = colorTotal.add(colorDiff);

            /**
             * Specular light
             */
            final Vector lightRef = normal.mul(normal.mul(2).dot(dirToLight)).sub(dirToLight);
            final double cosTheta = -lightRef.dot(dir);

            if (cosTheta > 0)
            {
                final double shininess = finish.shininess;
                final double specCoeff = finish.specCoeff;

                final Color colorSpec = light.color.mul(Math.pow(cosTheta, shininess) * specCoeff * distCoeff);
                colorTotal = colorTotal.add(colorSpec);
            }
        }

        /**
         * Reflection
         */
        if (depth > 0)
        {
            final Vector rr = dir.sub(normal.mul(dir.mul(2).dot(normal)));
            final Color colorReflect = raytrace(scene, depth - 1, hitPoint, rr.normalize());
            colorTotal = colorTotal.add(colorReflect.mul(finish.reflectiveness));
        }

        return colorTotal;
    }
}

@@ -1556,156 +1556,445 @@
     
-final Ray lightRay2 = scene.rootShape.shootRay(hitPoint, dirToLight);%0A            if (lightRay2 != null && lightRay2.first() != null)%0A            %7B%0A
+/**%0A             * Check if path to light is obstructed%0A             */%0A            final Ray lightRay2 = scene.rootShape.shootRay(hitPoint, dirToLight);%0A            final double distToLight = toLight.length();%0A            if (lightRay2 != null)%0A            %7B%0A                final Point pp = lightRay2.first();%0A                if (pp != null && pp.dist %3C distToLight)%0A                %7B%0A                    /* Light is obstructed */%0A    
     
@@ -2031,23 +2031,22 @@
     
-%7D%0A%0A
     
+%7D%0A
         
 fina
@@ -2045,52 +2045,14 @@
     
-final double distToLight = toLight.length();
+    %7D%0A
 %0A   

Fix bug in light detection.