package com.brackeen.javagamebook.graphics3D;

import java.awt.*;
import java.awt.image.*;
import com.brackeen.javagamebook.math3D.*;
import com.brackeen.javagamebook.graphics3D.texture.*;

/**
    Klasa ShadedTexturedPolygonRenderer jest podklasą PolygonRenderer
    renderującą dynamicznie teksturę ShadedTexture oświetloną jednym 
    światłem. Domyślnie intensywność światła otoczenia wynosi 0.5 i nie
    ma żadnego światła punktowego.
*/
public class ShadedTexturedPolygonRenderer
    extends FastTexturedPolygonRenderer
{

    private PointLight3D lightSource;
    private float ambientLightIntensity = 0.5f;
    private Vector3D directionToLight = new Vector3D();

    public ShadedTexturedPolygonRenderer(Transform3D camera,
        ViewWindow viewWindow)
    {
        this(camera, viewWindow, true);
    }

    public ShadedTexturedPolygonRenderer(Transform3D camera,
        ViewWindow viewWindow, boolean clearViewEveryFrame)
    {
        super(camera, viewWindow, clearViewEveryFrame);
    }


    /**
        Pobiera punktowe źródło światła dla tego renderera.
    */
    public PointLight3D getLightSource() {
        return lightSource;
    }


    /**
        Ustawia źródło światła dla tego renderera.
    */
    public void setLightSource(PointLight3D lightSource) {
        this.lightSource = lightSource;
    }


    /**
        Pobiera intensywność światła otoczenia.
    */
    public float getAmbientLightIntensity() {
        return ambientLightIntensity;
    }


    /**
        Ustawia intensywność światła otoczenia, zasadniczo między 0 a
        1.
    */
    public void setAmbientLightIntensity(float i) {
        ambientLightIntensity = i;
    }


    protected void drawCurrentPolygon(Graphics2D g) {
        // ustaw poziom cieniowania wielokąta, zanim zaczniesz rysować
        if (sourcePolygon instanceof TexturedPolygon3D) {
            TexturedPolygon3D poly =
                ((TexturedPolygon3D)sourcePolygon);
            Texture texture = poly.getTexture();
            if (texture instanceof ShadedTexture) {
                calcShadeLevel();
            }
        }
        super.drawCurrentPolygon(g);
    }


    /**
        Wylicza poziom cieniowania dla bieżącego wielokąta
    */
    private void calcShadeLevel() {
        TexturedPolygon3D poly = (TexturedPolygon3D)sourcePolygon;
        float intensity = 0;
        if (lightSource != null) {


            // punkt będący średnią z wierzchołków wielokąta
            directionToLight.setTo(0,0,0);
            for (int i=0; i<poly.getNumVertices(); i++) {
                directionToLight.add(poly.getVertex(i));
            }
            directionToLight.divide(poly.getNumVertices());

            // utwórz wektor wychodzący z tak uśrednionego wierzchołka
            // skierowany w kierunku światła
            directionToLight.subtract(lightSource);
            directionToLight.multiply(-1);

            // pobierz odległość od źródła światła dla potrzeb wygaszania
            float distance = directionToLight.length();

            // wylicz odbicie dyfuzyjne 
            directionToLight.normalize();
            Vector3D normal = poly.getNormal();
            intensity = lightSource.getIntensity(distance)
                * directionToLight.getDotProduct(normal);
            intensity = Math.min(intensity, 1);
            intensity = Math.max(intensity, 0);
        }

        intensity+=ambientLightIntensity;
        intensity = Math.min(intensity, 1);
        intensity = Math.max(intensity, 0);
        int level =
            Math.round(intensity*ShadedTexture.MAX_LEVEL);
        ((ShadedTexture)poly.getTexture()).
            setDefaultShadeLevel(level);
    }

}