{curl 5.0, 6.0, 7.0 applet}

{applet manifest = "manifest.mcurl"}

{api-version-switch
 case "6.0" do
    {import * from COM.CURL.GUI.STYLED-CONTROLS}
    {install-style-sheet
        {manifest-url "file", "DEFAULT-STYLE-SHEET"}
    }
}
{do
    let a:Applet = {get-the-applet}
    {a.set-title "Ray Tracing"}
    || {a.become-sticky}
}

{bold font-size=14pt, Real-Time Ray Tracing.}

{import * from CURL.R3D_F.RAY}

{import * from CURL.R3D_F.RAY.FANCY}
{let r:Random={Random}}

{define-proc {rotate z:float}:void
{do
    {let width:int=150,height:int=120}
    {let my-pixmap2:Pixmap = {Pixmap width, height}}
    {let f:Fill = {Fill width=width * 2pixels,
                      height=height * 2pixels,
                      background={FillPattern my-pixmap2}
                  }
    }
    {let n:Noise         = {Noise}}
    {let mp:Pigment = {MarblePigment 
                          {FastColor 1,1,1f},
                          {FastColor 1f,.9f,.90f},
                          {FastColor 1f,1f,.85f},
                          0.90f,
                          scale=.4f}}
    {do
        {for-pixel pixel at x, y no-read in my-pixmap2 do
            set pixel = {Developer.FastColor2Pixel {mp.getColor x/10f,y/10f,z}}
        }
        {set f.background = {FillPattern my-pixmap2}}
    }
    {set-document-properties || color = "white",
        background={FillPattern my-pixmap2}
    }
}
}
{let z:float = 0}
{rotate z}
{let animate_bg:bool=false}
||||||||||||||||||||||||||||||||||||||||||||||||||||

{let width:int       = 180}    {let height:int      = 140}

{let rs:RayScene = {RayScene width, height}}
{set rs.cam = {Camera  {Float3d 0f, -24f, -1f},
                  {Float3d 0f ,  0f, -1f},
                  {Float3d 0f ,  0f, 1f},
                  30,width,height}}

{let rn:RippleNormal = {RippleNormal 1f/20, 0deg}}
{let redTexture:ObjectTexture = 
    {ObjectTexture {ConstPigment 1.0f, .15f, 0.15f},
        {Finish ambient=0.5f, diffuse=.8f, specular=1f, 
            roughness=20.0f, reflection=0.95f},null}}
{let blueTexture:ObjectTexture =
    {ObjectTexture {ConstPigment 0.0f, .3f, 1f},
        {Finish ambient=0.5f, diffuse=1f, specular=1f, 
            roughness=20.0f, reflection=0.95f},
        null}}
{let whiteTexture:ObjectTexture =
    {ObjectTexture {ConstPigment 1.0f, 1f, .75f},
        {Finish emissive=1},null}}
{let mirrorTexture2:ObjectTexture =
    {ObjectTexture {ConstPigment 1.0f, 1.0f, 1.0f},
        {Finish ambient=0.2f, diffuse=0.4f, specular=1f, 
            roughness=30.0f, reflection=1f},rn}}

{let chkpig:CheckerPigment = {CheckerPigment 
                                 {FastColor 1,1,.5f},
                                 {FastColor 0,0,0}}}
{let mirrorTexture3:ObjectTexture =
    {ObjectTexture chkpig,
        {Finish ambient=0.5f, diffuse=0.8f, specular=1f, 
            roughness=30.0f, reflection=.6f},null}}


{let sphR:Sphere = {Sphere redTexture,{Float3d      5,0,0},1.25f}}
{let sphB:Sphere = {Sphere blueTexture,{Float3d    -4,0,0},1.25f}}
{let sph4:Sphere = {Sphere whiteTexture,{Float3d    3,0,3},0.2f,passlight=true}}
{let sph2:Sphere = {Sphere mirrorTexture2,{Float3d  0,0,-100},95f}}
{let lt1:PointLight = {PointLight 1f,1f,1f,{Float3d 3,8,3}}}
{rs.lights.append {AmbientLight .5f,.5f,.5f}}
{rs.lights.append lt1}

{rs.objects.append sphR}
{rs.objects.append sph2}
{rs.objects.append sphB}
{rs.objects.append sph4}



{let theta:Angle = 180deg}
{set lt1.lvec = sph4.center} || cool!

{let developer:Developer={Developer rs}}
{let usemouse:bool=false,mx:float,my:float}
{let xr:float,yr:float,zr:float,dxr:float,dyr:float,dzr:float}
{let xb:float,yb:float,zb:float,dxb:float,dyb:float,dzb:float}
{let animTimer:Timer = 
    {Timer
        frequency=30fps, || interval=0.03s, || repeat=3000,|| enabled?=false,
        {on TimerEvent do
            {if animate_bg then
               {set z=z+.15f}
               {rotate z}
             else
                 set xr={sin -6*theta} asa float*4
                 set yr={cos -7*theta} asa float*6+1
                 set zr={sin -5*theta} asa float*2 - 2f
                 set xb={sin 5*theta} asa float*4
                 set yb={cos 4*theta} asa float*6+1
                 set zb={sin 8*theta} asa float*2 - 2f
            {set sphR.center = {Float3d xr,yr,zr}}
            {set sphB.center = {Float3d xb,yb,zb}}
            ||{sphR.rebound}
            ||{sphB.rebound}
            {if usemouse then 
                {set lt1.lvec = {Float3d mx, 0, my }}
             else
                {set lt1.lvec = {Float3d {sin -17*theta/5} asa float*4,
                                    {cos -18*theta/5} asa float*4,
                                    {sin -19*theta/5} asa float*4 }}
            }
            {set sph4.center = lt1.lvec} || can't share anymore :-(
            {set rn.phs = -theta*30}
            {set chkpig.dx = -(theta/15deg) asa float}
            {set chkpig.dy = -(theta/15deg) asa float}
            {set theta            = theta + 1deg}
            {developer.develop_batch_noaa}
            }
        }
    }
}
{developer.develop_batch_noaa}

||{after 0s do {developer.develop_batch_noaa}}
{set developer.f.opaque-to-events?=true}
{set developer.f.horigin="center", developer.f.vorigin="center"}
{developer.f.add-event-handler
    {on e:PointerMotion do
        set mx = ( (e.x - developer.f.xd/2)/1pt) asa float / width  * 10 * 2
        set my = (-(e.y - developer.f.yd/2)/1pt) asa float / height * 15 - 1
    }
}
{developer.f.add-event-handler
    {on e:PointerEnter do set usemouse=true  }
}
{developer.f.add-event-handler
    {on e:PointerLeave do set usemouse=false }
}

{let ltblue:Color =  {Color.from-rgb 0.0,0.0,0.7}} || {Color.from-rgb 0.7,0.7,1}}
{let enablebutton:CommandButton={CommandButton style="label-only",
                                    label={text color=ltblue,text-underline?=true,pause},
                                    {on Action at b:CommandButton do
                                        {if animTimer.enabled? then
                                            set b.label = {text color=ltblue,text-underline?=true,continue}
                                            set animTimer.enabled? = false
                                         else
                                            set b.label = {text color=ltblue,text-underline?=true,pause}
                                            set animTimer.enabled? = true
                                        }
                                    }}
}
{let bgbutton:CommandButton={CommandButton style="label-only",
                                    label={text color=ltblue,text-underline?=true,animate background},
                                    {on Action at b:CommandButton do
                                        {if animate_bg then
                                            set b.label = {text color=ltblue,text-underline?=true,animate background}
                                            set animTimer.enabled? = true
                                            set enablebutton.label = {text color=ltblue,text-underline?=true,pause}
                                         else
                                            set b.label = {text color=ltblue,text-underline?=true,animate spheres}
                                            set animTimer.enabled? = true
                                            set enablebutton.label = {text color=ltblue,text-underline?=true,pause}
                                        }
                                        set animate_bg = not animate_bg
                                    }}
}


{br}
{let water:bool=true}
{let buttonmsg:Dynamic = "lake to plastic"}
{let restartmsg:Dynamic = ""}
{HBox valign="top",
    {VBox
        {value developer.f},
        {value bgbutton},
        {value enablebutton}
    },
    {Fill width=5px},
    {text font-size=10pt,
        If it's hard to believe that ray tracing can be done in real time by a plug-in
        you can {bold use the mouse to move the light 
        and watch the shadows change}, or       
        {CommandButton style="label-only",
            label={text color=ltblue,text-underline?=true,click here},
            {on Action at b:CommandButton do
                {if water then
                    set sph2.texture = mirrorTexture3
                    set buttonmsg.value = "plastic back into a lake"
                                            set animTimer.enabled? = true
                                            set enablebutton.label = {text color=ltblue,text-underline?=true,pause}
                                            set bgbutton.label = {text color=ltblue,text-underline?=true,animate background}
                                            set animate_bg = false
                    set water = false
                 else
                    set sph2.texture = mirrorTexture2
                    set buttonmsg.value = "lake to plastic"
                                            set animTimer.enabled? = true
                                            set enablebutton.label = {text color=ltblue,text-underline?=true,pause}
                                            set bgbutton.label = {text color=ltblue,text-underline?=true,animate background}
                                            set animate_bg = false
                    set water = true
                }
                {set enablebutton.label = {text color=ltblue,text-underline?=true,pause}}
                set animTimer.enabled? = true
            }} 
        to turn the {value buttonmsg}.
        {paragraph {br}}  
        {text font-size=10pt,
            To learn more, read {bold The Coolest Interactive Ray Tracing Tutorial on the Web}, 
            which is totally written in Curl and contains 
            {link href={url "tutorial.curl"},{bold a nice gallery}} of ray traced Curl procedural graphics.
        }       
    }
}
