package org.helioviewer.gl3d.shader;

import javax.media.opengl.GL;

import org.helioviewer.viewmodel.view.opengl.shader.GLFragmentShaderProgram;
import org.helioviewer.viewmodel.view.opengl.shader.GLShaderBuilder;
import org.helioviewer.viewmodel.view.opengl.shader.GLShaderBuilder.GLBuildShaderException;

public class GL3DImageFragmentShaderProgram extends GLFragmentShaderProgram {

    private double cutOffRadius= 0.0f;
	private double xTextureScale;
	private double yTextureScale;
	private double theta;
	private double phi;	

	public GL3DImageFragmentShaderProgram() {
    }
    /**
     * Binds (= activates it) the shader, if it is not active so far.
     * 
     * @param gl
     *            Valid reference to the current gl object
     */
    public final void bind(GL gl) {
    	bind(gl, shaderID, cutOffRadius, xTextureScale, yTextureScale, theta, phi);
    }
    private static void bind(GL gl, int shader, double cutOffRadius, double xTextureScale, double yTextureScale, double theta, double phi) {
        //if (shader != shaderCurrentlyUsed) {
            shaderCurrentlyUsed = shader;
            gl.glBindProgramARB(target, shader);
            gl.glProgramLocalParameter4dARB(target, 0, cutOffRadius, 0.0f, 0.0f, 0.0f);
            gl.glProgramLocalParameter4dARB(target, 1,xTextureScale, yTextureScale, theta, phi);
        //}
    }
    /**
     * Pushes the shader currently in use onto a stack.
     * 
     * This is useful to load another shader but still being able to restore the
     * old one, similar to the very common pushMatrix() in OpenGL.
     * 
     * @param gl
     *            Valid reference to the current gl object
     * @see #popShader(GL)
     */
    public static void pushShader(GL gl) {
        shaderStack.push(shaderCurrentlyUsed);
        gl.glPushAttrib(GL.GL_CURRENT_BIT);
        // Log.debug("GL3DFragmentShaderProgram: pushShader, current="+shaderCurrentlyUsed);
    }

    /**
     * Takes the top of from the shader stack and binds it.
     * 
     * This restores a shader pushed onto the stack earlier, similar to the very
     * common popMatrix() in OpenGL.
     * 
     * @param gl
     *            Valid reference to the current gl object
     * @see #pushShader(GL)
     */
    public static void popShader(GL gl) {
        gl.glPopAttrib();
        Integer restoreShaderObject = shaderStack.pop();
        int restoreShader = restoreShaderObject == null ? 0 : restoreShaderObject.intValue();
        if (restoreShader >= 0) {
            bind(gl, restoreShader, 0.0f,0.0,0.0, 0.0,0.0);
        }
    }

    protected void buildImpl(GLShaderBuilder shaderBuilder) {
        try {
        	String program = "\tif(texcoord0.x<0.0||texcoord0.y<0.0||texcoord0.x>textureScaleThetaPhi.x||texcoord0.y>textureScaleThetaPhi.y){"
        			//+ "\t\tOUT.color = float4(1.0,0.0,0.0,1.0);" + GLShaderBuilder.LINE_SEP
        			+ "\t}"+ GLShaderBuilder.LINE_SEP;
            program += "\tOUT.color.a=1.0;" + GLShaderBuilder.LINE_SEP;
            program += "\tfloat theta = textureScaleThetaPhi.z;" + GLShaderBuilder.LINE_SEP;
            program += "\tfloat phi = textureScaleThetaPhi.w;" + GLShaderBuilder.LINE_SEP;        	
            
            program += "\tfloat zaxisxrott = 0.0;" + GLShaderBuilder.LINE_SEP;
            program += "\tfloat zaxisyrott = 0.0*cos(theta) - 1.0*sin(theta);" + GLShaderBuilder.LINE_SEP;
            program += "\tfloat zaxiszrott = 0.0*sin(theta) + 1.0*cos(theta);" + GLShaderBuilder.LINE_SEP;             

            program += "\tfloat zaxisxrot = zaxisxrott*cos(phi) - zaxiszrott*sin(phi);" + GLShaderBuilder.LINE_SEP;
            program += "\tfloat zaxisyrot = zaxisyrott;" + GLShaderBuilder.LINE_SEP;
            program += "\tfloat zaxiszrot = zaxisxrott*sin(phi) + zaxiszrott*cos(phi);" + GLShaderBuilder.LINE_SEP;  
            
            
            program += "\tfloat4 v1 = float4(position.x, position.y, position.z, 0.0);" + GLShaderBuilder.LINE_SEP;
            program += "\tfloat4 v2 = float4(zaxisxrot, zaxisyrot, zaxiszrot, 0.0);" + GLShaderBuilder.LINE_SEP;
            program += "\tfloat projectionn = dot(v1,v2);" + GLShaderBuilder.LINE_SEP;
           
        	program += "\tif(projectionn<0.0){"
        			+ "\t\tdiscard;" + GLShaderBuilder.LINE_SEP
        			+ "\t}";    	
        	//program += "\tfloat2 texture;" + GLShaderBuilder.LINE_SEP;
            //program += "\ttexture.x = textureCoordinate.z - 0.5;" + GLShaderBuilder.LINE_SEP;
            //program += "\ttexture.y = textureCoordinate.w - 0.5;" + GLShaderBuilder.LINE_SEP;
            //program += "\toutput.a *= step(length(texture),cutOffRadius);" + GLShaderBuilder.LINE_SEP;        	
        	
        	
            shaderBuilder.addEnvParameter("float cutOffRadius");
            shaderBuilder.addEnvParameter("float4 textureScaleThetaPhi");     

            program = program.replace("position",shaderBuilder.useStandardParameter("float4", "TEXCOORD3"));            

            program = program.replace("output", shaderBuilder.useOutputValue("float4", "COLOR"));
            program = program.replace("textureCoordinate", shaderBuilder.useStandardParameter("float4", "TEXCOORD0"));
            shaderBuilder.useOutputValue("float4", "DEPTH");
            shaderBuilder.addMainFragment(program);
            System.out.println("GL3D Image Fragment Shader:\n" + shaderBuilder.getCode());
        } catch (GLBuildShaderException e) {
            e.printStackTrace();
        }

    }
    
	public void changeTextureScale(double xTextureScale, double yTextureScale) {
		this.xTextureScale = xTextureScale;
		this.yTextureScale = yTextureScale;
	}
	
    public void setCutOffRadius(double cutOffRadius){
    	this.cutOffRadius = cutOffRadius;
    }
	public void changeAngles(double theta, double phi) {
		this.theta = theta;
		this.phi = phi;
	}

}

@@ -2919,32 +2919,34 @@
 EP;%0A            
+//
 program += %22%5CtOU
@@ -2955,19 +2955,19 @@
 color.a=
-1.0
+0.7
 ;%22 + GLS
@@ -5174,17 +5174,17 @@
 TEXCOORD
-0
+5
 %22));%0A   

Put output texture coordinate on TEXCOORD5 to avoid collisions / set fixed alpha for testing