# LScript v2.2 Release Notes

## New Features

      All 20 LScript plug-ins have been integrated into a single disc file.  Further, LScript has
      been integrated into LCore, making it now an internal subsystem.
      A new Mesh Object Agent data member has been added, called "flags".  This data member is an
      array of five elements.  The first three duplicate the values found in the shadows[] data
      member.  The remaining two, flags[4] and flags[5], indicate the object's current
      "Unseen By Camera" and "Unseeen By Rays" settings.

      This new data member is intended to replace the existing shadows[] data member.  You should
      begin using this data member in future scripts as the shadows[] data memeber will eventually
      be removed from the Object Agent.
      A series of new identification methods have been added to the Object Agent class.
      These methods return a boolean true/false indicating the type of the object for
      which the Object Agent is a proxy.

            isMesh()
            isLight()
            isCamera()
            isBone()
            isScene()
            isImage()
            isChannel()
            isEnvelope()
            isVMap()
            isChannelGroup()
      The Image Object Agent now includes two new methods, alpha() and alphaSpot(), and a new data
      member called hasAlpha, for accessing Alpha-channel image data.

      The hasAlpha data member is a Boolean flag that indicates whether or not the image contains any
      Alpha image data.  If this flag is true, then the Alpha data can be accessed using the new methods.

      The new alpha() method functions just like the Image Object Agent rgb() method.  Given an (x,y)
      position within the image, the Alpha value for that pixel will be returned.  Alpha-channel data
      contains only one numeric value for each triplet RGB value.

      alphaSpot() functions just like rgbSpot(), with the exception that it only returns a single
      numeric value.
      The reqabort() function has been added to the Requester system.  This function is intended to be
      called from within a control or requester callback function, and will immediately terminate the
      posted requester.  No user intervention is required.

      When reqabort() is called without arguments, a "Cancel" result is returned to the reqpost() function.
      This simulates a user press of that button.  If a true value is provided to reqabort(), then an "Ok"
      result is passed to reqpost().

            generic
            {
                reqbegin("Reqabort() Test");

                reqsize(200,180);

                c1 = ctlstate("Goodbye",0,50,"goodbye");

                ctlposition(c1,35,10);

                if(reqpost())
                    info("You pressed OK");
                else
                    info("You pressed Cancel");

                reqend();
            }

            goodbye: val
            {
            //    reqabort();
                reqabort(true);
            }
      The ctlposition() function now accepts three additional, optional numeric arguments.  These
      new arguments provide access to sizeable requester controls in LScript.

      The third argument indicates the width (in pixels) of the control.  The fourth indicates the
      height (also in pixels) of the control.

      The fifth indicates the offset value for the control.  An offset value can be used to control
      the width of the label field for controls that have labels, or the distance a control is
      shifted to the right from its left-most position for those without labels.
      New selection types have been added to the Modeler selpolygon() function.  You can now select
      BONE, PATCH, and MBALL elements within the mesh.

      BONE is a synonym for Skelegon, and you can in fact also specify SKELEGON.

      MBALL stands for Metaball.

      These selection types are without argument, and will select all elements of that type within
      the current mesh.
      A new Light Object Agent data member has been added, called "flags".  This data member is an
      array of six elements, each corresponding to the flag values returned by the SDK function.  More
      specifically, each element provides the following information about the Light:

            flags[1]        true if Limited Range is enabled
            flags[2]        true if Affect Diffuse is enabled
            flags[3]        true if Affect Specular is enabled
            flags[4]        true if Affect Caustics is enabled
            flags[5]        true if Lens Flare is enabled
            flags[6]        true if Volumetric is enabled
      The Image Filter architecture supports 5 new buffer types:

        MOTIONX          2D vector-based motion blur buffer containing X distance values
        MOTIONY          2D vector-based motion blur buffer containing Y distance values
        REFLECTRED       Red levels of the contribution from mirror reflections
        REFLECTGREEN     Green levels of the contribution from mirror reflections
        REFLECTBLUE      Blue levels of the contribution from mirror reflections

      All new buffers are floating point, and must be accessed using the floatline()
      IF function.
      The Scene Object Agent has a new method called getSelect().  This method returns, as a list
      of Object Agents, all the items in a scene that are currently selected.  Called without arguments,
      all selected items--whether Mesh, Bone, Light, or Camera--will be returned.  A flag value can be
      specified to limit the view of selections to a particular genus.  Flags can be MESH, BONE, LIGHT,
      or CAMERA.

      This method is intended to simplfy the process of determining selected items, although the
      firstSelect() and nextSelect() methods are still available for special processing needs.
      The Scene Object Agent has a new data member called backdroptype.  This value holds the
      type of the current backdrop in the scene.  It can be either SOLID or GRADIENT.
      Several new backdrop-related methods have been added to the Scene Object Agent.

        backdropRay(time,ray)           This method returns the color value, as a vector, intersecting
                                        the given ray at the given time index.  The ray value must
                                        be normalized.

        backdropColor(time)             This method returns the color values for the zenith, sky, ground,
                                        and nadir, each as a vector, at the given time index.

        backdropSqueeze(time)           Returns the squeeze amount for the sky and ground, each as a
                                        floating point value, at the given time index.
      The Scene Object Agent has a new method called renderCamera().  Given a time index, this
      method will return the active camera in the scene at that time index as a Camera Object Agent.
      The Scene Object Agent has a new data member called fogtype.  This value holds the
      type of the fog active in the scene.  It can be one of NONE, LINEAR, NONLINEAR1,
      or NONLINEAR2.
      Many new fog-related methods have been added to the Scene Object Agent.

        fogMinDist(time)                This method returns the distance from the viewer (typically
                                        the camera) at which the fog effect is at a minimum.

        fogMaxDist(time)                This method returns the distance at which the fog effect
                                        reaches its maximum

        fogMinAmount(time)              Returns the minimum amount of fog (the amount at the minimum
                                        distance). Fog amounts range from 0.0 to 1.0.

        fogMaxAmount(time)              Returns the maximum amount of fog (the amount at the maximum
                                        distance).

        fogColor(time)                  This method returns, as a vector, the color of the fog at the
                                        given time index.
      The Scene Object Agent has three new data members that provide information about the scene's
      current compositing state.  compfg, compbg, and compfgalpha all contain either an Image Object
      Agent for the active compositing images (foreground, background, and foreground alpha,
      respectively), or they will contain 'nil' if no image is active for that position.
      A new Requester function has been added called requpdate().  This function can be used from
      within control callback functions to cause listboxes on the requester panel to refresh with
      new values.  It cannot be invoked from within a listbox count or value callback function,
      and will have no effect if it is.

                count;
                lb_items;

                generic
                {
                    for(count = 1;count <= 5;count++)
                        lb_items += "Item_" + count;

                    reqbegin("Testing requpdate()");

                    c1 = ctllistbox("Items",300,300,"lb_count","lb_value");
                    c2 = ctlbutton("Increment",200,"inc_button");

                    reqpost();
                }

                lb_count
                {
                    return(lb_items.count());
                }

                lb_value: index
                {
                    return(lb_items[index]);
                }

                inc_button
                {
                    x = count;
                    y = 1;
                    count += 5;

                    while(x <= count)
                    {
                        lb_items[y] = "Item_" + x;
                        ++x;
                        ++y;
                    }

                    requpdate();
                }
      Binary data can now be embedded directly within an LScript.  This data is handled by
      LScript as nothing more than a stream of unsigned bytes.  This allows any type of
      binary data to be embedded within the script and accessed at run-time.

      Binary data is delimited between a pair of preprocessor directives, "@data"
      and "@end".  Individual bytes are declared as integer values between 0 and 255.
      The data can be of any length on each line, but you should probably keep them
      under 80 columns for readibility and maximum editor compatibility.

      Each block of binary data must be named.  The name provided will become a global
      variable within the operating environment of the script when it begins to execute.

            @data bobdata
            070 079 082 077 000 000 039 064 076 087 079 050 084 065 071 083 000 000 000 010
            069 121 101 000 073 114 105 115 000 000 076 065 089 082 000 000 000 018 000 000
            ...
            @end

      The binary block identifiers exist at run-time just like any other global variable
      in your script.  They can be queried as Objects:

            info(bobdata.size());

      They can be used with the foreach() iterator:

            foreach(x,bobdata)
            {
                ...
            }

      They can be passed to functions:

            info(blocksize(bobdata));

            blocksize: data
            {
                return(data.size());
            }

      Their data can be accessed and modified as the script executes:

            x = bobdata[25];
            bobdata[25] = 0;

      As a side note, not only will your script sizes be considerably smaller, but parsing
      of the binary data will go slightly faster if values are included as a bare minimum.
      For instance, "0" will parse faster than "000", and consume two less bytes in the disc
      file.  The bytes in the examples above have been padded only for visual alignment, not
      out of any necessity.

      You can use this Generic script to generate syntactically correct LScript binary
      data from any disc file.  It will generate code to a new file, or you can specify
      an existing file (i.e., script) to which the generated code will be appended.
      A new File Object Agent method has been added specifically to handle block binary
      data.  Using writeData(), you can send the binary data in a block to a disc file.
      This can be used to re-create binary files from the embedded binary data within
      the script.  For instance, a LightWave object file can be embedded in a script
      and carried along with the script until needed:

            @version 2.2
            @warnings

            generic
            {
                output = File("ball.lwo","wb");
                output.writeData(ball);

                // important!  the file must be closed to flush any
                // remaining data to disc before the call to
                // LoadObject()

                output.close();

                LoadObject("ball.lwo");

                filedelete("ball.lwo");
            }

            @data ball
            070 079 082 077 000 000 039 064 076 087 079 050 084 065 071 083 000 000 000 010
            069 121 101 000 073 114 105 115 000 000 076 065 089 082 000 000 000 018 000 000
            000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 080 078 084 083
            ...
            @end
      A new global constant value called SCRIPTID exists in the LScript operating environment.
      This constant holds the full path and filename of the script currently being executed.
      The listbox control now has a fourth, optional callback function that allows you to specify
      which entries in the control can be selected by the user.  The select callback function
      should take an integer argument that represents the index of the element being selected,
      and should return a Boolean true/false value to indicate if the element can be selected.

            @version 2.2
            @warnings

            lb_items;

            generic
            {
                for(x = 1;x <= 5;x++)
                    lb_items += "Item_" + x;

                reqbegin("Testing List Box");

                c1 = ctllistbox("Items",300,300,"lb_count","lb_name",,"lb_select");

                reqpost();
            }

            lb_count
            {
                return(lb_items.size());
            }

            lb_name: index
            {
                return(lb_items[index]);
            }

            lb_select: index
            {
                // only allow selection of the odd-numbered elements

                return(index & 1);
            }

## Behavioral Changes

      Listbox controls in LScript are now always multiple-select.  In order to accomodate this,
      certain value changes have been made.

      The argument provided to the "event" function for listbox controls is now either an array
      of indices denoting the current selection(s) in the listbox, or 'nil' if no selections exist.

      The getvalue() return type for listbox controls has become multi-element, with each
      element denoting the index of the selected item.  If no items are selected in the listbox
      when getvalue() is called, then 'nil' is returned.

      The setvalue() function can now accept a number of different data types for setting the
      selection within a listbox.

      Here is a sample script to illustrates the new listbox interface mechanism:

        @version 2.2
        @warnings

        c1;
        lb_items;

        generic
        {
            for(x = 1;x <= 5;x++)
               lb_items += "Item_" + x;

            reqbegin("Testing List Box");

            c1 = ctllistbox("Items",300,300,"lb_count","lb_name","lb_event");
            c2 = ctlbutton("Select",50,"button_event");

            return if !reqpost();

            sel = getvalue(c1);

            reqend();

            if(sel == nil)
                info("No selections were made");
            else
                info("You have selected '",sel,"'!");
        }

        lb_count
        {
            return(lb_items.size());
        }

        lb_name: index
        {
            return(lb_items[index]);
        }

        lb_event: items
        {
            // 'items' is an array of integer index values,
            // or 'nil'

            if(items == nil)
                info("No items are selected");
            else
                info("You have selected '",items,"'!");
        }

        button_event
        {
        //    a = @"Item_2","Item_4"@;
            a = @1,3,5@;
        //    a = 4;
        //    a = "Item_5";

            setvalue(c1,a);
        }
      LScript is no longer using the Panels sub-system to generate requesters, but rather is
      now using the LightWave toolkit directly.  This has lead to a change in the
      interpretation of the listbox height value.

      The listbox control used to specify widths in pixels and heights in number of listbox
      entries that should be visible.  However, the height for a listbox now also specifies
      pixels.  Taking the example script provided in the v2.1 release notes, the following
      would produce a listbox that is 300-pixels wide and 10-pixels high in v2.2:

        c1 = ctllistbox("Items",300,10,"lb_count","lb_name","lb_event");

      This will need to be updated for use with v2.2:

        c1 = ctllistbox("Items",300,300,"lb_count","lb_name","lb_event");
      The compression algorithm used by the LScript run-time system did not function properly
      when compiled file sizes exeeded some threshold.  For this reason, it has been replaced
      with a newer binary-based compression algorithm that functions similarly, achieves
      equitable ratios, and does not appear to be effected by the size of the file.

      The original compression algorithm remains in LScript to support decompression of older
      compiled scripts.
      The LightColor() and AmbientColor() Command Sequence functions now expect their arguments
      to be in floating-point format, expressed as 0.0 to indicate 0 and 1.0 to indicated 255.
      You can continue to use integer values between 0 and 255 for individual color components,
      but they must be converted to their floating-point equivalents in the range of 0.0 to
      1.0--i.e., (150 / 255.0)

## Bug Fixes

      Containers holding arrays were not being cleared completely when new values
      were assigned, leaving phantom pointers to the reclaimed arrays.
      Array duplication included an additional memory lock that prevented
      subsequent reclamation.  This caused memory consumption during a script's
      execution when arrays were frequently created and destroyed.
      Modeler's new() command dropped it's integer parameter with the release
      of LightWave [6].  LScript has been corrected to adhere to this.
      A problem with the logic flow in object processing caused certain data
      members (like 'totallayers') to be unrecognized.
      The Tab control created with ctltab() was not receiving the correct
      data type, causing a crash of the application when tabs are altered.
      The genus data member of the Object Agent passed to the Item Motion
      create() function always returned zero (0), regardless of the type of the
      object.
      The Image Object Agent methods rgbSpot(), lumaSpot() and needAA() were not
      accepting the correct number of arguments.
      The LightFalloffType() CS function was incorrectly accepting string arguments.
      It has been corrected to accept integer values between 1 and 4 (1==off).
      Point and Polygon data members introduced in v1.4 were lost during the object
      code reorganization that took place in v2.0.  These have been added back to
      LScript.
      Variables holding regular expressions (search, or search-and-replaced) could
      not correctly be tested for equality or inequality with other values.