uniform sampler3D baseTexture;
uniform float SampleDensityValue;
uniform float TransparencyValue;
uniform float IsoSurfaceValue;

varying vec4 cameraPos;
varying vec4 vertexPos;
varying mat4 texgen;

void main(void)
{ 
    vec4 t0 = vertexPos;
    vec4 te = cameraPos;
    vec3 eyeDirection = normalize((te-t0).xyz);

    if (te.x>=0.0 && te.x<=1.0 &&
        te.y>=0.0 && te.y<=1.0 &&
        te.z>=0.0 && te.z<=1.0)
    {
        // do nothing... te inside volume
    }
    else
    {
        if (te.x<0.0)
        {
            float r = -te.x / (t0.x-te.x);
            te = te + (t0-te)*r;
        }

        if (te.x>1.0)
        {
            float r = (1.0-te.x) / (t0.x-te.x);
            te = te + (t0-te)*r;
        }

        if (te.y<0.0)
        {
            float r = -te.y / (t0.y-te.y);
            te = te + (t0-te)*r;
        }

        if (te.y>1.0)
        {
            float r = (1.0-te.y) / (t0.y-te.y);
            te = te + (t0-te)*r;
        }

        if (te.z<0.0)
        {
            float r = -te.z / (t0.z-te.z);
            te = te + (t0-te)*r;
        }

        if (te.z>1.0)
        {
            float r = (1.0-te.z) / (t0.z-te.z);
            te = te + (t0-te)*r;
        }
    }

    t0 = t0 * texgen;
    te = te * texgen;

    const float max_iteratrions = 2048.0;
    float num_iterations = ceil(length((te-t0).xyz)/SampleDensityValue);
    if (num_iterations<2.0) num_iterations = 2.0;

    if (num_iterations>max_iteratrions) 
    {
        num_iterations = max_iteratrions;
    }

    vec3 deltaTexCoord=(t0-te).xyz/float(num_iterations-1.0);
    vec3 texcoord = te.xyz;

    vec4 previousColor = texture3D( baseTexture, texcoord);
    
    float normalSampleDistance = 1.0/512.0;
    vec3 deltaX = vec3(normalSampleDistance, 0.0, 0.0);
    vec3 deltaY = vec3(0.0, normalSampleDistance, 0.0);
    vec3 deltaZ = vec3(0.0, 0.0, normalSampleDistance);
    
    while(num_iterations>0.0)
    {
        vec4 color = texture3D( baseTexture, texcoord);

        float m = (previousColor.a-IsoSurfaceValue) * (color.a-IsoSurfaceValue);
        if (m <= 0.0)
        {
            float r = (IsoSurfaceValue-color.a)/(previousColor.a-color.a);
            texcoord = texcoord - r*deltaTexCoord;
            
            float a = color.a;
            float px = texture3D( baseTexture, texcoord + deltaX).a;
            float py = texture3D( baseTexture, texcoord + deltaY).a;
            float pz = texture3D( baseTexture, texcoord + deltaZ).a;

            float nx = texture3D( baseTexture, texcoord - deltaX).a;
            float ny = texture3D( baseTexture, texcoord - deltaY).a;
            float nz = texture3D( baseTexture, texcoord - deltaZ).a;
            
            vec3 grad = vec3(px-nx, py-ny, pz-nz);
            if (grad.x!=0.0 || grad.y!=0.0 || grad.z!=0.0)
            {
                vec3 normal = normalize(grad);
                float lightScale = 0.1 +  abs(dot(normal.xyz, eyeDirection))*0.9;

                color.x = lightScale;
                color.y = lightScale;
                color.z = lightScale;
            }

            color.a = 1.0;

            gl_FragColor = color;
            
            return;
        }
        
        previousColor = color;
        
        texcoord += deltaTexCoord; 

        --num_iterations;
    }

    // we didn't find an intersection so just discard fragment
    discard;
}
