7 entries in For Scripters

“List” struct

Easily create associative array-like structures in 3dsmax

Friday, June 6th, 2008

As 3dsmax doesn’t allow for either associative arrays or dynamically-set object properties, it can be difficult to store unstructured, arbitrary variables.

Sometimes you just want to store lists of name/value pairs, to keep track of a few settings throughout your script, without relying on a host of variables, resorting to .ini files, or custom attributes.

Therefore, I set about writing a basic Dictionary, or List struct, similar to VB and other languages.

Example code

Here’s a really basic example of storing 5 named variables within a List:

names = #("five", "four", "three", "two", "one")
values = #(5,4,3,2,1)
lst = List()

for i = 1 to 5 do lst.addItem names[i] values[i]

So let’s get some data back out:

lst.getValue "two"
-- 2

lst.getIndex "two"
-- 4

lst.getValues()
-- #(5, 4, 3, 2, 1)

Or print the whole lot:

lst.print() -- unsorted

five:   5
four:   4
three:  3
two:    2
one:    1

How about some sorting:

lst.sort() -- by name, alphabetically

five:   5
four:   4
one:    1
three:  3
two:    2

lst.sort field:#value -- by value

one:    1
two:    2
three:  3
four:   4
five:   5

As you can see, it’s pretty straightforward stuff!

Properties and Methods

Properties

  • items – the key/value pairs.
    • Names can be a #name, “string”, or even an index
    • Values can be any MaxWrapper value (i.e. anything)

Setters

  • addItem – adds an item to the List, and if it already exists
  • setItem – synonym for the above

Getters

  • getValue – returns the value of the named item
  • getIndex – returns the index of the named item
  • getName – returns the name of the first item that matches the supplied value
  • getItem – returns the List item corresponding to the supplied name (typically, you wouldn’t use this, as you know the name component already, it’s just included for completeness)
  • getItems() – returns all items as an array of ListItem structs
  • getNames() – returns all names as an array
  • getValues() - returns all values as an array

Clear or delete

  • clear() – clears the lit of all items, and returns the empty ListItems array
  • deleteItem – deletes the named item from the list, and returns it
  • deleteIndex – deletes the item at the index, and returns it

Utilities

  • sort field: order: func: – sorts the list in a variety of ways, even supply a comparison function (see the max help on qsort)
  • print() – prints the List items to the Listener

Next version

Possible improvements in the next version might be:

  • .ini file integration, with save() and load() methods
  • Support for hierarchical Lists, perhaps getValue #(#parent, #child, #grandchild, …)

Download

Download List.struct.ms here.

Time Stamper

A struct to make light work of timing tasks, benchmarking, etc

Friday, May 9th, 2008

This struct basically makes timing things much easier by packaging a few useful methods together.

Now, instead of writing and retrieving timestamp variables, and formatting strings to the listener, you simply call struct methods such as start(), end(), and print(), or see a report of the process with getReport().

Example Code

Create a new Time Stamper, assigning a task name:

ts = timeStamper "Testing"

Time something, and alert the results in a messagebox:

ts.start()
-- your code here
ts.alert()

Benchmark a series of tests, and print the results to the listener when completed:

for i = 1 to 10 do (
        ts.start()
        -- your code here
        ts.end()
)
ts.print average:true
-- Average processing time for 'Testing' was 24.6162 seconds, based on 10 timed sessions.

Methods

Starting and stopping

  • start() – start timing. Returns start time
  • end() – end timing. Returns last timing duration
  • reset() – reset all timing data

Getting results in English

  • print average: difference: – end timing and print results to listener
  • prompt average: difference: – end timing and prompt results to notification area
  • alert average: difference: – end timing and alert the results in a messagebox

For the above methods, the following keyword arguments can be supplied:

  • average – returns the average result of all the timed tests since the TimeStamper was instantiated or last reset
  • difference – returns the comparative difference between another TimeStamper, in English, e.g.“Test 1′ was 2.58 times quicker than ‘Test 2′”

Getting results as numbers

  • getLast() – gets the last single timed session (alias for duration property)
  • getTotal() – gets the total of all timed sessions
  • getAverage() – gets the average of all timed sessions
  • getDifference difference: average: – Returns a 3-element array representing how much quicker one time stamper is than another.

The array’s elements are ordered like so:

  1. – how many times quicker the quickest Time Stamper was
  2. – the task name of the quicker time stamper
  3. – the task name of the slower time stamper

Getting results as an Excel-compatible report

  • getReport columns: step: output: – gets all timed sessions as a customizable report

The step property defines how many iterations to average/total values for, and defaults to 10.

The columns property can take any of the following name values:

  • #index – the numeric index of the row, e.g. 1, 2, 3
  • #step – the current step, e.g. 1, 11, 21
  • #stepaverage – the average of all measurements from the current step
  • #steptotal – the total of all the measurements from the current step
  • #slower – how much slower the current step was than the fastest step
  • #quicker – how much quicker the current step was than the slowest step
  • #total – the cumulative total from all measurements so far

The output property defines where the generate report will be output to. Values can be:

  • No value – the report will be returned as a string
  • “path/to/file.txt” – a file path. If the file exists it will be overwritten, if not it will be created
  • #window – a new script window
  • – a reference to a windowstream
  • – a reference to a stringstream

Download a report that was built using calls to getReport() in Excel 2007 or in Excel 2003

Properties

  • duration – the duration of the last timed session
  • durations – an array of all timed sessions
  • task – the name of the current timed task

Demo and case study

Check out a case study and download a demo script here:

Download

Download TimeStamper.ms.

Progress Bar Updater

A struct to simply and easily update a progress bar by providing just start and end values, and calling update()

Thursday, May 1st, 2008

Updating a progress bar is fairly simple in conceptual terms, but it always takes a slightly different bit of code to do it right:

  • What if the sequence is backwards?
  • What if you’re incrementing in units of 2, or 3, or 10?
  • How big is the progress jump?

It makes sense to abstract the process and stick it in a struct. The progressBarUpdater does just that, and really is as simple as:

  1. Create a struct instance
  2. Initialize it with a reference to a progress bar, and the known start and end values of the calculation
  3. Call update() for each loop iteration.

In code, starting with a 2-line initialization, it looks like this:

pbu = progressBarUpdater()
pbu.init pb1 startValue endValue

And to update the progress bar, this is the only command you need to place in the loop:

pbu.update()

The pbUpdater struct already knows everything it needs to know, so it’s just one call.

Download

Download progressBarUpdater.ms.

UI Manager

Save and load rollout settings, such as size, position, control states, items, etc to a preferences file

Thursday, May 1st, 2008

A struct containing methods to save and load rollout settings, such as size, position, control states, items, etc
to a preferences file, as well as methods to accomplish UI control tasks for example keeping one spinner higher or lower
than another when editing ranges.

Usage

To manage a rollout or dialog, you simply:

  1. create a struct instance
  2. initialize it with a reference to a rollout
  3. Manage the rollout by calling the struct’s methods

In code, that’s as easy as this:

ui = uiManager()
ui.initialize roTools
ui.loadPosition()

All settings are saved to an .ini file named after the rollout title, so in this case, an ini file named “Tools.ini” would be saved to your max installation’s /plugcfg folder.

Methods

This is a work in progress, and will be updated from time to time with new methods.

Dialog functions

  • savePosition - save the dialog position
  • loadPosition - load the dialog position
  • saveSize - save the dialog size
  • loadSize - restore the dialog size

Rollout functions

  • autoSizeFloater - resize the floater to exactly the size of all open rollouts
  • toggleRollout - set one or several rollouts open
  • loadRolloutStates - save all rolled-up / down states (not yet implemented)
  • saveRolloutStates - load all rolled-up / down states (not yet implemented)

Control functions

  • updateSpinnerPair - ensure that spinners react as a pair, eg one can never go higher than the other
  • moveListboxItem – move selected Listbox items up or down, and have them remain selected
  • moveMultiListboxItems – move multiple MultiListbox selections up or down, and have them remain selected
  • getValue - abstract function to get a control’s value (not yet implimented)
  • setValue - abstract function to set a controls’s value (not yet implimented)

Preference functions (WIP)

  • saveValue - save a control’s value
  • loadValue - load a control’s value
  • saveAllValues - save all controls’ values
  • loadAllValues - load all controls’ values

Downloads

Download uiManager0.52.ms. Place in your scripts/startup directory, or just include the file when you need it.

These example files will get you started:

  • Preferences functionality – save and restore a dialog’s position when re-running a script
  • Floater functionality – open only selected rollouts, and automatically resize when opening rollouts

ActiveX Inspector

Lists all ActiveX controls, and lets you interactively test their methods and properties

Wednesday, September 21st, 2005

This MAXScript entry has not yet been completed…
(more…)

VMS Tidy

Re-arranges and beautifies Visual MaxScript output

Thursday, May 19th, 2005

What VMS Tidy is

VMS Tidy reorders the lines of code that Visual MaxScript creates, so that the linear order of the lines matches the visual order of the controls. It also has options for renumbering and renaming controls.

This makes for much quicker prototyping of tools as you can just jump in and start throwing UI elements around without worrying about:

  • Visual relationships between UI elements and code
  • Relationships between groups and contained controls
  • Out-of order lines of code
  • Whitespace between blocks of code
  • Code indentation

VMS Tidy lets you concentrate on the task of designing functional user interfaces within Visual MaxScript before tidying and re-ordering it’s output to match the visuals.

Tidy modes

In the screenshot below, some sample code has been pasted into the editor window – as you can see, it’s all out of order, jumbled up, and none of the controls have been named (eg spn4, rdo2, chk4).

You can use one of the 3 VMS Tidy modes to tidy up the code:

  1. Layout Only – In this screen, the layout has been tidied with the “layout only” option. VMS Tidy has reordered and indented the code to make it more readable.
  2. Re-number -In this screen, the controls have also been re-numbered using the “re-number” option. Controls that were previously named are renumbered in consecutive order, eg spn1, spn2, spn3.
  3. Re-name – In this screen, the controls have actually been re-named, using the “re-name” option. Note how the controls are now named , eg spnArms, btnObject, sld1.Naming options can be edited from the <strong>Options</strong> dialog.</li> </ol> <h3>Results</h3> <p>Once the code has been tidied, it behaves exactly the same as before. Here is the result of the above code after clicking the <strong>Test</strong> button.</p> <p><img src="/resources/maxscript/For%20Scripters/VMS%20Tidy/VMS_Tidy_sample_rollout.gif" class="no-border"></p> <h3>Workflow</h3> <p>The process of working with VMS Tidy is this:</p> <ol> <li>Use Visual Max Script to design an your user interface</li> <li>Copy the code to the VMS editor window</li> <li>Click the “Go!” button to tidy the code</li> <li>Copy, re-<strong>Edit</strong> or <strong>Test</strong> the code</li> </ol> <h3>Options</h3> <p>You can change the options for renaming and restructuring from the options option of the Tidy dropdown.</p> <p><img src="/resources/maxscript/For%20Scripters/VMS%20Tidy/VMS_Tidy_options.gif" class="no-border"></p> <h3>What VMS Tidy isn’t</h3> <p>VMS Tidy is not a visual code designer, or a replacement for the Visual MaxScript Editor.</p> <h3>Known issues</h3> <p>Nested groups are currently not supported. Sorry.</p> <h3>Download and Installation</h3> <p>Download and extract VMS Tidy.zip, then run the main <strong>VMS Tidy</strong> script from 3dsmax to create the VMS Tidy dialog.</p> </div> <div class="postmetadata"> Posted in <a href="/code/category/development/maxscript/for-scripters/" title="View all posts in For Scripters" rel="category tag">For Scripters</a>, <a href="/code/category/development/maxscript/" title="View all posts in MaxScript" rel="category tag">MaxScript</a> | No Comments » </div> </div> <div class="post"> <h2 id="post-129"><a href="/code/development/maxscript/excel-functions/" rel="bookmark" title="Permanent Link to Excel Functions">Excel Functions</a></h2> <p class="intro">A set of functions to get you started with communication with Excel</p> <h4>Friday, January 21st, 2005</h4> <div class="entry"> <p>This MAXScript entry has not yet been completed…<br> <a href="/code/development/maxscript/excel-functions/#more-129" class="more-link">(more…)</a></p> </div> <div class="postmetadata"> Posted in <a href="/code/category/development/maxscript/for-scripters/" title="View all posts in For Scripters" rel="category tag">For Scripters</a>, <a href="/code/category/development/maxscript/" title="View all posts in MaxScript" rel="category tag">MaxScript</a> | <a href="/code/development/maxscript/excel-functions/#respond" title="Comment on Excel Functions">No Comments »</a> </div> </div> </div> <div id="sidebar"> <ul style="margin:0px;"> <li> </li> <li style="float:none;line-height:0px"> </li> <li> <li class="pagenav"> <h3>Pages</h3> <ul> <li class="page_item page-item-4"><a href="/code" title="Development Index (by category)">Development Index (by category)</a></li> <li class="page_item page-item-153">Development Posts (by date)</li> <li class="page_item page-item-195">Form Creator</li> <li class="page_item page-item-196">Comment Headings</li> </ul> </li> <li> <h3>Dave's stuff</h3> <ul> <li><a href="http://www.davestewart.co.uk">My portfolio</a></li> <li></li> </ul> </li> <li> <h3>Categories</h3> <ul> <li class="cat-item cat-item-3"> <a href="/code/category/development/" title="View all posts filed under Development">Development</a> (71) <ul class="children"> <li class="cat-item cat-item-35"> <a href="/code/category/development/after-effects/" title="View all posts filed under After Effects">After Effects</a> (1)</li> <li class="cat-item cat-item-30"> <a href="/code/category/development/flash/" title="View all posts filed under Flash">Flash</a> (3) <ul class="children"> <li class="cat-item cat-item-8"> <a href="/code/category/development/flash/actionscript/" title="View all posts filed under ActionScript">ActionScript</a> (3)</li> </ul> </li> <li class="cat-item cat-item-14"> <a href="/code/category/development/html/" title="View all posts filed under HTML">HTML</a> (3)</li> <li class="cat-item cat-item-5"> <a href="/code/category/development/javascript/" title="View all posts filed under JavaScript">JavaScript</a> (6) <ul class="children"> <li class="cat-item cat-item-15"> <a href="/code/category/development/javascript/jquery/" title="View all posts filed under jQuery">jQuery</a> (5)</li> </ul> </li> <li class="cat-item cat-item-7 current-cat-parent"> <a href="/code/category/development/maxscript/" title="View all posts filed under MaxScript">MaxScript</a> (54) <ul class="children"> <li class="cat-item cat-item-16"> <a href="/code/category/development/maxscript/maxscript-animation/" title="View all posts filed under Animation">Animation</a> (8)</li> <li class="cat-item cat-item-19"> <a href="/code/category/development/maxscript/cameras/" title="View all posts filed under Cameras">Cameras</a> (4)</li> <li class="cat-item cat-item-23 current-cat"> <a href="/code/category/development/maxscript/for-scripters/" title="View all posts filed under For Scripters">For Scripters</a> (7)</li> <li class="cat-item cat-item-27"> <a href="/code/category/development/maxscript/fun/" title="View all posts filed under Fun">Fun</a> (4)</li> <li class="cat-item cat-item-28"> <a href="/code/category/development/maxscript/functions/" title="View all posts filed under Functions">Functions</a> (3)</li> <li class="cat-item cat-item-24"> <a href="/code/category/development/maxscript/materials/" title="View all posts filed under Materials">Materials</a> (5)</li> <li class="cat-item cat-item-21"> <a href="/code/category/development/maxscript/modelling/" title="View all posts filed under Modelling">Modelling</a> (4)</li> <li class="cat-item cat-item-17"> <a href="/code/category/development/maxscript/particles/" title="View all posts filed under Particles">Particles</a> (1)</li> <li class="cat-item cat-item-18"> <a href="/code/category/development/maxscript/rendering/" title="View all posts filed under Rendering">Rendering</a> (3)</li> <li class="cat-item cat-item-34"> <a href="/code/category/development/maxscript/text/" title="View all posts filed under Text">Text</a> (3)</li> <li class="cat-item cat-item-26"> <a href="/code/category/development/maxscript/tools/" title="View all posts filed under Tools">Tools</a> (3)</li> <li class="cat-item cat-item-22"> <a href="/code/category/development/maxscript/ui-design/" title="View all posts filed under UI Design">UI Design</a> (7)</li> <li class="cat-item cat-item-25"> <a href="/code/category/development/maxscript/widgets/" title="View all posts filed under Widgets">Widgets</a> (5)</li> <li class="cat-item cat-item-20"> <a href="/code/category/development/maxscript/workflow/" title="View all posts filed under Workflow">Workflow</a> (7)</li> </ul> </li> <li class="cat-item cat-item-12"> <a href="/code/category/development/php/" title="View all posts filed under PHP">PHP</a> (6) <ul class="children"> <li class="cat-item cat-item-38"> <a href="/code/category/development/php/kohana/" title="View all posts filed under Kohana">Kohana</a> (3)</li> <li class="cat-item cat-item-29"> <a href="/code/category/development/php/wordpress/" title="View all posts filed under Wordpress">Wordpress</a> (1)</li> </ul> </li> <li class="cat-item cat-item-31"> <a href="/code/category/development/vba/" title="View all posts filed under VBA">VBA</a> (2)</li> <li class="cat-item cat-item-13"> <a href="/code/category/development/xml/" title="View all posts filed under XML">XML</a> (1)</li> </ul> </li> <li class="cat-item cat-item-32"> <a href="/code/category/freelance/" title="View all posts filed under Freelance">Freelance</a> (8) <ul class="children"> <li class="cat-item cat-item-33"> <a href="/code/category/freelance/quoting/" title="View all posts filed under Quoting">Quoting</a> (8)</li> </ul> </li> <li class="cat-item cat-item-40"> <a href="/code/category/misc/" title="View all posts filed under Misc">Misc</a> (3) <ul class="children"> <li class="cat-item cat-item-41"> <a href="/code/category/misc/tips/" title="View all posts filed under Tips">Tips</a> (3)</li> </ul> </li> </ul> </li> <li> <h3>Calendar</h3> <ul> <li> <table id="wp-calendar" summary="Calendar"> <caption> November 2010 </caption> <thead> <tr> <th abbr="Monday" scope="col" title="Monday">M</th> <th abbr="Tuesday" scope="col" title="Tuesday">T</th> <th abbr="Wednesday" scope="col" title="Wednesday">W</th> <th abbr="Thursday" scope="col" title="Thursday">T</th> <th abbr="Friday" scope="col" title="Friday">F</th> <th abbr="Saturday" scope="col" title="Saturday">S</th> <th abbr="Sunday" scope="col" title="Sunday">S</th> </tr> </thead> <tfoot> <tr> <td abbr="October" colspan="3" id="prev"><a href="/code/2010/10/" title="View posts for October 2010">« Oct</a></td> <td class="pad"> </td> <td colspan="3" id="next" class="pad"> </td> </tr> </tfoot> <tbody> <tr> <td>1</td> <td>2</td> <td>3</td> <td>4</td> <td>5</td> <td>6</td> <td>7</td> </tr> <tr> <td>8</td> <td>9</td> <td>10</td> <td>11</td> <td>12</td> <td>13</td> <td>14</td> </tr> <tr> <td>15</td> <td>16</td> <td>17</td> <td>18</td> <td>19</td> <td>20</td> <td>21</td> </tr> <tr> <td>22</td> <td id="today">23</td> <td>24</td> <td>25</td> <td>26</td> <td>27</td> <td>28</td> </tr> <tr> <td>29</td> <td>30</td> <td class="pad" colspan="5"> </td> </tr> </tbody> </table> </li> </ul> </li> <li> <h3>Archives</h3> <ul> <li><a href="/code/2010/" title="2010">2010</a></li> <li><a href="/code/2009/" title="2009">2009</a></li> <li><a href="/code/2008/" title="2008">2008</a></li> <li><a href="/code/2007/" title="2007">2007</a></li> <li><a href="/code/2006/" title="2006">2006</a></li> <li><a href="/code/2005/" title="2005">2005</a></li> <li><a href="/code/2004/" title="2004">2004</a></li> <li><a href="/code/2003/" title="2003">2003</a></li> <li><a href="/code/2002/" title="2002">2002</a></li> <li><a href="/code/2001/" title="2001">2001</a></li> </ul> </li> <li id="linkcat-11" class="linkcat"> <h3>Forums</h3> <ul> <li><a href="http://www.actionscript.org/forums/">ActionScript.org</a></li> <li><a href="http://www.aenhancers.com/" title="Expressions, Scripts & Presets for After Effects">AEnhancers</a></li> <li><a href="http://forums.cgsociety.org/forumdisplay.php?f=98">CG Talk MaxScript</a></li> </ul> </li> <li> <h3>Meta</h3> <ul> <li>Log in</li> </ul> </li> </ul> </div> <div id="footer"> <div style="padding:10px;"> <p>Keyframes and Code is the blog of <a href="http://www.davestewart.co.uk">Dave Stewart</a> | and . 21 queries. 1.967 seconds.</p> </div> </div> </div> </body> </html>