package framework.view3D;

import javax.media.j3d.Appearance;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.TexCoordGeneration;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.TextureCubeMap;
import javax.media.j3d.TextureUnitState;

import framework.model3D.BackgroundBox;
import framework.model3D.ReflectionMapGenerator;

public class ReflectionMapShader {
	TextureCubeMap reflectionMappingTexture = null;

	public void init(BackgroundBox skyBox) {
		reflectionMappingTexture = new TextureCubeMap(TextureCubeMap.BASE_LEVEL, TextureCubeMap.RGB, skyBox.getTopImage().getWidth());
		ImageComponent2D topImage = (ImageComponent2D)skyBox.getTopImage();
		ImageComponent2D bottomImage = (ImageComponent2D)skyBox.getBottomImage();
		ImageComponent2D eastImage = (ImageComponent2D)skyBox.getEastImage();
		ImageComponent2D westImage = (ImageComponent2D)skyBox.getWestImage();
		ImageComponent2D northImage = (ImageComponent2D)skyBox.getNorthImage();
		ImageComponent2D southImage = (ImageComponent2D)skyBox.getSouthImage();		
		reflectionMappingTexture.setImage(0, TextureCubeMap.POSITIVE_Y, topImage);
		reflectionMappingTexture.setImage(0, TextureCubeMap.NEGATIVE_Y, bottomImage);
		reflectionMappingTexture.setImage(0, TextureCubeMap.POSITIVE_Z, eastImage);
		reflectionMappingTexture.setImage(0, TextureCubeMap.NEGATIVE_Z, westImage);
		reflectionMappingTexture.setImage(0, TextureCubeMap.POSITIVE_X, northImage);
		reflectionMappingTexture.setImage(0, TextureCubeMap.NEGATIVE_X, southImage);
	}
	
	
	public void updateAppearance(Appearance ap, ReflectionMapGenerator reflectionMapGenerator, Camera3D camera) {
		if (reflectionMappingTexture == null) return;
		if (!reflectionMapGenerator.hasMapped()) {
			TexCoordGeneration tcg = new TexCoordGeneration(TexCoordGeneration.REFLECTION_MAP, TexCoordGeneration.TEXTURE_COORDINATE_3);
			TextureAttributes ta = new TextureAttributes();
			ta.setTextureMode(TextureAttributes.COMBINE);
			ta.setCombineRgbMode(TextureAttributes.COMBINE_INTERPOLATE);
			ta.setCombineRgbSource(0, TextureAttributes.COMBINE_TEXTURE_COLOR);
			ta.setCombineRgbSource(1, TextureAttributes.COMBINE_PREVIOUS_TEXTURE_UNIT_STATE);
			ta.setCombineRgbSource(2, TextureAttributes.COMBINE_CONSTANT_COLOR);
			ta.setCombineRgbFunction(0, TextureAttributes.COMBINE_SRC_COLOR);
			ta.setCombineRgbFunction(1, TextureAttributes.COMBINE_SRC_COLOR);
			ta.setCombineRgbFunction(2, TextureAttributes.COMBINE_SRC_COLOR);
			ta.setTextureBlendColor(reflectionMapGenerator.getBlendColor());
			ta.setCapability(TextureAttributes.ALLOW_TRANSFORM_READ);
			ta.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE);
			// TexCoordGeneration.REFLECTION_MAP は視線に対して固定なので、視線の向きに合わせてテクスチャを回転
			ta.setTextureTransform(camera.getWorldToView());
			int n = ap.getTextureUnitCount();
			if (n > 0) {
				// テクスチャユニットの一番最後に反射マッピングを設定する
				TextureUnitState newUnitStates[] = new TextureUnitState[n + 1];
				if (ap.getTextureUnitState() != null && n > 0) System.arraycopy(ap.getTextureUnitState(), 0, newUnitStates, 0, n);
				newUnitStates[n] = new TextureUnitState(reflectionMappingTexture, ta, tcg);
				
				ap.setTextureUnitState(newUnitStates);
			} else {	
				ap.setTexture(reflectionMappingTexture);
				ap.setTextureAttributes(ta);
				ap.setTexCoordGeneration(tcg);
			}
			reflectionMapGenerator.setMapped();
		} else {
			TextureAttributes ta;
			int n = ap.getTextureUnitCount();
			if (n > 0) {
				ta = ap.getTextureUnitState(ap.getTextureUnitCount() - 1).getTextureAttributes();
			} else {
				ta = ap.getTextureAttributes();
			}
			// TexCoordGeneration.REFLECTION_MAP は視線に対して固定なので、視線の向きに合わせてテクスチャを回転
			ta.setTextureTransform(camera.getWorldToView());						
		}
	}
}
