Feedback

Please leave feedback and comments. I am always interested to hear how people get on using these LScripts!

Thursday 19 December 2013

LScript - Image_TV


LScript (Layout) applies a crt television effect.

Changes
  • Added presets

Compatible with Newtek LightWave 9.6 and above.

// LScript Image Filter - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/*  
    LScript Image Filter - TV

    Image_TV.ls

*/

@version 2.5
@warnings
@script image
@name *TV

    // Title
    sTitle = "*TV";

    // Version
    sVersion = "v1.0";

    nApertureGrilleOpactiy = 0.05;
    nScanlineDistortion = 1;
    nScanlineOpacity = 0.1;
    nScanlineNoise = 0.05;
    nScanlineScale = 0.025;
    nScanlineSpeed = -0.5;
    nScanlineThickness = 2;
    nStaticOpacity = 0.05;

    // Control
    ctrl_c0,ctrl_c1,ctrl_c2,ctrl_c3,ctrl_c4,ctrl_c5,ctrl_c6,ctrl_c7,ctrl_c8; 

create
{
    setdesc(sTitle);
}

process: ifo
{
    _Thickness = 1 / nScanlineThickness;
    _ApertureColor = 1;

    nTime = Scene().currenttime;
    for(i = 1;i <= ifo.height;++i)
    {
    if(mod(ceil(i * _Thickness),2) == 0){_Scanline = nScanlineOpacity + (randu() * nScanlineNoise);}else{_Scanline = - nScanlineOpacity;}
    _Scanline += abs(sin(nTime + (i * nScanlineScale) * nScanlineSpeed) * nScanlineOpacity);
    _Distortion = sin(nTime + (i * nScanlineScale) * nScanlineSpeed) * nScanlineDistortion * randu();
                
      for(j = 1;j <= ifo.width;++j)
        {

        if(nScanlineDistortion <> 0) // Distortion
          {
          u = clip(1,ifo.width,round(j + _Distortion,0));
          v = clip(1,ifo.height,i + 1);
          ifo.red[j,i] = ifo.red[u,v];
          ifo.green[j,i] = ifo.green[u,v];
          ifo.blue[j,i] = ifo.blue[u,v];
          }

        if(nStaticOpacity > 0.0) // Static
          {
          _Static = randu() * nStaticOpacity; 
          ifo.red[j,i] = ifo.red[j,i] + _Static;
          ifo.green[j,i] = ifo.green[j,i] + _Static;
          ifo.blue[j,i] = ifo.blue[j,i] + _Static;
          }

        if(nApertureGrilleOpactiy > 0.0) // Aperture Grille
          {
          if(j == 1){_ApertureColor = 1;}
          if(_ApertureColor > 3){_ApertureColor = 1;}
          if(_ApertureColor == 1) // Red
            {
            ifo.red[j,i] = ifo.red[j,i] + nApertureGrilleOpactiy;
            ifo.green[j,i] = ifo.green[j,i] - nApertureGrilleOpactiy;
            ifo.blue[j,i] = ifo.blue[j,i] - nApertureGrilleOpactiy;
            }
          if(_ApertureColor == 2) // Green
            {
            ifo.red[j,i] = ifo.red[j,i] - nApertureGrilleOpactiy;
            ifo.green[j,i] = ifo.green[j,i] + nApertureGrilleOpactiy;
            ifo.blue[j,i] = ifo.blue[j,i] - nApertureGrilleOpactiy;
            }

          if(_ApertureColor == 3) // Blue
            {
            ifo.red[j,i] = ifo.red[j,i] - nApertureGrilleOpactiy;
            ifo.green[j,i] = ifo.green[j,i] - nApertureGrilleOpactiy;
            ifo.green[j,i] = ifo.green[j,i] + nApertureGrilleOpactiy;
            }
          ++_ApertureColor;
          }

        ifo.red[j,i] = clip(0.0,1.0,ifo.red[j,i] + _Scanline);
        ifo.green[j,i] = clip(0.0,1.0,ifo.green[j,i] + _Scanline);
        ifo.blue[j,i] = clip(0.0,1.0,ifo.blue[j,i] + _Scanline);
        }
    }
}

// CLIP

clip: min,max,n
{
    if(n < min) n = min;
    if(n > max) n = max;
    return(n);
}

load: what,io
{
    if(what == SCENEMODE)
    {
        if(io.read().asStr() == sTitle + " " + sVersion)
            {
            nApertureGrilleOpacity = io.read().asNum(); // Aperture Grille Opacity
            nScanlineDistortion = io.read().asInt(); // Scanline Distortion
            nScanlineOpacity = io.read().asNum(); // Scanline Opacity
            nScanlineNoise = io.read().asNum(); // Scanline Noise           
            nScanlineScale = io.read().asNum(); // Scanline Scale           
            nScanlineSpeed = io.read().asNum(); // Scanline Speed           
            nScanlineThickness = io.read().asInt(); // Scanline Thickness
            nStaticOpacity = io.read().asNum(); // Static Opacity
            }
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        // Header
        io.writeln(sTitle + " " + sVersion);

        io.writeln(nApertureGrilleOpacity); // Aperture Grille Opacity
        io.writeln(nScanlineDistortion); // Scanline Distortion
        io.writeln(nScanlineOpacity); // Scanline Opacity
        io.writeln(nScanlineNoise); // Scanline Noise
        io.writeln(nScanlineScale); // Scanline Scale
        io.writeln(nScanlineSpeed); // Scanline Speed
        io.writeln(nScanlineThickness); // Scanline Thickness
        io.writeln(nStaticOpacity); // Static Opacity
    }
}

options
{
    reqbegin(sTitle + " " + sVersion);

    // Control
    ctrl_c0 = ctlpopup("Preset",1, @"CRT",
                                    "Aperture Grille",
                                    "Scanlines",
                                    "Bad Signal",
                                    "Distortion"@);
    ctlsep();
    ctrl_c1 = ctlnumber("Aperture Grille Opacity",nApertureGrilleOpactiy);
    ctlsep();
    ctrl_c2 = ctlinteger("Scanline Distortion",nScanlineDistortion);
    ctrl_c3 = ctlnumber("Opacity",nScanlineOpacity);
    ctrl_c4 = ctlnumber("Noise",nScanlineNoise);
    ctrl_c5 = ctlnumber("Scale",nScanlineScale);
    ctrl_c6 = ctlnumber("Speed",nScanlineSpeed);
    ctrl_c7 = ctlinteger("Thickness",nScanlineThickness);
    ctlsep();
    ctrl_c8 = ctlnumber("Static",nStaticOpacity);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    // Refresh
    ctlrefresh(ctrl_c0,"refresh_preset"); // Preset

    return if !reqpost();

    nApertureGrilleOpactiy = getvalue(ctrl_c1); // Aperture Grille Opacity
    nScanlineDistortion = getvalue(ctrl_c2); // Scanline Distortion
    nScanlineOpacity = getvalue(ctrl_c3); // Scanline Opacity
    nScanlineNoise = getvalue(ctrl_c4); // Scanline Noise
    nScanlineScale = getvalue(ctrl_c5); // Scanline Scale
    nScanlineSpeed = getvalue(ctrl_c6); // Scanline Speed
    nScanlineThickness = getvalue(ctrl_c7); // Scanline Thickness
    nStaticOpacity = getvalue(ctrl_c8); // Static Opacity

    reqend();
}

refresh_preset:value
{
    if(value == 1) // CRT
      {
      setvalue(ctrl_c1,0.05); // Aperture Grille Opacity
      setvalue(ctrl_c2,1); // Scanline Distortion
      setvalue(ctrl_c3,0.1); // Scanline Opacity
      setvalue(ctrl_c4,0.05); // Scanline Noise
      setvalue(ctrl_c5,0.025); // Scanline Scale
      setvalue(ctrl_c6,-0.5); // Scanline Speed
      setvalue(ctrl_c7,2); // Scanline Thickness
      setvalue(ctrl_c8,0.05); // Static Opacity
      }

    if(value == 2) // Aperture Grille
      {
      setvalue(ctrl_c1,0.2); // Aperture Grille Opacity
      setvalue(ctrl_c2,0); // Scanline Distortion
      setvalue(ctrl_c3,0.0); // Scanline Opacity
      setvalue(ctrl_c4,0.0); // Scanline Noise
      setvalue(ctrl_c5,0.025); // Scanline Scale
      setvalue(ctrl_c6,-0.5); // Scanline Speed
      setvalue(ctrl_c7,1); // Scanline Thickness
      setvalue(ctrl_c8,0.0); // Static Opacity
      }

    if(value == 3) // Scanlines
      {
      setvalue(ctrl_c1,0.0); // Aperture Grille Opacity
      setvalue(ctrl_c2,0); // Scanline Distortion
      setvalue(ctrl_c3,0.1); // Scanline Opacity
      setvalue(ctrl_c4,0.0); // Scanline Noise
      setvalue(ctrl_c5,0.025); // Scanline Scale
      setvalue(ctrl_c6,-0.5); // Scanline Speed
      setvalue(ctrl_c7,2); // Scanline Thickness
      setvalue(ctrl_c8,0.0); // Static Opacity
      }

    if(value == 4) // Bad Signal
      {
      setvalue(ctrl_c1,0.1); // Aperture Grille Opacity
      setvalue(ctrl_c2,4); // Scanline Distortion
      setvalue(ctrl_c3,0.2); // Scanline Opacity
      setvalue(ctrl_c4,0.1); // Scanline Noise
      setvalue(ctrl_c5,0.025); // Scanline Scale
      setvalue(ctrl_c6,-0.5); // Scanline Speed
      setvalue(ctrl_c7,2); // Scanline Thickness
      setvalue(ctrl_c8,0.2); // Static Opacity
      }

    if(value == 5) // Distortion
      {
      setvalue(ctrl_c1,0.0); // Aperture Grille Opacity
      setvalue(ctrl_c2,10); // Scanline Distortion
      setvalue(ctrl_c3,0.01); // Scanline Opacity
      setvalue(ctrl_c4,0.2); // Scanline Noise
      setvalue(ctrl_c5,0.1); // Scanline Scale
      setvalue(ctrl_c6,-0.5); // Scanline Speed
      setvalue(ctrl_c7,2); // Scanline Thickness
      setvalue(ctrl_c8,0.1); // Static Opacity
      }
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

LScript - Image_Fluff&Dust


LScript (Layout) applies dirt,dust and fluff to rendered frames like on old film.

Changes
  • Added presets
  • Updated interface

Compatible with Newtek LightWave 9.6 and above.

// LScript Image Filter - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/*  
    LScript Image Filter - Fluff & Dust
    Image_Fluff&Dust.ls

*/

@version 2.5
@warnings
@script image
@name *Fluff & Dust

    // Title
    sTitle = "*Fluff & Dust";

    // Version
    sVersion = "v1.0";

    // Variable
    Global_nOpacity = 1.0;

    Dust_bEnable = true;
    Dust_vColor = <0,0,0>;
    Dust_iAmount = 25000; 
    Dust_nOpacity = 0.2;
    Dust_nMinSize = 0.1;
    Dust_nMaxSize = 1.0;

    Dirt_bEnable = true;
    Dirt_vColor = <0,0,0>;
    Dirt_iFrequency = 1;
    Dirt_iAmount = 500;
    Dirt_nOpacity = 0.1;
    Dirt_nMinSize = 1.0;
    Dirt_nMaxSize = 10.0;

    Fluff_bEnable = true;
    Fluff_vColor = <0,0,0>;
    Fluff_iFrequency = 1;
    Fluff_iMinAmount = 1;
    Fluff_iMaxAmount = 9;
    Fluff_iMinLength = 50;
    Fluff_iMaxLength = 100;
    Fluff_nMinOpacity = 0.05;
    Fluff_nMaxOpacity = 0.5;
    Fluff_nMinSize = 0.1;
    Fluff_nMaxSize = 1.0;     

    // Control
    ctrl_dust0,ctrl_dust1,ctrl_dust2,ctrl_dust3,ctrl_dust4,ctrl_dust5,
    ctrl_dirt0,ctrl_dirt1,ctrl_dirt2,ctrl_dirt3,ctrl_dirt4,ctrl_dirt5,ctrl_dirt6,
    ctrl_fluff0,ctrl_fluff1,ctrl_fluff2,ctrl_fluff3,ctrl_fluff4,ctrl_fluff5,ctrl_fluff6,ctrl_fluff7,ctrl_fluff8,ctrl_fluff9,ctrl_fluff10;

create
{
    setdesc(sTitle);
}

process: ifo
{

// Dust

    if(Dust_bEnable == true)
      {

      if(runningUnder() != SCREAMERNET) moninit(Dust_iAmount);

      vColor = Dust_vColor * (1/255);
      for(a = 1;a <= Dust_iAmount;++a)
        {
        v = ;
        circleenhancedIFO(ifo,
                          v, // Vector
                          max(Dust_nMinSize,randu() * Dust_nMaxSize), // Size
                          0.0,// fade
                          vColor.x,vColor.y,vColor.z, // Color
                          Dust_nOpacity * Global_nOpacity); // Opacity    

        if(runningUnder() != SCREAMERNET) if(monstep()) return;

        }
      }

// Dirt

    if(random(1,Dirt_iFrequency) == 1 && Dirt_bEnable == true)
      {

      if(runningUnder() != SCREAMERNET) moninit(Dirt_iAmount);

      vColor = Dirt_vColor * (1/255);
      for(a = 1;a <= Dirt_iAmount;++a)
      {
      v = ;
      circleenhancedIFO(ifo,
                        v, // Vector
                        max(Dirt_nMinSize,randu() * Dirt_nMaxSize), // Size
                        0.0,// fade
                        vColor.x,vColor.y,vColor.z, // Color
                        Dirt_nOpacity * Global_nOpacity); // Opacity    

      if(runningUnder() != SCREAMERNET) if(monstep()) return;

      }
    }

// Fluff

    if(random(1,Fluff_iFrequency) == 1 && Fluff_bEnable == true)
      {
      Fluff_iAmount = random(Fluff_iMinAmount,Fluff_iMaxAmount);

      if(runningUnder() != SCREAMERNET) moninit(Fluff_iAmount);

      vColor = Fluff_vColor * (1/255);
      for(a = 1;a <= Fluff_iAmount;++a)
        {
        iL = random(Fluff_iMinLength,Fluff_iMaxLength);
        s2 = max(Fluff_nMinSize,randu() * Fluff_nMaxSize); 
        v2 = ;
        o2 = max(Fluff_nMinOpacity,randu() * Fluff_nMaxOpacity);  
        for(l = 1;l <= iL;++l)
          {
          s1 = s2; 
          v1 = v2;
          s2 = max(Fluff_nMinSize,randu() * Fluff_nMaxSize); 
          v2 = ;
          o1 = o2; 
          o2 = max(Fluff_nMinOpacity,randu() * Fluff_nMaxOpacity); 
          lineenhancedIFO(ifo,
                          v1, // Vector
                          v2, // Vector
                          s1, // Size
                          s2, // Size
                          vColor.x,vColor.y,vColor.z, // Color
                          o1 * Global_nOpacity, // Opacity
                          vColor.x,vColor.y,vColor.z, // Color
                          o2 * Global_nOpacity); // Opacity
          }

        if(runningUnder() != SCREAMERNET) if(monstep()) return;

        }
      }

}

// IFO

circleenhancedIFO: ifo,v,s,f,r,g,b,o // vector,size,fade,red,green,blue,opacity
{
    // Size <= 1
    if(s <= 1)
      {
      o *= s;
      if (v.x >= 1 && v.x <= ifo.width && v.y >= 1 && v.y <= ifo.height)
        { 
        if(o >= 1.0)
          {
          ifo.red[v.x,v.y] = r;
          ifo.green[v.x,v.y] = g;
          ifo.blue[v.x,v.y] = b;
          }
        else if(o > 0.0)
          {
          ifo.red[v.x,v.y] = (ifo.red[v.x,v.y] * (1-o)) + (r * o);
          ifo.green[v.x,v.y] = (ifo.green[v.x,v.y] * (1-o)) + (g * o);
          ifo.blue[v.x,v.y] = (ifo.blue[v.x,v.y] * (1-o)) + (b * o);
          }
        }
      return; 
      }
    // Half Size
    s *= 0.5; 
    // Grid
    x0 = floor(v.x - s - 1);
    y0 = floor(v.y - s - 1);
    x1 = floor(v.x + s + 1);
    y1 = floor(v.y + s + 1);
    // Offscreen
    if(x1 < 1 || x0 > ifo.width){break;}
    if(y1 < 1 || y0 > ifo.height){break;}
    // Grid
    if(x0 < 1){x0 = 1;}
    if(y0 < 1){y0 = 1;}
    if(x1 > ifo.width){x1 = ifo.width;}
    if(y1 > ifo.height){y1 = ifo.height;}
    // Fade
    _f = s * f;
    // Draw
    for(y = y0;y <= y1;++y)
      {
      for(x = x0;x <= x1;++x)
        {
        // Opacity          
        _o = 0.0;
        d = distance2D(v,);
        f_01 = maprange01(_f,s,d);        
        if(f_01 <= 0.0){_o = o;} // Inside
        else if(f_01 <= 1.0)
          {
          _o = o * (1 - f_01);
   }      
        if(_o >= 1.0)
          {
          ifo.red[x,y] = r;
          ifo.green[x,y] = g;
          ifo.blue[x,y] = b;
          }
        else if (_o > 0.0)
          {
          ifo.red[x,y] = (ifo.red[x,y] * (1-_o)) + (r * _o);
          ifo.green[x,y] = (ifo.green[x,y] * (1-_o)) + (g * _o);
          ifo.blue[x,y] = (ifo.blue[x,y] * (1-_o)) + (b * _o);
          }
        }
      }
}

lineenhancedIFO: ifo,v1,v2,s1,s2,r1,g1,b1,o1,r2,g2,b2,o2 // vector1,vector2,size1,size2,red1,green1,blue1,opacity1,red2,green2,blue2,opacity2
{
    // Size < 1
    if(s1 < 1){o1 *= s1;}
    if(s2 < 1){o2 *= s2;}
    // Half Size
    s1 *= 0.5;
    s2 *= 0.5;
    // Interpolation
    d = distance2D(v1,v2);
    if(d <> 0.0)
      {
      vInt = (v2 - v1) * (1 / d);
      sInt = (s2 - s1) * (1 / d);
      rInt = (r2 - r1) * (1 / d);
      gInt = (g2 - g1) * (1 / d);
      bInt = (b2 - b1) * (1 / d);
      oInt = (o2 - o1) * (1 / d);
      }
    else
      {
      vInt = <0.0,0.0,0.0>;
      sInt = max(s1,s2);
      rInt = max(r1,r2);
      gInt = max(g1,g2);
      bInt = max(b1,b2);
      oInt = max(o1,o2);
      }
    // Clip
    cx0 = -1.0;
    cy0 = -1.0;
    cx1 = -1.0;
    cy1 = -1.0;
    // Offset
    vOffset = @ <0.0,0.0,0.0>,<-0.25,-0.25,0.0>,<0.25,-0.25,0.0>,<-0.25,0.25,0.0>,<0.25,0.25,0.0> @;
    // Draw
    for(i = 0;i <= floor(d);++i)
      {
      // Interpolate
      v = v1 + (vInt * i);
      s = s1 + (sInt * i);
      r = r1 + (rInt * i);
      g = g1 + (gInt * i);
      b = b1 + (bInt * i);
      o = o1 + (oInt * i);
      // Grid
      x0 = floor(v.x - s - 1);
      y0 = floor(v.y - s - 1);
      x1 = floor(v.x + s + 1);
      y1 = floor(v.y + s + 1);
      if(x0 < 1){x0 = 1;}
      if(y0 < 1){y0 = 1;}
      if(x1 > ifo.width){x1 = ifo.width;}
      if(y1 > ifo.height){y1 = ifo.height;}
      // Draw
      for(y = y0;y <= y1;++y)
        {
        for(x = x0;x <= x1;++x)
          {
          if (x >= 1 && x <= ifo.width && y >= 1 && y <= ifo.height)
            { 
            if(clip2D(,cx0,cy0,cx1,cy1) == true)
              {               
              // Opacity          
              _o = 0.0;
              ld = linedistance2D(,v1,v2);
              if(ld < (s - 1)){_o = o;} // Inside
              else if(ld <= (s + 1))
                {
                smo = 0;
                for(sm = 1;sm <= 5;++sm)
                  {              
                 if(linedistance2D( + vOffset[sm],v1,v2) <= s){++smo;} 
                  }
                if(smo > 0.0){_o = o * (0.2 * smo);}else{_o = 0.0;}
                }
              if(_o >= 1.0)
                {
                ifo.red[x,y] = r;
                ifo.green[x,y] = g;
                ifo.blue[x,y] = b;
                }
              else if (_o > 0.0)
                {
                ifo.red[x,y] = (ifo.red[x,y] * (1-_o)) + (r * _o);
                ifo.green[x,y] = (ifo.green[x,y] * (1-_o)) + (g * _o);
                ifo.blue[x,y] = (ifo.blue[x,y] * (1-_o)) + (b * _o);
                }
              }
            }
          }
        }       
      // Update Clip
      cx0 = x0; 
      cy0 = y0; 
      cx1 = x1; 
      cy1 = y1; 
      }
}

// MAP RANGE

maprange01: n1,n2,i
{    
    if(n2-n1 == 0.0){return(0.0);}
  else
    {return((1/(n2-n1)) * (i-n1));}
}

// VECTOR 2D

clip2D: v,x0,y0,x1,y1 // b
{
    if((v.x >= x0) && (v.x <= x1) && (v.y >= y0) && (v.y <= y1)){return(false);}
  else
    return(true);
}

distance2D: v1, v2 // n
{
    // Vector
    return(sqrt(((v2.x - v1.x) * (v2.x - v1.x)) +
                ((v2.y - v1.y) * (v2.y - v1.y))));
}

linedistance2D: v1,v2,v3 // n
{
    // Vector v1 from line v2 to v3
    nSqrLineMagnitude = sqrlinemagnitude2D(v2,v3);
    if(nSqrLineMagnitude < 0.00000000000001)
      {
      return(-1.0);
      }
    u = ((v1.x - v2.x) * (v3.x - v2.x) + (v1.y - v2.y) * (v3.y - v2.y)) / nSqrLineMagnitude;
    if(u < 0.0000001 or u > 1)
      {
      x = distance2D(v1,v2);
      y = distance2D(v1,v3);
      return(min(x,y));
      }
    else
      {
      x = v2.x + u * (v3.x - v2.x);
      y = v2.y + u * (v3.y - v2.y);
      return(distance2D(v1,));
      }
}

sqrlinemagnitude2D: v1,v2 // n
{
    return((v2.x - v1.x) * (v2.x - v1.x) + (v2.y - v1.y) * (v2.y - v1.y));
}

//

load: what,io
{
    if(what == SCENEMODE)
    {
        if(io.read().asStr() == sTitle + " " + sVersion)
            {
            // Global
            Global_nOpacity = io.read().asNum();

            // Dust
            Dust_bEnable = io.read().asInt();
            Dust_vColor = io.read().asVec();
            Dust_iAmount = io.read().asInt();
            Dust_nOpacity = io.read().asNum();
            Dust_nMinSize = io.read().asNum();
            Dust_nMaxSize = io.read().asNum();

            // Dirt
            Dirt_bEnable = io.read().asInt();
            Dirt_vColor = io.read().asVec();
            Dirt_iFrequency = io.read().asInt();
            Dirt_iAmount = io.read().asInt();
            Dirt_nOpacity = io.read().asNum();
            Dirt_nMinSize = io.read().asNum();
            Dirt_nMaxSize = io.read().asNum();

            // Fluff
            Fluff_bEnable = io.read().asInt();
            Fluff_vColor = io.read().asVec();
            Fluff_iFrequency = io.read().asInt();
            Fluff_iMinAmount = io.read().asInt();
            Fluff_iMaxAmount = io.read().asInt();
            Fluff_iMinLength = io.read().asInt();
            Fluff_iMaxLength = io.read().asInt();
            Fluff_nMinOpacity = io.read().asNum();
            Fluff_nMaxOpacity = io.read().asNum();
            Fluff_nMinSize = io.read().asNum();
            Fluff_nMaxSize = io.read().asNum();
            }
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        // Header
        io.writeln(sTitle + " " + sVersion);

        // Global
        io.writeln(Global_nOpacity);

        // Dust
        io.writeln(Dust_bEnable);
        io.writeln(Dust_vColor);
        io.writeln(Dust_iAmount); 
        io.writeln(Dust_nOpacity);
        io.writeln(Dust_nMinSize);
        io.writeln(Dust_nMaxSize);

        // Dirt
        io.writeln(Dirt_bEnable);
        io.writeln(Dirt_vColor);
        io.writeln(Dirt_iFrequency);
        io.writeln(Dirt_iAmount);
        io.writeln(Dirt_nOpacity);
        io.writeln(Dirt_nMinSize);
        io.writeln(Dirt_nMaxSize);

        // Fluff
        io.writeln(Fluff_bEnable);
        io.writeln(Fluff_vColor);
        io.writeln(Fluff_iFrequency);
        io.writeln(Fluff_iMinAmount);
        io.writeln(Fluff_iMaxAmount);
        io.writeln(Fluff_iMinLength);
        io.writeln(Fluff_iMaxLength);
        io.writeln(Fluff_nMinOpacity);
        io.writeln(Fluff_nMaxOpacity);
        io.writeln(Fluff_nMinSize);
        io.writeln(Fluff_nMaxSize);   
    }
}

options
{
    reqbegin(sTitle + " " + sVersion);
    reqsize(340,402);

    // Control

    // Preset
    ctrl_pr0 = ctlpopup("Preset",1, @"Projected Film (Dirty)",
                                     "Dust (Light)",
                                     "Dust & Dirt (Heavy)",
                                     "Fluff"@);

    // Global
    ctlsep();
    ctrl_g0 = ctlnumber("Global Opacity",Global_nOpacity);
    ctlsep();
    ctrl_tab = ctltab("Dust","Dirt","Fluff","Developer");

    // Dust
    ctrl_dust0 = ctlcheckbox("Enable",Dust_bEnable);
    ctrl_dust1 = ctlcolor("Color",Dust_vColor);
    ctrl_dust2 = ctlinteger("Amount",Dust_iAmount);
    ctrl_dust3 = ctlnumber("Opacity",Dust_nOpacity);
    ctrl_dust4 = ctlnumber("Min Size",Dust_nMinSize);
    ctrl_dust5 = ctlnumber("Max Size",Dust_nMaxSize);

    ctlposition(ctrl_dust0,36,104,172,20,100);
    ctlposition(ctrl_dust1,36,134,212,20,100);
    ctlposition(ctrl_dust2,36,158,212,20,100);
    ctlposition(ctrl_dust3,36,180,212,20,100);
    ctlposition(ctrl_dust4,36,204,212,20,100);
    ctlposition(ctrl_dust5,36,228,212,20,100);

    ctlpage(1,ctrl_dust0,ctrl_dust1,ctrl_dust2,ctrl_dust3,
              ctrl_dust4,ctrl_dust5);

    // Dirt
    ctrl_dirt0 = ctlcheckbox("Enable",Dirt_bEnable);
    ctrl_dirt1 = ctlcolor("Color",Dirt_vColor);
    ctrl_dirt2 = ctlinteger("Frequency (1 = on)",Dirt_iFrequency);
    ctrl_dirt3 = ctlinteger("Amount",Dirt_iAmount);
    ctrl_dirt4 = ctlnumber("Opacity",Dirt_nOpacity);
    ctrl_dirt5 = ctlnumber("Min Size",Dirt_nMinSize);
    ctrl_dirt6 = ctlnumber("Max Size",Dirt_nMaxSize);

    ctlposition(ctrl_dirt0,36,104,172,20,100);
    ctlposition(ctrl_dirt1,36,134,212,20,100);
    ctlposition(ctrl_dirt2,36,158,212,20,100);
    ctlposition(ctrl_dirt3,36,180,212,20,100);
    ctlposition(ctrl_dirt4,36,204,212,20,100);
    ctlposition(ctrl_dirt5,36,228,212,20,100);
    ctlposition(ctrl_dirt6,36,252,212,20,100);

    ctlpage(2,ctrl_dirt0,ctrl_dirt1,ctrl_dirt2,ctrl_dirt3,
              ctrl_dirt4,ctrl_dirt5,ctrl_dirt6);

    // Fluff
    ctrl_fluff0 = ctlcheckbox("Enable",Fluff_bEnable);
    ctrl_fluff1 = ctlcolor("Color",Fluff_vColor);
    ctrl_fluff2 = ctlinteger("Frequency (1 = on)",Fluff_iFrequency);
    ctrl_fluff3 = ctlinteger("Min Amount",Fluff_iMinAmount);
    ctrl_fluff4 = ctlinteger("Max Amount",Fluff_iMaxAmount);
    ctrl_fluff5 = ctlinteger("Min Length",Fluff_iMinLength);
    ctrl_fluff6 = ctlinteger("Max Length",Fluff_iMaxLength);
    ctrl_fluff7 = ctlnumber("Min Opacity",Fluff_nMinOpacity);
    ctrl_fluff8 = ctlnumber("Max Opacity",Fluff_nMaxOpacity);
    ctrl_fluff9 = ctlnumber("Min Size",Fluff_nMinSize);
    ctrl_fluff10 = ctlnumber("Max Size",Fluff_nMaxSize);

    ctlposition(ctrl_fluff0,36,104,172,20,100);
    ctlposition(ctrl_fluff1,36,134,212,20,100);
    ctlposition(ctrl_fluff2,36,158,212,20,100);
    ctlposition(ctrl_fluff3,36,180,212,20,100);
    ctlposition(ctrl_fluff4,36,204,212,20,100);
    ctlposition(ctrl_fluff5,36,228,212,20,100);
    ctlposition(ctrl_fluff6,36,252,212,20,100);
    ctlposition(ctrl_fluff7,36,276,212,20,100);
    ctlposition(ctrl_fluff8,36,300,212,20,100);
    ctlposition(ctrl_fluff9,36,324,212,20,100);
    ctlposition(ctrl_fluff10,36,348,212,20,100);

    ctlpage(3,ctrl_fluff0,ctrl_fluff1,ctrl_fluff2,ctrl_fluff3,ctrl_fluff4,ctrl_fluff5,
              ctrl_fluff6,ctrl_fluff7,ctrl_fluff8,ctrl_fluff9,ctrl_fluff10);

    // Developer
    ctrl_dev = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");
    ctlposition(ctrl_dev,120,120,280,20,100);
    ctlpage(4,ctrl_dev);

    // Refresh
    ctlrefresh(ctrl_pr0,"refresh_preset"); // Preset

    return if !reqpost();

    Global_nOpacity = getvalue(ctrl_g0);

    Dust_bEnable = getvalue(ctrl_dust0);
    Dust_vColor = getvalue(ctrl_dust1);
    Dust_iAmount = getvalue(ctrl_dust2);
    Dust_nOpacity = getvalue(ctrl_dust3); 
    Dust_nMinSize = getvalue(ctrl_dust4); 
    Dust_nMaxSize = getvalue(ctrl_dust5); 

    Dirt_bEnable = getvalue(ctrl_dirt0);
    Dirt_vColor = getvalue(ctrl_dirt1);
    Dirt_iFrequency = getvalue(ctrl_dirt2);
    Dirt_iAmount = getvalue(ctrl_dirt3);
    Dirt_nOpacity = getvalue(ctrl_dirt4); 
    Dirt_nMinSize = getvalue(ctrl_dirt5); 
    Dirt_nMaxSize = getvalue(ctrl_dirt6); 

    Fluff_bEnable = getvalue(ctrl_fluff0);
    Fluff_vColor = getvalue(ctrl_fluff1);
    Fluff_iFrequency = getvalue(ctrl_fluff2);
    Fluff_iMinAmount = getvalue(ctrl_fluff3);
    Fluff_iMaxAmount = getvalue(ctrl_fluff4);
    Fluff_iMinLength = getvalue(ctrl_fluff5);
    Fluff_iMaxLength = getvalue(ctrl_fluff6);
    Fluff_nMinOpacity = getvalue(ctrl_fluff7);
    Fluff_nMaxOpacity = getvalue(ctrl_fluff8);
    Fluff_nMinSize = getvalue(ctrl_fluff9);
    Fluff_nMaxSize = getvalue(ctrl_fluff10);

    reqend();
}

refresh_preset:value
{
    if(value == 1) // Projected Film (Dirty)
      {
      setvalue(ctrl_dust0,1); // Dust Enable
      setvalue(ctrl_dust1,<0,0,0>); // Dust Color
      setvalue(ctrl_dust2,25000); // Dust Amount
      setvalue(ctrl_dust3,0.2); // Dust Opacity
      setvalue(ctrl_dust4,0.1); // Dust Min Size
      setvalue(ctrl_dust5,1.0); // Dust Max Size

      setvalue(ctrl_dirt0,1); // Dirt Enable
      setvalue(ctrl_dirt1,<0,0,0>); // Dirt Color
      setvalue(ctrl_dirt2,1); // Dirt Frequency
      setvalue(ctrl_dirt3,500); // Dirt Amount
      setvalue(ctrl_dirt4,0.1); // Dirt Opacity
      setvalue(ctrl_dirt5,1); // Dirt Min Size
      setvalue(ctrl_dirt6,10); // Dirt Max Size

      setvalue(ctrl_fluff0,1); // Fluff Enable
      setvalue(ctrl_fluff1,<0,0,0>); // Fluff Color
      setvalue(ctrl_fluff2,1); // Fluff Frequency
      setvalue(ctrl_fluff3,1); // Fluff Min Amount
      setvalue(ctrl_fluff4,9); // Fluff Max Amount
      setvalue(ctrl_fluff5,50); // Fluff Min Length
      setvalue(ctrl_fluff6,100); // Fluff Max Length
      setvalue(ctrl_fluff7,0.05); // Fluff Min Opacity
      setvalue(ctrl_fluff8,0.5); // Fluff Max Opacity
      setvalue(ctrl_fluff9,0.1); // Fluff Min Size
      setvalue(ctrl_fluff10,1.0); // Fluff Max Size
      }

    if(value == 2) // Dust (Light)
      {
      setvalue(ctrl_dust0,1); // Dust Enable
      setvalue(ctrl_dust1,<1.0,1.0,1.0>); // Dust Color
      setvalue(ctrl_dust2,5000); // Dust Amount
      setvalue(ctrl_dust3,0.2); // Dust Opacity
      setvalue(ctrl_dust4,0.1); // Dust Min Size
      setvalue(ctrl_dust5,5.0); // Dust Max Size

      setvalue(ctrl_dirt0,0); // Dirt Enable

      setvalue(ctrl_fluff0,0); // Fluff Enable
      }

    if(value == 3) // Dust & Dirt (Heavy)
      {
      setvalue(ctrl_dust0,1); // Dust Enable
      setvalue(ctrl_dust1,<1.0,1.0,1.0>); // Dust Color
      setvalue(ctrl_dust2,30000); // Dust Amount
      setvalue(ctrl_dust3,0.2); // Dust Opacity
      setvalue(ctrl_dust4,0.1); // Dust Min Size
      setvalue(ctrl_dust5,5.0); // Dust Max Size

      setvalue(ctrl_dirt0,1); // Dirt Enable
      setvalue(ctrl_dirt1,<1.0,1.0,1.0>); // Dirt Color
      setvalue(ctrl_dirt2,1); // Dirt Frequency
      setvalue(ctrl_dirt3,10); // Dirt Amount
      setvalue(ctrl_dirt4,0.1); // Dirt Opacity
      setvalue(ctrl_dirt5,200); // Dirt Min Size
      setvalue(ctrl_dirt6,200); // Dirt Max Size

      setvalue(ctrl_fluff0,0); // Fluff Enable
      }

    if(value == 4) // Fluff
      {
      setvalue(ctrl_dust0,0); // Dust Enable

      setvalue(ctrl_dirt0,0); // Dirt Enable

      setvalue(ctrl_fluff0,1); // Fluff Enable
      setvalue(ctrl_fluff1,<1.0,1.0,1.0>); // Fluff Color
      setvalue(ctrl_fluff2,1); // Fluff Frequency
      setvalue(ctrl_fluff3,2000); // Fluff Min Amount
      setvalue(ctrl_fluff4,2000); // Fluff Max Amount
      setvalue(ctrl_fluff5,10); // Fluff Min Length
      setvalue(ctrl_fluff6,20); // Fluff Max Length
      setvalue(ctrl_fluff7,0.05); // Fluff Min Opacity
      setvalue(ctrl_fluff8,0.5); // Fluff Max Opacity
      setvalue(ctrl_fluff9,0.1); // Fluff Min Size
      setvalue(ctrl_fluff10,1.0); // Fluff Max Size
      }

}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

Wednesday 18 December 2013

LScript - Motion_Squash


LScript (Layout) to squash objects based on interaction with ground plane. I use it for quick ball animations to squash as they bounce.

Compatible with Newtek LightWave 9.6 and above.

// LScript Item Animation - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/* 
    LScript Item Animation - Squash

    Motion_Squash.ls

*/

@version 2.2
@warnings
@script motion
@name *Squash

    // Title
    sTitle = "*Squash";

    // Version
    sVersion = "v1.0";

    // Item
    GroundItem = nil; // Item
    GroundItemName = "nil"; // Item

    // Variable
    bWorldCoordinates = false;
    nRadius = 1.0;
    nStretchX = 0.33;
    nStretchZ = 0.33;

create
{
    // Description
    setdesc(sTitle);

    // Info
    info("*Squash - Apply a scaling effect based on Y axis.");
}

destroy
{
}

process: ma, frame, time
{     
    // Variables
    if(bWorldCoordinates) 
      {
      vPosition = ma.get(WPOSITION,time);
      vRotation = ma.get(ROTATION,time);
      vScale = ma.get(SCALING,time);
      vGroundItemPosition = <0,0,0>;
      vGroundItemRotation = <0,0,0>;
      vGroundItemScale = <0,0,0>;

      if(GroundItemName != "nil") {GroundItem = Mesh(GroundItemName); GroundItemName = "nil";}
      if(GroundItem)
        { 
        vGroundItemPosition = GroundItem.getWorldPosition(time);
        vGroundItemRotation = GroundItem.getRotation(time);
        vGroundItemScale = GroundItem.getScaling(time);
        }
      else
        {
        Item = ma.objID;
        ItemParent = Item.parent;
        if(ItemParent)
          {
          vGroundItemPosition = ItemParent.getWorldPosition(time);
          vGroundItemRotation = ItemParent.getRotation(time);
          vGroundItemScale = ItemParent.getScaling(time);
          }
        }

      }
    else
      {
      vPosition = ma.get(POSITION,time);
      vRotation = ma.get(ROTATION,time);
      vScale = ma.get(SCALING,time);
      vGroundItemPosition = <0,0,0>;
      vGroundItemRotation = <0,0,0>;
      vGroundItemScale = <0,0,0>;

      if(GroundItemName != "nil") {GroundItem = Mesh(GroundItemName); GroundItemName = "nil";}
      if(GroundItem)
        { 
        vGroundItemPosition = GroundItem.getPosition(time);
        vGroundItemRotation = GroundItem.getRotation(time);
        vGroundItemScale = GroundItem.getScaling(time);
        }
      else
        {
        Item = ma.objID;
        ItemParent = Item.parent;
        if(ItemParent)
          {
          vGroundItemPosition = ItemParent.getPosition(time);
          vGroundItemRotation = ItemParent.getRotation(time);
          vGroundItemScale = ItemParent.getScaling(time);
          }
        }

      }
        
  nDistance =  abs(vGroundItemPosition.y - vPosition.y);
  if(nDistance < nRadius)
    {
    // Squash
    nScale = (1 / nRadius) * nDistance;
    vScale.y := nScale;
    // Stretch
    vScale.x = 1 + ((1 - nScale) * nStretchX);
    vScale.z = 1 + ((1 - nScale) * nStretchZ);
    }

// ma

  ma.set(SCALING,vScale);

}

load: what,io
{
    if(what == SCENEMODE)   // processing an ASCII scene file
    {
        sHeader = io.read().asStr();

        if(sHeader == sTitle + " " + sVersion)
            {
            GroundItemName = io.read().asStr();
            bWorldCoordinates = io.read().asInt();
            nRadius = io.read().asNum();
            nStretchX = io.read().asNum();
            nStretchZ = io.read().asNum();
            }
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        // Header
        io.writeln(sTitle + " " + sVersion);

        if(GroundItem != nil)
            {
            io.writeln(string(GroundItem.name));
            }
        else
            {
            io.writeln("nil");
            }    

        io.writeln(bWorldCoordinates);
        io.writeln(nRadius);
        io.writeln(nStretchX);
        io.writeln(nStretchZ);
    }
}

options
{
    if(reqisopen())
        {
        reqend();
        return;
        }
 
    reqbegin(sTitle + " " + sVersion);

    ctrl_c0 = ctlcheckbox("World Coordinates",bWorldCoordinates);
    ctrl_c1 = ctlmeshitems("Ground Item",GroundItem);
    ctrl_c2 = ctldistance("Radius",nRadius);
    ctrl_c3 = ctlpercent("Stretch X",nStretchX);
    ctrl_c4 = ctlpercent("Stretch Z",nStretchZ);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    // Refresh
    ctlrefresh(ctrl_c0,"refresh_c0"); // World Coordinates
    ctlrefresh(ctrl_c1,"refresh_c1"); // Ground Item
    ctlrefresh(ctrl_c2,"refresh_c2"); // Radius
    ctlrefresh(ctrl_c3,"refresh_c3"); // Stretch X
    ctlrefresh(ctrl_c4,"refresh_c4"); // Stretch Z

    reqopen();
}

refresh_c0:value // World Coordinates
{
    bWorldCoordinates = value;
}

refresh_c1:value // Ground Item
{
    GroundItem = value;
}

refresh_c2:value // Radius
{
    nRadius = value;
}

refresh_c3:value // Stretch X
{
    nStretchX = value;
}

refresh_c4:value // Stretch Z
{
    nStretchZ = value;
}
All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

LScript - Image_Stars


LScript (Layout) generate stars for space background image maps.

Compatible with Newtek LightWave 9.6 and above.

// LScript Image Filter - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/*  
    LScript Image Filter - Stars
    Image_Stars.ls

*/

@version 2.5
@warnings
@script image
@name *Stars

    // Title
    sTitle = "*Stars";

    // Version
    sVersion = "v1.0";

    // Variable
    Global_nOpacity = 1.0;

    Stars_vColor = <255,255,255>;
    Stars_iAmount = 200; 
    Stars_nOpacity = 0.2;
    Stars_nMinSize = 1.0;
    Stars_nMaxSize = 5.0;

create
{
    setdesc(sTitle);
}

process: ifo
{

    if(runningUnder() != SCREAMERNET) moninit(Stars_iAmount);

    vColor = Stars_vColor * (1/255);
    for(a = 1;a <= Stars_iAmount;++a)
      {
      v = ;
      circleenhancedIFO(ifo,
                        v, // Vector
                        max(Stars_nMinSize,randu() * Stars_nMaxSize), // Size
                        0.0,// fade
                        vColor.x,vColor.y,vColor.z, // Color
                        Stars_nOpacity * Global_nOpacity); // Opacity    

      if(runningUnder() != SCREAMERNET) if(monstep()) return;

      }
}

// IFO

circleenhancedIFO: ifo,v,s,f,r,g,b,o // vector,size,fade,red,green,blue,opacity
{
    // Size <= 1
    if(s <= 1)
      {
      o *= s;
      if (v.x >= 1 && v.x <= ifo.width && v.y >= 1 && v.y <= ifo.height)
        { 
        if(o >= 1.0)
          {
          ifo.red[v.x,v.y] = r;
          ifo.green[v.x,v.y] = g;
          ifo.blue[v.x,v.y] = b;
          }
        else if(o > 0.0)
          {
          ifo.red[v.x,v.y] = (ifo.red[v.x,v.y] * (1-o)) + (r * o);
          ifo.green[v.x,v.y] = (ifo.green[v.x,v.y] * (1-o)) + (g * o);
          ifo.blue[v.x,v.y] = (ifo.blue[v.x,v.y] * (1-o)) + (b * o);
          }
        }
      return; 
      }
    // Half Size
    s *= 0.5; 
    // Grid
    x0 = floor(v.x - s - 1);
    y0 = floor(v.y - s - 1);
    x1 = floor(v.x + s + 1);
    y1 = floor(v.y + s + 1);
    // Fade
    _f = s * f;
    // Draw
    for(y = y0;y <= y1;++y)
      {
      for(x = x0;x <= x1;++x)
        {
        // Wrap
        x2 = x;
        if(x2 < 1){x2 = ifo.width - abs(mod(x2,ifo.width));}
        if(x2 > ifo.width){x2 = mod(x2,ifo.width) + 1;}
        y2 = y;
        if(y2 < 1){y2 = ifo.height - abs(mod(y2,ifo.height));}
        if(y2 > ifo.height){y2 = mod(y2,ifo.height) + 1;}
        // Opacity          
        _o = 0.0;
        d = distance2D(v,);
        f_01 = maprange01(_f,s,d);     
        if(f_01 <= 0.0){_o = o;} // Inside
        else if(f_01 <= 1.0)
          {
          _o = o * (1 - f_01);
   }      
        if(_o >= 1.0)
          {
          ifo.red[x2,y2] = r;
          ifo.green[x2,y2] = g;
          ifo.blue[x2,y2] = b;
          }
        else if (_o > 0.0)
          {
          ifo.red[x2,y2] = (ifo.red[x2,y2] * (1-_o)) + (r * _o);
          ifo.green[x2,y2] = (ifo.green[x2,y2] * (1-_o)) + (g * _o);
          ifo.blue[x2,y2] = (ifo.blue[x2,y2] * (1-_o)) + (b * _o);
          }
        }
      }
}

// MAP RANGE

maprange01: n1,n2,i
{    
    if(n2-n1 == 0.0){return(0.0);}
  else
    {return((1/(n2-n1)) * (i-n1));}
}

// VECTOR 2D

clip2D: v,x0,y0,x1,y1 // b
{
    if((v.x >= x0) && (v.x <= x1) && (v.y >= y0) && (v.y <= y1)){return(false);}
  else
    return(true);
}

distance2D: v1, v2 // n
{
    // Vector
    return(sqrt(((v2.x - v1.x) * (v2.x - v1.x)) +
                ((v2.y - v1.y) * (v2.y - v1.y))));
}

linedistance2D: v1,v2,v3 // n
{
    // Vector v1 from line v2 to v3
    nSqrLineMagnitude = sqrlinemagnitude2D(v2,v3);
    if(nSqrLineMagnitude < 0.00000000000001)
      {
      return(-1.0);
      }
    u = ((v1.x - v2.x) * (v3.x - v2.x) + (v1.y - v2.y) * (v3.y - v2.y)) / nSqrLineMagnitude;
    if(u < 0.0000001 or u > 1)
      {
      x = distance2D(v1,v2);
      y = distance2D(v1,v3);
      return(min(x,y));
      }
    else
      {
      x = v2.x + u * (v3.x - v2.x);
      y = v2.y + u * (v3.y - v2.y);
      return(distance2D(v1,));
      }
}

sqrlinemagnitude2D: v1,v2 // n
{
    return((v2.x - v1.x) * (v2.x - v1.x) + (v2.y - v1.y) * (v2.y - v1.y));
}

//

load: what,io
{
    if(what == SCENEMODE)
    {
        if(io.read().asStr() == sTitle + " " + sVersion)
            {
            // Global
            Global_nOpacity = io.read().asNum();

            // Stars
            Stars_vColor = io.read().asVec();
            Stars_iAmount = io.read().asInt();
            Stars_nOpacity = io.read().asNum();
            Stars_nMinSize = io.read().asNum();
            Stars_nMaxSize = io.read().asNum();
            }
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        // Header
        io.writeln(sTitle + " " + sVersion);

        // Global
        io.writeln(Global_nOpacity);

        // Stars
        io.writeln(Stars_vColor);
        io.writeln(Stars_iAmount); 
        io.writeln(Stars_nOpacity);
        io.writeln(Stars_nMinSize);
        io.writeln(Stars_nMaxSize);
    }
}

options
{
    reqbegin(sTitle + " " + sVersion);

    // Control

    // Global
    ctrl_g0 = ctlnumber("Global Opacity",Global_nOpacity);

    ctlsep();
    ctrl_stars0 = ctlcolor("Color",Stars_vColor);
    ctrl_stars1 = ctlinteger("Amount",Stars_iAmount);
    ctrl_stars2 = ctlnumber("Opacity",Stars_nOpacity);
    ctrl_stars3 = ctlnumber("Min Size",Stars_nMinSize);
    ctrl_stars4 = ctlnumber("Max Size",Stars_nMaxSize);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    return if !reqpost();

    Global_nOpacity = getvalue(ctrl_g0);

    Stars_vColor = getvalue(ctrl_stars0);
    Stars_iAmount = getvalue(ctrl_stars1);
    Stars_nOpacity = getvalue(ctrl_stars2); 
    Stars_nMinSize = getvalue(ctrl_stars3); 
    Stars_nMaxSize = getvalue(ctrl_stars4); 

    reqend();
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

LScript - Motion_TimeReference


LScript (Layout) to quickly add motion to a channel based on time.

Compatible with Newtek LightWave 9.6 and above.

// LScript Item Animation - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/* 
    LScript Item Animation - Time Reference

    Motion_TimeReference.ls

*/

@version 2.2
@warnings
@script motion
@name *Time Reference

    // Title
    sTitle = "*Time Reference";

    // Version
    sVersion = "v1.0";

    // Variable
    aChannel = @"X","Y","Z","H","P","B","SX","SY","SZ"@; 
    iChannel = 1;
    nAmount = 1.0;

create
{
  _setdesc(); // setdesc();
}

destroy
{
}

_setdesc
{
  if(iChannel >= 1 && iChannel <= 3){setdesc(sTitle + " - Channel " + aChannel[iChannel] + " @ " + nAmount + "m/s");}
  if(iChannel >= 4 && iChannel <= 6){setdesc(sTitle + " - Channel " + aChannel[iChannel] + " @ " + nAmount + " degrees");}
  if(iChannel >= 7 && iChannel <= 9){setdesc(sTitle + " - Channel " + aChannel[iChannel] + " @ " + nAmount + "m/s");}
}

process: ma, frame, time
{   
 if(nAmount <> 0.0)
   {
    if(iChannel == 1) // X
      {
       vPosition = ma.get(POSITION,time) + ;
       // ma
       ma.set(POSITION,vPosition);
      }
    if(iChannel == 2) // Y
      {
       vPosition = ma.get(POSITION,time) + <0.0,nAmount * time,0.0>;
       // ma
       ma.set(POSITION,vPosition);
      }
    if(iChannel == 3) // Z
      {
       vPosition = ma.get(POSITION,time) + <0.0,0.0,nAmount * time>;
       // ma
       ma.set(POSITION,vPosition);
      }
    if(iChannel == 4) // H
      {
       vRotation = ma.get(ROTATION,time) + ;
       // ma
       ma.set(ROTATION,vRotation);
      }
    if(iChannel == 5) // P
      {
       vRotation = ma.get(ROTATION,time) + <0.0,nAmount * time,0.0>;
       // ma
       ma.set(ROTATION,vRotation);
      }
    if(iChannel == 6) // B
      {
       vRotation = ma.get(ROTATION,time) + <0.0,0.0,nAmount * time>;
       // ma
       ma.set(ROTATION,vRotation);
      }
    if(iChannel == 7) // SX
      {
       vScaling = ma.get(SCALING,time) + ;
       // ma
       ma.set(SCALING,vScaling);
      }
    if(iChannel == 8) // SY
      {
       vScaling = ma.get(SCALING,time) + <0.0,nAmount * time,0.0>;
       // ma
       ma.set(SCALING,vScaling);
      }
    if(iChannel == 9) // SZ
      {
       vScaling = ma.get(SCALING,time) + <0.0,0.0,nAmount * time>;
       // ma
       ma.set(SCALING,vScaling);
      }

    }
}

load: what,io
{
    if(what == SCENEMODE)   // processing an ASCII scene file
    {
        iChannel = io.read().asInt();
        nAmount = io.read().asNum();
        _setdesc(); // setdesc();
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        io.writeln(iChannel);
        io.writeln(nAmount);
    }
}

options
{
    reqbegin(sTitle + " " + sVersion);

    ctrl_c0 = ctlchoice("Channel",iChannel,@"X","Y","Z","H","P","B","SX","SY","SZ"@);
    ctrl_c1 = ctlnumber("Amount",nAmount);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    return if !reqpost();

    iChannel = getvalue(ctrl_c0);
    nAmount = getvalue(ctrl_c1);
    _setdesc(); // setdesc();

    reqend();
}
All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

Saturday 14 September 2013

LScript - Modeler_PointNormalToSkelegon


LScript (Modeler) to create skelegons based on the normals at point locations.

Compatible with Newtek LightWave 9.6 and above.

// LScript Modeler - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/*  
    LScript Modeler - Point Normal To Skelegon

    Modeler_PointNormalToSkelegon.ls

*/

@version 2.2
@warnings
@script modeler
@name *Point Normal To Skelegon

    // Title
    sTitle = "*Point Normal To Skelegon";

    // Version
    sVersion = "v1.0";

    // Variable
    aSelectedPoints = nil;

    ctrl_c0;

main
{

    // Store
    nSize = recall("nSize",0.1); 

    reqbegin(sTitle + " " + sVersion);

    // Reset
    ctrl_res0 = ctlbutton("Reset",50,"button_reset"); // Button Reset
    ctlsep();

    // Control
    ctrl_c0 = ctldistance("Size",nSize);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    return if !reqpost();

    nSize = getvalue(ctrl_c0);

    // Store
    store("nSize",nSize);

    // Selection - Point (DIRECT)
    selmode(DIRECT);
    iPointCount = pointcount();
    if(iPointCount < 1) error("None or not enough points selected.");

    editbegin();

        aSelectedPoints = points; // Store points for later use

        foreach(iSelectedPoint,aSelectedPoints)
          {
          aPolygons = nil;
          aPolygons = iSelectedPoint.polygon();
          // Error
          if(aPolygons == nil) error("Points must be connected to polygons.");
          foreach(iPolygons,aPolygons)
            {
            aPoints = nil;
            aPoints = polyinfo(iPolygons);
            // Error
            if(sizeof(aPoints) < 4) error("Polygons need a minimum of 3 points.");
          }
        }

    editend();

    undogroupbegin(); // Undo

    moninit(iPointCount,"Processing...");  // Progress Monitor

        foreach(iSelectedPoint,aSelectedPoints)
          {

    // Selection - Point (GLOBAL)
    selmode(GLOBAL);

    editbegin();

          vNorm = pointnormal(iSelectedPoint);   
          i1 = addpoint(pointinfo(iSelectedPoint)); // Returns ID
          i2 = addpoint(vNorm * nSize + pointinfo(iSelectedPoint)); // Returns ID
          aNormalPolygon[1] = i1;
          aNormalPolygon[2] = i2;
          iPolygon = addpolygon(aNormalPolygon);

    editend(); 

          // Selection - Polygon (USER)
          selmode(USER);

          selpolygon(CLEAR); 
          selpolygon(SET,POLYID,iPolygon);
          cmdseq("MakeSkelegons");
          delete(); 

          monstep(); // Progress Monitor
          }

    undogroupend(); // Undo

    info(iPointCount," skelegon(s) added.");
}

button_reset
{
    setvalue(ctrl_c0,0.1); // Size
}

pointnormal: point // v
{
    v = <0.0,0.0,0.0>;
    aPolygons = point.polygon();
    iPolygonCount = size(aPolygons);
    for(p = 1; p <= iPolygonCount; p++)
      {
      v += polynormal(aPolygons[p]);          
      }
    v /= iPolygonCount;
    return(normalize3D(v));
}

// INTERPOLATION

linear1D: n1,n2,i // i = interpolation point (0-1)
{
    return(n1 * (1 - i) + n2 * i);     
}

// VECTOR 3D

crossproduct3D: v1,v2 // v
{
    // Vector
    return();
}

distance3D: v1, v2 // n
{
    // Vector
    return(sqrt(((v2.x - v1.x) * (v2.x - v1.x)) +
                ((v2.y - v1.y) * (v2.y - v1.y)) + 
                ((v2.z - v1.z) * (v2.z - v1.z))));
}

magnitude3D: v // n
{
    // Vector
    return(sqrt((v.x * v.x) + (v.y * v.y) + (v.z * v.z)));
}

normalize3D: v // v
{
    // Vector normalize to 0 - 1
    nMagnitude = magnitude3D(v);
    if(nMagnitude <> 0) nMagnitude = 1 / nMagnitude;
    return(v * nMagnitude);
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

Wednesday 31 July 2013

LScript - Displace_Expand


LScript (Layout) to animate models expanding in to existence. It is best used upon non subdivided and unwelded polygons.

Compatible with Newtek LightWave 9.6 and above.

// LScript Displacement Map - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/*  
    LScript Displacement Map - Expand 

    Displace_Expand.ls

*/

@version 2.2
@warnings
@script displace
@name *Expand

    // Title
    sTitle = "*Expand";

    // Version
    sVersion = "v1.0";

    // Item
    Item;

    // Variable
    iCount = 0;
    iPoint = 0;
    iPointCount = 0;
    vPosition = <0.0,0.0,0.0>;

    // Requester
    bRequesterUpdate = false; // Update
    iRequesterFrame = -1; // Frame

    // Envelope
    envAmount; // Amount

    // Control
    ctrl_c0;

create: obj
{
    setdesc(sTitle);

    // Item
    Item = obj;

    // Envelope
    envAmount = Envelope("Amount (" + sTitle + ")",CHAN_NUMBER,sTitle); // Amount
    envAmount.persist(false);
    envAmount.createKey(0,0.0);

    // Info
    info("*Expand - Use with unwelded polygons without subdivions.");
}

destroy
{
}

newtime: id, frame, time
{

    if(reqisopen() && iRequesterFrame != frame)
        {
        bRequesterUpdate = true; // Update       

        setvalue(ctrl_c0,envAmount.value(Scene().currenttime)); // Amount

        iRequesterFrame = frame; // Frame
        bRequesterUpdate = false; // Update
        }

    // Subpatch Level
    SubPatchLevel(0,0);

    // Variable
    nAmount = clip(0.0,1.0,envAmount.value(time));
    iPointCount = Item.pointCount();
    nPoint = nAmount * iPointCount;
    nFrac = frac(nPoint);
    iPoint = nPoint - nFrac;    
    vPosition = linear1D(Item.position(Item.points[max(1,iPoint)]),Item.position(Item.points[min(iPointCount,iPoint + 1)]),nFrac);
    iCount = 0; // Count
}

flags
{
    // WORLD      LOCAL

    return(LOCAL);
}

process: da
{
    iCount++; // Count
    if(iCount <= iPoint)
      {
      }
    else
      {
      // da

      da.source[1] = vPosition.x;
      da.source[2] = vPosition.y;
      da.source[3] = vPosition.z;
      }     
}

// CLIP

clip: min,max,n
{
    if(n < min) n = min;
    if(n > max) n = max;
    return(n);
}

// INTERPOLATION

linear1D: n1,n2,i // i = interpolation point (0-1)
{
    return(n1 * (1 - i) + n2 * i);     
}

load: what,io
{
    if(what == SCENEMODE)   // processing an ASCII scene file
    {
        if(io.read().asStr() == sTitle + " " + sVersion)
            {
            // Envelope
            envAmount.load(); // Amount
            }
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {    
        // Header
        io.writeln(sTitle + " " + sVersion);

        // Envelope
        envAmount.save(); // Amount
    }
}

options
{
    if(reqisopen())
        {
        reqend();
        return;
        }

    reqbegin(sTitle + " " + sVersion);

    ctrl_c0 = ctlpercent("Amount",envAmount.value(Scene().currenttime)); // Amount
    ctrl_c1e = ctlbutton("E",20,"button_c1e"); // Button

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    // Refresh
    ctlrefresh(ctrl_c0,"refresh_c0"); // Amount

    reqopen();
}

button_c1e // Amount
{
    envAmount.edit();
}

refresh_c0:value // Amount
{
    if(bRequesterUpdate) return; // Requester Update
    setvalue(ctrl_c0,clip(0.0,1.0,value));
    iKey = envAmount.keyExists(Scene().currenttime);
    if(iKey == nil)
        {envAmount.createKey(Scene().currenttime,clip(0.0,1.0,value));}
    else
        {envAmount.setKeyValue(iKey,clip(0.0,1.0,value));}
}
All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

LScript - Channel_Filter


LScript (Layout) to filter envelopes to smooth it out based on time samples.

Compatible with Newtek LightWave 9.6 and above.

// LScript Channel Filter - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/* 
    LScript Channel Filter - Filter

    Channel_Filter.ls

*/

@version 2.2
@warnings
@script channel
@name *Filter

    // Title
    sTitle = "*Filter";

    // Version
    sVersion = "v1.0";

    // Variable
    iFilter = 5;

    // Controls 
    ctrl_c0;

create: channel
{
    setdesc(sTitle + " - " + iFilter);
}

destroy
{
    // take care of final clean-up activities here
}

process: ca, frame, time
{
    fps = (1 / Scene().fps);
    iCount = 0;
    nValue = 0.0;
    for(iS = -iFilter; iS <= iFilter; iS++)
      {
      nValue += ca.get(time + (iS * fps));
      iCount++; 
      }
    if(iCount > 1){nValue = nValue * (1 / iCount);}

    // ca    
    ca.set(nValue);
}

load: what,io
{
    if(what == SCENEMODE)   // processing an ASCII scene file
    {
        if(io.read().asStr() == sTitle + " " + sVersion)
            {
            iFilter = io.read().asInt(); // Filter
            setdesc(sTitle + " - " + iFilter);
            }
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        // Header
        io.writeln(sTitle + " " + sVersion);
        io.writeln(iFilter); // Filter
    }
}

options
{
    if(reqisopen())
        {
        reqend();
        return;
        }

    reqbegin(sTitle + " " + sVersion);

    ctrl_c0 = ctlinteger("Filter",iFilter);   

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    // Refresh
    ctlrefresh(ctrl_c0,"refresh_c0"); // Filter

    reqopen();
}

refresh_c0:value // Filter
{
    iFilter = min(max(0,value),100);
    setvalue(ctrl_c0,iFilter); 
    setdesc(sTitle + " - " + iFilter);
}
All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

Thursday 28 March 2013

Free Stuff - Tin Cans (Object)


Free objects for LightWave : Various high quality sub-division modeled tin cans (10).

Compatible with Newtek LightWave 9.6 and above.

Download - zipped object (.zip)

Tuesday 26 March 2013

LScript - Image_Alpha

LScript (Layout) to create compressed video artifact effect.

Compatible with Newtek LightWave 9.6 and above.

// LScript Image Filter - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/* 
    LScript Image Filter - Alpha

    Image_Alpha.ls

*/

@version 2.5
@warnings
@script image
@name *Alpha

    // Title
    sTitle = "*Alpha";

    // Version
    sVersion = "v1.0";

    aType = @"Solid","Luma","Luma (Invert)"@;
    iType = 1;

create
{
    setdesc(sTitle + " - " + aType[iType]);
}

process: ifo
{

    if(iType == 1) // Solid
      {

      iProgress = ifo.height;
      if(runningUnder() != SCREAMERNET) moninit(iProgress);
      for(i = 1;i <= ifo.height;++i)
        {
        for(j = 1;j <= ifo.width;++j)
          {
          ifo.alpha[j,i] = 1.0;
          }
        if(runningUnder() != SCREAMERNET) if(monstep()) return;
        }

      }

    if(iType == 2) // Luma
      {

      iProgress = ifo.height;
      if(runningUnder() != SCREAMERNET) moninit(iProgress);
      for(i = 1;i <= ifo.height;++i)
        {
        for(j = 1;j <= ifo.width;++j)
          {
          ifo.alpha[j,i] = clip(0.0,1.0,(ifo.red[j,i] + ifo.green[j,i] + ifo.blue[j,i]) * (1 / 3));
          }
        if(runningUnder() != SCREAMERNET) if(monstep()) return;
        }

      }

    if(iType == 3) // Luma (Invert)
      {

      iProgress = ifo.height;
      if(runningUnder() != SCREAMERNET) moninit(iProgress);
      for(i = 1;i <= ifo.height;++i)
        {
        for(j = 1;j <= ifo.width;++j)
          {
          ifo.alpha[j,i] = clip(0.0,1.0,1.0 - ((ifo.red[j,i] + ifo.green[j,i] + ifo.blue[j,i]) * (1 / 3)));
          }
        if(runningUnder() != SCREAMERNET) if(monstep()) return;
        }

      }

}

// CLIP

clip: min,max,n
{
    if(n < min) n = min;
    if(n > max) n = max;
    return(n);
}

load: what,io
{
    if(what == SCENEMODE)
    {
        iType = io.read().asInt();

        setdesc(sTitle + " - " + aType[iType]);
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        io.writeln(iType);
    }
}

options
{
    reqbegin(sTitle + " " + sVersion);


    // Control
    ctrl_c0 = ctlchoice("Type",iType,@"Solid","Luma","Luma Invert"@); // Type

    // Developer
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    return if !reqpost();

    iType = getvalue(ctrl_c0);

    setdesc(sTitle + " - " + aType[iType]);

    reqend();
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

Friday 15 March 2013

LScript - Image_Pixelate

LScript (Layout) to create a pixelated effect with envelope control.

Changes
  • Override alpha

Compatible with Newtek LightWave 9.6 and above.

// LScript Image Filter - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/* 
    LScript Image Filter - Pixelate

    Image_Pixelate.ls

*/

@version 2.5
@warnings
@script image
@name *Pixelate

    // Title
    sTitle = "*Pixelate";

    // Version
    sVersion = "v1.0";

    // Envelope
    envSize; // Size

    // Control
    ctrl_c0;

create
{
    setdesc(sTitle);

    // Envelope
    envSize = Envelope("Size (" + sTitle + ")",CHAN_NUMBER,sTitle); // Size
    envSize.persist(false);
    envSize.createKey(0,20.0);
}

process: ifo
{
    // Variable
    iSize = ceil(envSize.value(Scene().currenttime));

    // Error
    if(iSize < 2){return;}
    if(ifo.width < 1 || ifo.height < 1){return;}

    iGridX = ceil(ifo.width / iSize);
    iGridY = ceil(ifo.height / iSize);

    iGridXOffset = abs((ifo.width - (iGridX * iSize)) * 0.5);
    iGridYOffset = abs((ifo.height - (iGridY * iSize)) * 0.5);

    iProgress = iGridX * iGridY;
    if(runningUnder() != SCREAMERNET) moninit(iProgress);

    for(y = 0;y <= iGridY - 1; ++y)
      {

      for(x = 0;x <= iGridX - 1; ++x)
        {
        v1 = ;
        v2 = ;

        // Draw 
        pixelateIFO(ifo,v1,v2);

        if(runningUnder() != SCREAMERNET) if(monstep()) return;
        }      
      }
  
}

pixelateIFO: ifo,v1,v2 // vector,red,green,blue
{
    // Order
    if(v1.x > v2.x){n = v2.x;v2.x = v1.x; v1.x = n;}
    if(v1.y > v2.y){n = v2.y;v2.y = v1.y; v1.y = n;}

    if(v1.x < 1 || v2.x > ifo.width ||
       v1.y < 1 || v2.y > ifo.height)
      {
      // Offscreen
      if(v2.x < 1){return;}
      if(v1.x > ifo.width){return;}
      if(v2.y < 1){return;}
      if(v1.y > ifo.width){return;}
  
      // Clip
      if(v1.x < 1){v1.x = 1;}
      if(v1.x > ifo.width){v1.x = ifo.width;}
      if(v1.y < 1){v1.y = 1;}
      if(v1.y > ifo.height){v1.y = ifo.height;}
      if(v2.x < 1){v2.x = 1;}
      if(v2.x > ifo.width){v2.x = ifo.width;}
      if(v2.y < 1){v2.y = 1;}
      if(v2.y > ifo.height){v2.y = ifo.height;}
      }

    r = 0;
    g = 0;
    b = 0;
    c = 0;
    
    // Average
    for(y = v1.y; y <= v2.y; ++y)
      {
      for(x = v1.x; x <= v2.x; ++x)
        {
        r += ifo.red[x,y];
        g += ifo.green[x,y];
        b += ifo.blue[x,y];
        ++c;
        }
      }

    if(c > 1)
      {
      r *= 1 / c;
      g *= 1 / c;
      b *= 1 / c;
      }

    // Draw
    for(y = v1.y; y <= v2.y; ++y)
      {
      for(x = v1.x; x <= v2.x; ++x)
        {
        ifo.red[x,y] = r;
        ifo.green[x,y] = g;
        ifo.blue[x,y] = b;
        ifo.alpha[x,y] = 1.0;
        }
      }
}

load: what,io
{
    if(what == SCENEMODE)   // processing an ASCII scene file
    {
        if(io.read().asStr() == sTitle + " " + sVersion)
            {
            // Envelope
            envSize.load(); // Size
            }
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {    
        // Header
        io.writeln(sTitle + " " + sVersion);

        // Envelope
        envSize.save(); // Size
    }
}

options
{
    if(reqisopen())
        {
        reqend();
        return;
        }

    reqbegin(sTitle + " " + sVersion);

    ctrl_c0 = ctlpercent("Size",envSize.value(Scene().currenttime) * 0.01); // Size
    ctrl_c1e = ctlbutton("E",20,"button_c1e"); // Button

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    // Refresh
    ctlrefresh(ctrl_c0,"refresh_c0"); // Size

    reqopen();
}

button_c1e // Size
{
    envSize.edit();
}

refresh_c0:value // Size
{
    setvalue(ctrl_c0,max(0.0,value));
    iKey = envSize.keyExists(Scene().currenttime);
    if(iKey == nil)
        {envSize.createKey(Scene().currenttime,max(0.0,value * 100));}
    else
        {envSize.setKeyValue(iKey,max(0.0,value * 100));}
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

Monday 11 March 2013

LScript - Image_DigitalArtifacts

LScript (Layout) to create compressed video artifact effect.

Compatible with Newtek LightWave 9.6 and above.

// LScript Image Filter - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/* 
    LScript Image Filter - Digital Artifacts

    Image_DigitalArtifacts.ls

*/

@version 2.5
@warnings
@script image
@name *Digital Artifacts

    // Title
    sTitle = "*Digital Artifacts";

    // Version
    sVersion = "v1.0";

    iBlockSize = 8;
    iLifeRed = 2;
    iLifeGreen = 2;
    iLifeBlue = 2;
    nErrorRed = 0.03;
    nErrorGreen = 0.03;
    nErrorBlue = 0.03;
    bColorSync = false;

    aBlock = nil; // Block

    // Control
    ctrl_pr0,ctrl_c0,ctrl_c1,ctrl_c2,ctrl_c3,ctrl_c4,ctrl_c5,ctrl_c6,ctrl_c7; 

create
{
    setdesc(sTitle);
}

process: ifo
{

    // Error
    if(ifo.width < 1 || ifo.height < 1){return;}

    // Variable

    iBlock = 1;
    iBlockMultiplier = 1 / (iBlockSize * iBlockSize);
    iGridX = floor(ifo.width / iBlockSize);
    iGridY = floor(ifo.height / iBlockSize);
    _nErrorRed = nErrorRed * (iBlockSize * iBlockSize);
    _nErrorGreen = nErrorGreen * (iBlockSize * iBlockSize);
    _nErrorBlue = nErrorBlue * (iBlockSize * iBlockSize);

    // Init Block
    if(aBlock.size() <> (iGridX * iGridY) || ifo.frame == 0)
      {
      for(b = 1; b <= (iGridX * iGridY); ++b)
        {
        aBlock[b,1] = 0; // Red Count 
        aBlock[b,2] = 0; // Green Count 
        aBlock[b,3] = 0; // Blue Count 
        aBlock[b,4] = 0.0; // Red
        aBlock[b,5] = 0.0; // Green
        aBlock[b,6] = 0.0; // Blue
        } 
      }   

    iProgress = iGridX * iGridY;
    if(runningUnder() != SCREAMERNET) moninit(iProgress);

    for(gy = 0;gy <= iGridY - 1; ++gy)
      {

      for(gx = 0;gx <= iGridX - 1; ++gx)
        {
 
        _gx = gx * iBlockSize; 
        _gy = gy * iBlockSize; 

        r = 0;
        g = 0;
        b = 0;

        // Average
        for(i = 1;i <= iBlockSize; ++i)
          {
          for(j = 1;j <= iBlockSize; ++j)
            {
            r += ifo.red[j + _gx,i + _gy]; // Red
            g += ifo.green[j + _gx,i + _gy]; // Green
            b += ifo.blue[j + _gx,i + _gy]; // Blue
            }
          }

        r *= iBlockMultiplier;
        g *= iBlockMultiplier;
        b *= iBlockMultiplier;

        // Difference 
        rd = 0;
        gd = 0;
        bd = 0;

        for(i = 1;i <= iBlockSize; ++i)
          {
          for(j = 1;j <= iBlockSize; ++j)
            {
            rd += abs(ifo.red[j + _gx,i + _gy] - r);
            gd += abs(ifo.green[j + _gx,i + _gy] - g);
            bd += abs(ifo.blue[j + _gx,i + _gy] - b);
            }
          }

        // Update Block
        if(bColorSync)
          { 
          if((aBlock[iBlock,1] <= 0 && rd < _nErrorRed) || 
             (aBlock[iBlock,2] <= 0 && gd < _nErrorGreen) || 
             (aBlock[iBlock,3] <= 0 && bd < _nErrorBlue)) 
            {
            c = random(1,3);
            aBlock[iBlock,1] = c;
            aBlock[iBlock,2] = c;
            aBlock[iBlock,3] = c;
            }
          aBlock[iBlock,4] = r;
         aBlock[iBlock,5] = g;
         aBlock[iBlock,6] = b;
         }
       else
         {
         if(aBlock[iBlock,1] <= 0 && rd < _nErrorRed) // Red
           {
           aBlock[iBlock,1] = random(1,iLifeRed);
           aBlock[iBlock,4] = r;
           }

         if(aBlock[iBlock,2] <= 0 && gd < _nErrorGreen) // Green
           {
           aBlock[iBlock,2] = random(1,iLifeGreen);
           aBlock[iBlock,5] = g;
           }

         if(aBlock[iBlock,3] <= 0 && bd < _nErrorBlue) // Blue
           {
           aBlock[iBlock,3] = random(1,iLifeBlue);
           aBlock[iBlock,6] = b;
           }
         }
        
        // Read Block
        rd = aBlock[iBlock,1];
        --aBlock[iBlock,1];
        r =  aBlock[iBlock,4];
        gd = aBlock[iBlock,2];
        --aBlock[iBlock,2];
        g =  aBlock[iBlock,5];
        bd = aBlock[iBlock,3];
        --aBlock[iBlock,3];
        b =  aBlock[iBlock,6];

        // Draw Block
        for(i = 1;i <= iBlockSize; ++i)
          {
          for(j = 1;j <= iBlockSize; ++j)
            {
            if(rd > 0){ifo.red[j + _gx,i + _gy] = r;}
            if(gd > 0){ifo.green[j + _gx,i + _gy] = g;}
            if(bd > 0){ifo.blue[j + _gx,i + _gy] = b;}
            }
          }

        ++iBlock;

        if(runningUnder() != SCREAMERNET) if(monstep()) return;
        }      
      }
  
}

// CLIP

clip: min,max,n
{
    if(n < min) n = min;
    if(n > max) n = max;
    return(n);
}

load: what,io
{
    if(what == SCENEMODE)
    {
        bColorSync = io.read().asInt();
        iBlockSize = io.read().asInt();
        iLifeRed = io.read().asInt();
        iLifeGreen = io.read().asInt();
        iLifeBlue = io.read().asInt();
        nErrorRed = io.read().asNum();
        nErrorGreen = io.read().asNum();
        nErrorBlue = io.read().asNum();
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        io.writeln(bColorSync);                
        io.writeln(iBlockSize);         
        io.writeln(iLifeRed);  
        io.writeln(iLifeGreen);
        io.writeln(iLifeBlue);        
        io.writeln(nErrorRed);         
        io.writeln(nErrorGreen);         
        io.writeln(nErrorBlue);         
    }
}

options
{
    reqbegin(sTitle + " " + sVersion);

    // Control
    ctrl_pr0 = ctlpopup("Preset",1, @"Low",
                                     "Medium",
                                     "High",
                                     "Extreme"@);

    ctlsep();
    ctrl_c0 = ctlinteger("Block Size",iBlockSize);
    ctrl_c1 = ctlcheckbox("Color Sync",bColorSync);
    ctrl_c2 = ctlinteger("Life Red",iLifeRed);
    ctrl_c3 = ctlinteger("     Green",iLifeGreen);
    ctrl_c4 = ctlinteger("     Blue",iLifeBlue);
    ctrl_c5 = ctlpercent("Error Red",nErrorRed);
    ctrl_c6 = ctlpercent("      Green",nErrorGreen);
    ctrl_c7 = ctlpercent("      Blue",nErrorBlue);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    // Refresh
    ctlrefresh(ctrl_pr0,"refresh_preset"); // Preset
    ctlrefresh(ctrl_c0,"refresh_c0"); // Block Size
    ctlrefresh(ctrl_c2,"refresh_c2"); // Life Red
    ctlrefresh(ctrl_c3,"refresh_c3"); // Life Green
    ctlrefresh(ctrl_c4,"refresh_c4"); // Life Blue

    ctlrefresh(ctrl_c5,"refresh_c5"); // Error Red
    ctlrefresh(ctrl_c6,"refresh_c6"); // Error Green
    ctlrefresh(ctrl_c7,"refresh_c7"); // Error Blue

    return if !reqpost();

    iBlockSize = max(1,getvalue(ctrl_c0));
    bColorSync = getvalue(ctrl_c1);
    iLifeRed = max(1,getvalue(ctrl_c2));
    iLifeGreen = max(1,getvalue(ctrl_c3));
    iLifeBlue = max(1,getvalue(ctrl_c4));
    iErroRed = max(0.0,getvalue(ctrl_c5));
    iErrorGreen = max(0.0,getvalue(ctrl_c6));
    iErrorBlue = max(0.0,getvalue(ctrl_c7));

    reqend();
}

refresh_preset:value
{
    if(value == 1) // Low
      {
      setvalue(ctrl_c0,8); // Block Size
      setvalue(ctrl_c1,0); // Sync Color
      setvalue(ctrl_c2,1); // Life Red
      setvalue(ctrl_c3,1); // Life Green
      setvalue(ctrl_c4,1); // Life Blue
      setvalue(ctrl_c5,0.02); // Error Red
      setvalue(ctrl_c6,0.02); // Error Green
      setvalue(ctrl_c7,0.02); // Error Blue
      }  

    if(value == 2) // Medium
      {
      setvalue(ctrl_c0,8); // Block Size
      setvalue(ctrl_c1,0); // Sync Color
      setvalue(ctrl_c2,2); // Life Red
      setvalue(ctrl_c3,2); // Life Green
      setvalue(ctrl_c4,2); // Life Blue
      setvalue(ctrl_c5,0.02); // Error Red
      setvalue(ctrl_c6,0.03); // Error Green
      setvalue(ctrl_c7,0.04); // Error Blue
      } 

    if(value == 3) // High
      {
      setvalue(ctrl_c0,8); // Block Size
      setvalue(ctrl_c1,0); // Sync Color
      setvalue(ctrl_c2,3); // Life Red
      setvalue(ctrl_c3,3); // Life Green
      setvalue(ctrl_c4,3); // Life Blue
      setvalue(ctrl_c5,0.02); // Error Red
      setvalue(ctrl_c6,0.04); // Error Green
      setvalue(ctrl_c7,0.06); // Error Blue
      }

    if(value == 4) // Extreme
      {
      setvalue(ctrl_c0,8); // Block Size
      setvalue(ctrl_c1,0); // Sync Color
      setvalue(ctrl_c2,9); // Life Red
      setvalue(ctrl_c3,9); // Life Green
      setvalue(ctrl_c4,9); // Life Blue
      setvalue(ctrl_c5,0.1); // Error Red
      setvalue(ctrl_c6,0.1); // Error Green
      setvalue(ctrl_c7,0.1); // Error Blue
      }
}

refresh_c0:value // Block Size
{
    iBlockSize = max(1,value);
    setvalue(ctrl_c0,iBlockSize);
}

refresh_c2:value // Life Red
{
    iLifeRed = max(1,value);
    setvalue(ctrl_c2,iLifeRed);
}

refresh_c3:value // Life Green
{
    iLifeGreen = max(1,value);
    setvalue(ctrl_c3,iLifeGreen);
}

refresh_c4:value // Life Blue
{
    iLifeBlue = max(1,value);
    setvalue(ctrl_c4,iLifeBlue);
}

refresh_c5:value // Error Red
{
    nErrorRed = clip(0.0,1.0,value);
    setvalue(ctrl_c5,nErrorRed);
}

refresh_c6:value // Error Green
{
    nErrorGreen = clip(0.0,1.0,value);
    setvalue(ctrl_c6,nErrorGreen);
}

refresh_c7:value // Error Blue
{
    nErrorBlue = clip(0.0,1.0,value);
    setvalue(ctrl_c7,nErrorBlue);
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

Monday 4 March 2013

LScript - Image_DepthDesaturation


LScript (Layout) desaturates the image based on depth buffer.

Compatible with Newtek LightWave 9.6 and above.

// LScript Image Filter - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/* 
    LScript Image Filter - Depth Desaturate

    Image_DepthDesaturate.ls

*/

@version 2.5
@warnings
@script image
@name *Depth Desaturate

    // Title
    sTitle = "*Depth Desaturate";

    // Version
    sVersion = "v1.0";

    nAmount = 1.0;  
    nMin = 1.0;
    nMax = 10.0;

    // Control
    ctrl_c0;  

create
{
    setdesc(sTitle);
}

process: ifo
{
    iProgress = ifo.height;
    if(runningUnder() != SCREAMERNET) moninit(iProgress);
    for(i = 1;i <= ifo.height;++i)
      {
      for(j = 1;j <= ifo.width;++j)
        {
        nAverage = (ifo.red[j,i] + ifo.green[j,i] + ifo.blue[j,i]) * 0.3333333333;
        nDepth = clip(0.0,1.0,maprange01(nMin,nMax,ifo.depth[j,i]));        
        ifo.red[j,i] = ifo.red[j,i] - (nAmount * nDepth) * (ifo.red[j,i] - nAverage);
        ifo.green[j,i] = ifo.green[j,i] - (nAmount * nDepth) * (ifo.green[j,i] - nAverage);
        ifo.blue[j,i] = ifo.blue[j,i] - (nAmount * nDepth) * (ifo.blue[j,i] - nAverage);
        }
      if(runningUnder() != SCREAMERNET) if(monstep()) return;
      }
}

// CLIP

clip: min,max,n
{
    if(n < min) n = min;
    if(n > max) n = max;
    return(n);
}

// MAP RANGE

maprange01: n1,n2,i
{    
    if(n2-n1 == 0.0){return(0.0);}
  else
    {return((1/(n2-n1)) * (i-n1));}
}

load: what,io
{
    if(what == SCENEMODE)
    {
        nAmount = io.read().asNum();
        nMin = io.read().asNum();
        nMax = io.read().asNum();
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        io.writeln(nAmount);         
        io.writeln(nMin);         
        io.writeln(nMax);         
    }
}


options
{
    reqbegin(sTitle + " " + sVersion);

    // Control
    ctrl_c0 = ctlpercent("Amount",nAmount);
    ctrl_c1 = ctlnumber("Min (m)",nMin);
    ctrl_c2 = ctlnumber("Max (m)",nMax);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    // Refresh
    ctlrefresh(ctrl_c0,"refresh_c0"); // Amount

    return if !reqpost();

    nAmount = clip(0.0,1.0,getvalue(ctrl_c0));
    nMin = getvalue(ctrl_c1);
    nMax = getvalue(ctrl_c2);

    reqend();
}

refresh_c0:value // Amount
{
    nAmount = clip(0.0,1.0,value);
    setvalue(ctrl_c0,nAmount);
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

LScript - Image_Depth


LScript (Layout) to create a grey scale representation of the depth buffer.

Compatible with Newtek LightWave 9.6 and above.

// LScript Image Filter - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/* 
    LScript Image Filter - Depth

    Image_Depth.ls

*/

@version 2.5
@warnings
@script image
@name *Depth

    // Title
    sTitle = "*Depth";

    // Version
    sVersion = "v1.0";

    nMin = 0.0;
    nMax = 10.0;

create
{
    setdesc(sTitle);
}

process: ifo
{
    iProgress = ifo.height;
    if(runningUnder() != SCREAMERNET) moninit(iProgress);
    for(i = 1;i <= ifo.height;++i)
      {
      for(j = 1;j <= ifo.width;++j)
        {
        nDepth = 1 - clip(0.0,1.0,maprange01(nMin,nMax,ifo.depth[j,i]));        
        ifo.red[j,i] = nDepth;
        ifo.green[j,i] = nDepth;
        ifo.blue[j,i] = nDepth;
        }
      if(runningUnder() != SCREAMERNET) if(monstep()) return;
      }
}

// CLIP

clip: min,max,n
{
    if(n < min) n = min;
    if(n > max) n = max;
    return(n);
}

// MAP RANGE

maprange01: n1,n2,i
{    
    if(n2-n1 == 0.0){return(0.0);}
  else
    {return((1/(n2-n1)) * (i-n1));}
}

load: what,io
{
    if(what == SCENEMODE)
    {
        nMin = io.read().asNum();
        nMax = io.read().asNum();
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        io.writeln(nMin);         
        io.writeln(nMax);         
    }
}

options
{
    reqbegin(sTitle + " " + sVersion);

    // Control
    ctrl_c0 = ctlnumber("Min (m)",nMin);
    ctrl_c1 = ctlnumber("Max (m)",nMax);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    return if !reqpost();

    nMin = getvalue(ctrl_c0);
    nMax = getvalue(ctrl_c1);

    reqend();
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

Monday 18 February 2013

LScript - Generic_Blueprint


LScript (Layout) to quickly setup a scene to produce a blueprint look.

Please be aware this script overrides objects surfaces settings.

Compatible with Newtek LightWave 9.6 and above.

// LScript Generic - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/*  
    LScript Generic - Blueprint

    Generic_Blurprint.ls

*/

@version 2.2
@warnings
@script generic
@name *Blurprint

    sTitle = "*Blueprint";
    sVersion = "v1.0";    

generic
{
    reqbegin(sTitle + " " + sVersion);

    ctrl_c0 = ctlcolor("Background",<60,100,200>);
    ctrl_c1 = ctlcolor("Lines",<255,255,255>);
    ctrl_c2 = ctlnumber("Opacity",0.2);
    ctrl_c3 = ctlchoice("Show",1,@ "Edge","All" @,false);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    return if !reqpost();   

    vBackgroundColor = getvalue(ctrl_c0);
    vLineColor = getvalue(ctrl_c1) * (1/255);
    nOpacity = getvalue(ctrl_c2);
    if(getvalue(ctrl_c3) == 2){iPolygonEdgeFlag = 31;}else{iPolygonEdgeFlag = 15;}
    
    // Background Color
    if(Scene().backdroptype == GRADIENT){CommandInput("GradientBackdrop");}
    CommandInput("BackdropColor " +  (vBackgroundColor.x * (1/255)) + " " + (vBackgroundColor.y * (1/255)) + " " + (vBackgroundColor.z * (1/255)));

    // Item
    Item = Mesh();
    while(Item)
      {

      if(Item.isMesh())
        {
        SelectItem(Item.id);
        CommandInput("PolygonEdgeFlags " + iPolygonEdgeFlag);
        CommandInput("PolygonEdgeThickness 1 1 1 1 1");
        CommandInput("PolygonEdgeColor " + vLineColor.x + " " + vLineColor.y + " " + vLineColor.z);

        // Surface
        Surface = Surface();
        while(Surface)
          {
          Surface.setValue(SURFCOLR,vBackgroundColor); // Color
          Surface.setValue(SURFLUMI,1.0); // Luminosity
          Surface.setValue(SURFDIFF,0.0); // Diffuse
          Surface.setValue(SURFSPEC,0.0); // Specularity
          Surface.setValue(SURFREFL,0.0); // Reflection
          Surface.setValue(SURFTRAN,nOpacity); // Transparency
          Surface.setValue(SURFTRNL,0.0); // Translucency
          Surface.setValue(SURFBUMP,0.0); // Bump
          Surface.setValue(SURFSIDE,1); // Sided
          Surface = Surface.next();
          }

        }

      Item = Item.next();
      }

    info(sTitle + " " + sVersion + " - developer: Stephen Culley - http://www.stephenculley.co.uk");
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

LScript - Generic_BoxRig (v1.1)

LScript (Layout) to rig a box so that it can pivot upon its edges and corners. This script sets up the hiearchy and expressions required ready for animation upon any selected objects.

Use "Parent" null to position and rotate box and "Control" null to animate using the rig.

Problem
  • Under LightWave 11 Item Shape is broken due to changes in comring
Changes
  • Fixed parenting (v1.1)
  • Objects require pivot to be resting on ground and centre of object
  • Does not work on clones due to expressions
  • Fixed getting correct boundingbox extents from layers
  • Fixed Parent in Place issues
  • Fixed offset when pivot not at bottom of object
Compatible with Newtek LightWave 9.6 up and prior to 11.0.

// LScript Generic - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/*  
    LScript Generic - BoxRig

    Generic_BoxRig.ls

*/

@version 2.2
@warnings
@script generic
@name *Box Rig
  
    // Title
    sTitle = "*Box Rig";

    // Version
    sVersion = "v1.1";    

generic
{

    // Item Select
    Items = Scene().getSelect();  
    if(Items == nil)
      {
      info("Select an object.");
      return;
      }

    // Parent in Place
    bParentInPlace = Scene().generalopts[3];
    if(bParentInPlace){ParentInPlace();}

    for(i = 1; i <= Items.size(); i++)
      {

      if(Items[i].genus == MESH && !Items[i].null)
        {

        GoToFrame(0);

        SelectItem(Items[i].id);
 
        // Box Item
        BoxItem = Mesh(0); // Get Box
        BoxItem_Parent = BoxItem.parent; // Parent
        vPivot = BoxItem.getPivot(0.0);
        vPosition = BoxItem.getPosition(0.0); // Position
        vRotation = BoxItem.getRotation(0.0); // Rotation
        vScaling = BoxItem.getScaling(0.0); // Scaling
        aBoundingBox = BoxItem.position(getlayernumber(BoxItem)); // Bounding Box
        aBoundingBox[1] -= vPivot; 
        aBoundingBox[2] -= vPivot;

        sName = BoxItem.name; // Name

        // Reset Box
        Position(0.0,-aBoundingBox[1].y,0.0);
        Rotation(0.0,0.0,0.0);
        Scale(1.0,1.0,1.0);
        CreateKey(0);

        // Parent Item
        AddNull(sName + "_Parent");
        ParentItem = Mesh(sName + "_Parent"); // Assign to a var       
        ItemColor(12); // Color Dark Red
        Position();
        Rotation(vRotation);
        Scale(vScaling);
        CreateKey(0);
        if(BoxItem_Parent != nil){ParentItem(BoxItem_Parent.id);} // Parent

        // Pivot Item
        AddNull(sName + "_Pivot");
        PivotItem = Mesh(sName + "_Pivot"); // Assign to a var
        ItemColor(5); // Color Dark Red
        ParentItem(ParentItem.id); // Parent

        // Shift Item
        AddNull(sName + "_Shift");
        ShiftItem = Mesh(sName + "_Shift"); // Assign to a var
        ItemColor(5); // Color Dark Red
        ParentItem(PivotItem.id); // Parent
        MoveTool();
        EnableXH();
        EnableYP();
        EnableZB();
        RotateTool();
        EnableXH();
        EnableYP();
        EnableZB();
        SquashTool();
        EnableXH();
        EnableYP();
        EnableZB();

        // Box Item
        BoxItem.select();
        ParentItem(ShiftItem.id); // Parent
        ItemColor(7); // Color Brown
        MoveTool();
        EnableYP();
        RotateTool();
        EnableYP();
        EnableZB();
        SquashTool();
        EnableXH();
        EnableYP();
        EnableZB();

        // Extent Item
        AddNull(sName + "_Extent");
        ExtentItem = Mesh(sName + "_Extent"); // Assign to a var
        ItemColor(5); // Color Dark Red
        ParentItem(ParentItem.id); // Parent
        Position(aBoundingBox[2].x,0.0,aBoundingBox[2].z);
        CreateKey(0);
        MoveTool();
        EnableYP();
        RotateTool();
        EnableXH();
        EnableYP();
        EnableZB();
        SquashTool();
        EnableXH();
        EnableYP();
        EnableZB();

        // Control Item
        AddNull(sName + "_Control");
        ControlItem = Mesh(sName + "_Control"); // Assign to a var
        ItemColor(12); // Color Red
        ParentItem(ParentItem.id); // Parent
        MoveTool();
        EnableYP();
        RotateTool();
        EnableYP();
        EnableZB();
        SquashTool();
        EnableXH();
        EnableYP();
        EnableZB();

        // Custom
        customshape(ParentItem,nil,0,nil,"Parent");
        customshape(PivotItem,ParentItem,8,nil,"Pivot");
        customshape(ShiftItem,ParentItem,8,nil,"Shift");
        customshape(BoxItem,ParentItem,8,nil,"");
        customshape(ExtentItem,ParentItem,8,nil,"Extent");
        customshape(ControlItem,ParentItem,6,0.15,"Control");

    // EXPRESSIONS

        // Shift_X
        createexpression(sName + "_Shift_X","max(min((( - ([" + sName + "_Control.Position.X] * 1000) ) * (1 / 5)) * (  [" + sName + "_Extent.Position.X]  ),[" + sName + "_Extent.Position.X]),-[" + sName + "_Extent.Position.X])");
        ShiftItem.select();
        attachexpression(sName + "_Shift_X",sName + "_Shift.Position.X");

        // Shift_Z
        createexpression(sName + "_Shift_Z","max(min((( - ([" + sName + "_Control.Position.Z] * 1000) ) * (1 / 5)) * (  [" + sName + "_Extent.Position.Z]  ),[" + sName + "_Extent.Position.Z]),-[" + sName + "_Extent.Position.Z])");
        ShiftItem.select();
        attachexpression(sName + "_Shift_Z",sName + "_Shift.Position.Z");

        // Pivot_X
        createexpression(sName + "_Pivot_X","min(max((( - ([" + sName + "_Control.Position.X] * 1000) ) * (1 / 5)) * (  -[" + sName + "_Extent.Position.X]  ),-[" + sName + "_Extent.Position.X]),[" + sName + "_Extent.Position.X])");
        PivotItem.select();
        attachexpression(sName + "_Pivot_X",sName + "_Pivot.Position.X");

        // Pivot_Z
        createexpression(sName + "_Pivot_Z","min(max((( - ([" + sName + "_Control.Position.Z] * 1000) ) * (1 / 5)) * (  -[" + sName + "_Extent.Position.Z]  ),-[" + sName + "_Extent.Position.Z]),[" + sName + "_Extent.Position.Z])");
        PivotItem.select();
        attachexpression(sName + "_Pivot_Z",sName + "_Pivot.Position.Z");

        // Pivot_H
        createexpression(sName + "_Pivot_H","[" + sName + "_Control.Rotation.H]");
        PivotItem.select();
        attachexpression(sName + "_Pivot_H",sName + "_Pivot.Rotation.H");

        // Pivot_P
        createexpression(sName + "_Pivot_P","mapRange([" + sName + "_Control.Position.Z],0.000,[" + sName + "_Extent.Position.Z],0.000,90.000)");
        PivotItem.select();
        attachexpression(sName + "_Pivot_P",sName + "_Pivot.Rotation.P");

        // Pivot_B
        createexpression(sName + "_Pivot_B","- mapRange([" + sName + "_Control.Position.X],0.000,[" + sName + "_Extent.Position.X],0.000,90.000)");
        PivotItem.select();
        attachexpression(sName + "_Pivot_B",sName + "_Pivot.Rotation.B");

    //

        // Control
        ControlItem.select();
        MoveTool();

        }

      }

    // Parent in Place
    if(bParentInPlace){ParentInPlace();}

    info(sTitle + " " + sVersion + " - developer: Stephen Culley - http://www.stephenculley.co.uk");
}

getlayernumber: item
{
    if(item.totallayers == 1){return(1);}
    sTokens = parse(":",item.name);
    iLayer = 0;
    if (strleft(sTokens[2],5)=="Layer")
      {
      iLayer = integer(sTokens[2]);
      }
    else
      {
      iTotal = item.totallayers;
      for(i = 1; i <= iTotal; i++)
        {
        if(item.layerVisible(i) == 1)
          {
          if(item.layerName(i) == sTokens[2])
            {
            iLayer = i;
            break;
            }
          }
        else
          {
          iTotal++;
          }
        }
      }
  return iLayer;
}

createexpression: name, expression
{
    CommandInput("GE_CreateExpression " + "\"" + name + "\"" + " " + "\"" + expression + "\"");
} 

attachexpression: name,channel
{
    CommandInput("GE_OpenWindow");
    CommandInput("GE_SetEnv " + "\"" + channel);
    CommandInput("GE_AttachExpression " + "\"" + channel + "\"" + name);
}

customshape: item,linkto,shape,scale,label
{
    SelectItem(item.id);
    ApplyServer("CustomObjHandler","LW_ItemShape");

    // ItemShapeData structure
    aItemShapeData = @"p",                // ctxt
                      "p","p",            // self, linkTo
                      "d","d","d",        // time, level, scale
                      "i","i","i","i",    // axis, fill, shape, flags
                      "f","f","f",        // clrA
                      "f","f","f",        // clrB
                      "f","f","f",        // clrT
                      "d","d","d",        // linkPos
                      "s:120",            // label
                      "s:100",            // desc
                      "p",                // alreadylist
                      "s:256",            // selfname
                      "s:256",            // linktoname
                      "i"@;               // justify
                    
    comringattach("ItemShapeComRing", "shapecomring");
    aDataBlob = comringencode(aItemShapeData,
                              0,
                              item.id, 0,
                              0.0, 0.0, 0.0,
                              0, 0, 0, 0,
                              0.0, 0.0, 0.0,
                              0.0, 0.0, 0.0,
                              0.0, 0.0, 0.0,
                              0.0, 0.0, 0.0,
                              "",
                              "",
                              0,
                              "",
                              "",
                              0);

    comringmsg("ItemShapeComRing", 100, aDataBlob);
    aItemShape = comringdecode(aItemShapeData, aDataBlob);
    if(linkto != nil){aItemShape[3] = linkto.id;}    // linkto
    if(scale != nil){aItemShape[6] = scale;}    // Scale
    aItemShape[7] = 1;    // Axis
    aItemShape[9] = shape;    // Shape
    aItemShape[23] = label; // Label
    if(linkto != nil)
        aItemShape[27] = linkto.name;  // linkto name
    aDataBlob = comringencode(aItemShapeData,
                                aItemShape[1],
                                aItemShape[2],aItemShape[3],
                                aItemShape[4],aItemShape[5],aItemShape[6],
                                aItemShape[7],aItemShape[8],aItemShape[9],aItemShape[10],
                                aItemShape[11],aItemShape[12],aItemShape[13],
                                aItemShape[14],aItemShape[15],aItemShape[16],
                                aItemShape[17],aItemShape[18],aItemShape[19],
                                aItemShape[20],aItemShape[21],aItemShape[22],
                                aItemShape[23],
                                aItemShape[24],
                                aItemShape[25],
                                aItemShape[26],
                                aItemShape[27],
                                aItemShape[28]);
    comringmsg("ItemShapeComRing", 200, aDataBlob);
    comringdetach("ItemShapeComRing");
}

shapecomring: code, data
{
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs