67 entries in Development

Kohana ‘filesystem’ Helper

A robust helper to handle everything file and folder-related within Kohana

Wednesday, August 20th, 2008

Kohana is just an excellent framework to work with, but one of my beefs is that the structure of its bundled libraries and helpers is a little haphazard, missing basic functions you’d expect to find in the core (so you can rely on them when writing modules) omitted!

For this reason, here’s my attempt at a more integrated helper class. It’s somewhat of a Frankenstein’s monster with bits borrowed from Code Igniter, and my own code thrown in as well. Apart from this, it:

  • Adds a few new methods
  • Improves on some existing methods
  • Combines the ‘download’ helper functionality
  • Tidies up various method calls

The methods are:

  • map()
  • get_folders()
  • get_files()
  • delete_files()
  • read_file()
  • write_file()
  • make_path()
  • download()

Download filesystem.php here.

(more…)

I love CodeIgniter!

A brief introduction to the wonderful PHP CodeIgniter framework

Monday, June 30th, 2008

I don’t normally write a post unless I’m specifically publishing code, but I wanted to write a brief post about Code Igniter as it’s the best damn thing I’ve discovered since jQuery!

Overview

If you haven’t heard of it already, CodeIgniter is a rapid application-development framework for PHP that uses the Model-View-Controller pattern to separate the presentation, logic and data from each other whilst building your web application.

What this means in practice is that instead of building one large linear PHP file that…

  1. Contains swathes of PHP in the head to filter user input (logic), then
  2. Gets results from a database (data) and does something meaningful with them, then finally
  3. Outputs the HTML (presentation) and continues to escape in and out of PHP during the process

…you end up working on many different smaller files that do one task only, with which the framework pieces together for you to deliver finished web pages.

However, before I delve into MVC, I want to touch upon CodeIgniters excellent class library.

A excellent and fully-integrated set of Library classes

The primary reason I started using CodeIgniter in the first place, is that it provides an incredibly robust and integrated set of classes to handle everything web-app related, from database classes, to session classes, to file uploading and email.

Had it not been for the fact that you have to use them within the overall CodeIgniter structure, I may well have gone off and carried on the way I was going, with logic at the top of my pages, and presentation at the bottom.

However, in order to actually use them, you have to accept you’ll start coding within the CodeIgniter framework, and things will never be the same again…

An intelligent and modular approach to building web applications

The vast majority of what you do within CodeIgniter will be written within class files, that will fall under one of the three MVC areas:

  1. Controllers - classes responsible for making overall decisions, such as deciding what task is being undertaken in response to user-input, as well as loading supporting classes and logic to get the job done. Controllers are the first step in processing a task, and outputting a web page.

    It helps to think of controllers and their methods as the “folder” and “page” structure of a site. For example a “Home Controller” might have an “index” function would handle loading the home page, whilst a “Messaging Controller” and might have a “List” and “Compose” methods would handle listing messages, composing new messages, etc.

    Both these methods would take high-level decisions about the task in hand, offloading the drudgery of the tasks to other elements, such as…

  2. Models - classes responsible for everything “data” related, such as read and writing from databases, storing representations of said data, configuration, etc.

    In practice, what this means is that a Controller would never read or write data directly, it would hand all responsibility for that to a Model, and would just make calls such as “get the last 10 unread messages”. The model would do the grunt-work, leaving the Controller to get on with more important things.

  3. Views - static or dynamic files that are read by CodeIgniter, populated with data, and are output to the user. Views are analogous with the final page output you’d see in procedural PHP programming.

    A view file need not be an entire web page, it could just be a segment, such as a sidebar, a form, a graph, a header, or a footer. By combining views, you have a lot of power with regards to the output of the final page, as well as a really flexible way to store individual representations of data.

    For example, depending on user input, you could load either a Table View or a Graph View that would be populated by the Model data. Inside the view you’d have written code that would receive Model data and would know what to do with it.

The benefit of this approach is that it’s much easier and quicker to build and maintain your site, as everything’s modular, and can be loaded and swapped out according to the task at hand (and no more huge sprawling pages).

There aren’t really that many downsides to this approach, but it can be a little tricky sometimes, as due to the way CodeIgniter works behind teh scenes, you don’t work with a traditional one-to-one file / page structure, but once you’re used to it, you’ll never want to go back.

Comment Headings (beta)

Enable easy navigation of code using GIANT comments made up of block characters

Saturday, June 7th, 2008

When navigating through large classes, it can be a real pain to find certain bits of code if you don’t have a good IDE. As I often work in Flash IDE and DreamWeaver IDE, I have to rely on comment blocks here and there, with lots of ———- delimiters, etc. which is an OK start.

However, I saw the PaperVision 3D classes had moved on a step from this, and had rather nice blocks at the top of each script with their logo, made out of characters. Why not extend this idea and actually build a small Flash application to let me build dirty-great big words that I can use in my scripts for navigation purposes?

Comment Headings beta

Edit the text in the left-hand text box to update the text in the right, then copy and paste to your IDE.

You’ll need to be using a monospaced font to make it work! Mac users, you might have to experiment to find the best one…

Final release

The final release, which I’m working on in my spare time, will have:

  • a greater range of typefaces to choose from
  • options for other languages (ie, MaxScripters will be able to choose — for their comment delimiter)
  • more options with regards to the content and formatting of the comments
  • options to remember your last headings
  • Will be built on the MVC design pattern

Feel free to make suggestions below.

Download

“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

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

Setters

  • <ListItem> addItem <name> <value> - adds an item to the List, and if it already exists
  • <ListItem> setItem <name> <value> - synonym for the above

Getters

  • <value> getValue <name> - returns the value of the named item
  • <index> getIndex <name> - returns the index of the named item
  • <name> getName <value> - returns the name of the first item that matches the supplied value
  • <ListItem> getItem <name> - 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)
  • <array> getItems() - returns all items as an array of ListItem structs
  • <array> getNames() - returns all names as an array
  • <array> getValues() - returns all values as an array

Clear or delete

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

Utilities

  • <array> sort field:<name> order:<name> func:<function> - sorts the list in a variety of ways, even supply a comparison function (see the max help on qsort)
  • <string> 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 - Meshops.attach() Case Study

Monday, May 26th, 2008

Overview

In response to a post on CG Talk, Optimization ideas needed, a few other developers and I us pitched in to help out with ideas to solve a puzzling problem.

The issue was that a loop to attach 7500 objects was taking up to 8 minutes to complete. Where did the problem lie? Was it in the transformation code, the attachment code, or somewhere else?

Well as luck would have it, today’s Bank Holiday has been totally washed out with rain, so I had nothing better to than to do some testing and find the cause, and in the process road test my recently-developed TimeStamper struct.

Approach

After turning undo and redraw off, as well as optimizing the transformation code within the script, which cut a 1000-object test scene’s processing time in half, surprisingly the 7500-object scene was still taking around 8 minutes.

I suspected that the problem may well be in the fact that as mesh gets larger, perhaps it becomes computationally more expensive to add new meshes, seeing as the entire array of points and faces needs to be evaluated every time a new mesh is added. Cumulatively, this could really add up.

I though that perhaps the right approach would be to split the attaching up into phases, using a 2D loop, and I suspected that perhaps the square-root of the total attaches might yield the optimal performance, ie for 10000 attaches I’d perform a 100 x 100 loop, creating 100 intermediate meshes, then attaching them all at the end.

Results

These are the results for various variations of 2D loops, limiting the amount of objects attached per loop. The results are impressive!

  • For 1000 objects, the optimum loop combination was 31 loops of 32, a speed increase of 12 times over a single loop
  • For 3000 objects, the optimum loop combination was 55 loops of 54, a speed increase of 22 times over a single loop
  • For 5000 objects, the optimum loop combination was 50 loops of 100, a speed increase of 28 times over a single loop
  • For 7500 objects, the optimum loop combination was 87 loops of 86, a speed increase of 30 times over a single loop

And yes, the square root approach was most successful 3 out of 4 times.

Here are the results in table format, with the optimum loop highlighted:

1D / 2D loop comparison

Compared to the 1D loop, the 2D loop was 30 times faster on 7500 attachments.

In minutes and seconds, that means a decrease from 6 minutes and 29 seconds to just 12 seconds!

In graph-form that looks like this:

Conclusion

It seems pretty safe to say that in this case, building up intermediate meshes and attaching at the end is the best way to go. It looks likely that adding to already-huge arrays carries with it an overhead that can have an extremely negative effect in a lengthy loop situation.

I’ve no doubt that this approach most likely extends to other mesh / array / hash based computations as well, so splitting up large cumulatively-expensive calculations into smaller chunks could well be a great time-saver in other tasks as well.

So - a shame about the rain, but perhaps a bonus in disguise!

Resources

Transform Presets

Save and restore transformations as presets to objects such as cameras, IK handles, etc.

Saturday, May 17th, 2008

Transform Presets is a pretty simple plugin - it allows you to store multiple transformations of an object (and it’s target, if there is one) in a list, to call up when you like.

I built it for fun in response to a thread on CGTalk.

Screenshots

Here it is working on a target camera. Note both the camera and target are transformed.

And here it is working with an IK handle. Note the swivel angle is updated as well as the transform.

Download and installation

Download TransformPresets.mzp and then drag the .mzp file onto one of your 3dsmax viewports, which will install the script in the correct directory. Then you can add the script to a toolbar / quad by going to:

  • Customize > Customize User Interface…
  • Then look under the Animation Tools category for Transform Presets

Particle Visualizer and Papervision3D Exporter

A script to visualize particle motion and export particle and camera data to Flash's Papervision 3D

Saturday, May 10th, 2008

Papervision 3D is the latest in 3D development for the Adobe Flash platform. It supports a variety of methods for creating 3D content, from basic primitives, to import via the Collada file format. However, being XML-based, Collada files are pretty huge - getting a 300 frame, 150 particle animation into Flash was creating files that were about 22MB!

After trying various approaches to get animation data from 3dsmax to Flash, Good Technology got in contact with me to write an exporter in Max Script for their latest Papervision job for the Audi RS6 microsite.

The plugin has 2 main functions:

  • Visualize particle motion before export
  • Export particle and camera data from max’s Z-up coordinate system to Papervision’s Y-up coordinate system

More information and screengrabs are available on my portfolio site.

Screenshot

Interface

As with all interfaces I write for 3dsmax, I do my best to provide as much feedback as possible. Note:

  • Group titles are updated with the latest information
  • Dropdowns have an update button
  • Tasks have multiple customization options
  • Progress bars and dialog preferences come as standard

Download

This plugin is not available for download, however please contact me if you wish to discuss custom Papervision3D or any other development.

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

  • <number> start() - start timing. Returns start time
  • <number> end() - end timing. Returns last timing duration
  • <void> reset() - reset all timing data

Getting results in English

  • <void> print average: <boolean> difference: <TimeStamper> - end timing and print results to listener
  • <void> prompt average: <boolean> difference: <TimeStamper> - end timing and prompt results to notification area
  • <void> alert average: <boolean> difference: <TimeStamper> - end timing and alert the results in a messagebox

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

  • average <boolean> - returns the average result of all the timed tests since the TimeStamper was instantiated or last reset
  • difference <TimeStamper> - 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

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

The array’s elements are ordered like so:

  1. <number> - how many times quicker the quickest Time Stamper was
  2. <string> - the task name of the quicker time stamper
  3. <string> - the task name of the slower time stamper

Getting results as an Excel-compatible report

  • <string> getReport columns:<array> step:<number> output:<string/name/windowstream/filestream> - 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
  • <windowstream> - a reference to a windowstream
  • <stringstream> - a reference to a stringstream

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

Properties

  • duration <number> - the duration of the last timed session
  • durations <array> - an array of all timed sessions
  • task <string> - 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: