This article is aimed to present a rough interpretation of the .spt file format used in NWN2 (there are also alternate versions of this format) and provide some insight into creating custom trees based on existing files. Unfortunately I lack a full interpretation of the format and as such the creation of a completely new tree is (currently) impossible. If you have any information regarding this topic, be it to expand or correct anything written below I strongly encourage you to share this knowledge for the good of the community. MSpytkowski 18:59, 6 March 2009 (UTC)
Tools Required[]
- A text editor: While the Windows NotePad might seem to be a satisfying choice it should be noted that there exist free applications of significantly greater capabilities. I would personally advise using either EditPad or NotePad++, the second of which can be further modified to include a binary mode.
- A binary editor: While any such application should prove appropriate certain details require calculating float binary data. You may either ensure to obtain an editor capable of such conversion or augment yourself with a minor tool just for this task. It is also possible to calculate float data using a pen and paper, however this is tedious and is strongly unadvised. If you do not posses the ability to read binary and hexadecimal base numbers the standard calculator available on the operation system of your choice will also be a needed.
- A DDS converter
- A Normal map generator
- A Non-basic 2D-arts application
(The three above will be required to create textures for your creations. This tutorial will however not cover any topics concerning the creation of alphamaped textures or normal vector offset maps.)
The SpeedTree Format[]
Go ahead and open a .spt file in the Pad of your choice. You should notice that large parts of the file are composed of readable formatted strings. The rest looks quite gibberish and is composed of binary data. This data seems to come in either four byte integers or four byte floats, though arguably some eight byte integers and other formats can also be discerned.
You should quickly notice that the file is roughly divided into three main parts. First comes a short header that stretches from the beginning of the file to eight bytes prior of the first "BezierSpline". The second is the main body containing the Splines that govern various properties of the tree. They come in sets of nine with additional data nested between the eight and ninth spline. Last is the footer containing mainly texture atlas data and certain other minor controls.
The Header[]
Anything though to be an invariable has been written down. If you notice a file that does not conform to this pattern please inform me. Some values are marked as unknown, if you discover their meaning please inform me.
[28 byte invariable] - This contains the file ID and .spt version: e8 03 00 00 0c 00 00 00 5f 5f 49 64 76 53 70 74 5f 30 32 5f ea 03 00 00 d0 07 00 00
[variable size string] - the next part holds the size of a string and a string holding the main texture name
[4 byte invariable] - d1 07 00 00
[4 byte unknown] - unused
[4 byte invariable] - d2 07 00 00
[1 byte unknown] - unused
[4 byte invariable] - d3 07 00 00
[4 byte unknown] - unused
[4 byte invariable] - d5 07 00 00
[4 byte unknown] - unused
[4 byte invariable] - d6 07 00 00
[4 byte unknown] - unused
[4 byte invariable] - d7 07 00 00
[4 byte unknown] - unused
[4 byte invaraible] - f6 03 00 00
[4 byte integer] - number of iterations
The Body[]
Be warned that this is based mostly on assumption. The meaning of many values is yet to be discovered. Anything though to be an invariable has been written down. If you notice a file that does not conform to this pattern please inform me. Be aware that the following is only a single iteration.
[4 byte invariable] - begin iteration: f8 03 00 00
[4 byte invariable] - 70 17 00 00
[variable byte spline] - distortion control
[4 byte invariable] - 71 17 00 00
[variable byte spline] - weight control
[4 byte invariable] - 72 17 00 00
[variable byte spline] - rough wind response control
[4 byte invariable] - 73 17 00 00
[variable byte spline] - fine wind response control
[4 byte invariable] - 74 17 00 00
[variable byte spline] - hight/length control
[4 byte invariable] - 75 17 00 00
[variable byte spline] - rought radious control
[4 byte invariable] - 76 17 00 00
[variable byte spline] - fine radious control
[4 byte invariable] - 77 17 00 00
[variable byte spline] - angle control
[4 byte invariable] - 78 17 00 00
[4 byte integer] - mesh radial division
[4 byte invariable] - 79 17 00 00
[4 byte integer] - mesh height division
[4 byte invariable] - 7a 17 00 00
[4 byte float] - start next iteration generation
[4 byte invariable] - 7b 17 00 00
[4 byte float] - end next iteration generation
[4 byte invariable] - 7c 17 00 00
[4 byte float] - denesity of next iteration generation
[4 byte invariable] - 7d 17 00 00
[4 byte float] - horizontal texture tiling
[4 byte invariable] - 7e 17 00 00
[4 byte float] - vertical texutre tiling
[4 byte invariable] - 7f 17 00 00
[1 byte boolean] - horizontla texture alignment
[4 byte invariable] - 80 17 00 00
[1 byte boolean] - vertical texture alignment
[4 byte invariable] - 81 17 00 00
[variable byte spline] - unknown, possibly angle distortion
[4 byte invariable] - end iteration: f9 03 00 00
Note for the last spline: it is strange that this spline seems to be either an afterthought or an addition to a previously established format... the only tree I have analysed that possessed a non-trivial ninth spline is the "SpookyTree". The weird shape of this model seems to be derived from this spline though I do not fully understand how this works.
Apendix - Formats[]
A certain aspect that requires additional explanations is how exactly the spline data should be formatted and read (or written). First off you should know that they are simply sequential Bezier curves. Many programs, including all vector art applications, feature such splines. It would be advised that while the technical and mathematical aspects can be omitted you will most likely want a visual interface. Alternatively all calculations can be done by hand or roughly assessed. Later on I will also post a few examples of typical splines for general use.
The format for the string is as followed:
[...][4 byte integer - size of formatted string]BezierSpline¤A¤B¤C
{
¤N
¤[Point 0]
...
¤[Point N-1]
Where: ¤ is a tabulation
}
[...]
And the format of a point is:
X Y WX WY W
Together all the points form a function y=f(x) (yes, a function with all the implication and limitations!) with x in bound of <0; 1>. This means that the first value (X) for point 0 must by 0 and the same value for point N-1 must be 1, as well as that for any x within the bounds the function f(x) can equate to ONLY one single value.
In general:
A - lowest range of value
B - highest range of value
C - random distortion
Note: the following is ONLY an assumption!
When calculating the actual value of a parameter for a given x it is most likely [1-C+random(2C)]*[A+B*f(x)]...
N - number of points in spline, no less than 2
X, Y - position of point
WX, WY - relative position of control point (relative to X and Y)
W - weight of control point
Now this might make little sense, especially that intuition suggests a point requires only four values. This is because the two values usually used to describe a control point are in this case broken up into three. This is because WX and WY are normalise (XW^2+WY^2=1) and W is needed to determine the control points actual weight (which is usually dependant on the control points distance to the main point.
To calculate the actual control point position use these equations:
WX'=X+(WX*W)
WY'=Y+(WY*W)
Alternatively to calculate the relative weighted position of the control point:
W=(WX'-X)^2+(WY'-Y)^2
WX=(WX'-X)/W
WY=(WY'-Y)/W
And finally a string is formatter as follows:
[...][4 byte integer - size of formatted string][File Name][...]
A file name will invariably end in .tga, even in the textures you wish to supply were compressed to the .dds format. There is no point in changing the file name references for fronds and leaves as they are either way extracted from an atlas.
[]
Lastly we have the final stretch of the file. I must admit this section is complex and most of its purpose eludes me. However a structural decomposition of the invariables along with some common sense allowed me to find most of the important data. Differently than in the past two instances I am unable to give a complete breakdown, instead I will give you the data in a slightly different format:
[@4 byte hexadecimal][format] - meaning
Where the first part defines the value of a invariable that always precedes the value you should change. As every decent HexEditor should be equipped with a search function this is sufficient to locate and alter the needed bytes.
[@ee 03 00 00][4 byte integer] - number of leaf instances, for now partially useless
[@a5 0f 00 00][4 byte float][4 byte falot][4 byte float] - leaf scale, first two values equal, third should be zero, this entry repeats itself for each leaf instance, usually two times, some files might completely lack this section.
[@ca 32 00 00][4 byte integer] - iteration to be replaced by fronds (numbered from 0 up) this will hide further iterations
[@cb 32 00 00][1 byte integer] - frond/twig mode, 0 = multiple meshes, 1 = divided mesh
[@cc 32 00 00][4 byte integer] - number of meshes, will align in radial symmetry
[@cd 32 00 00][variable size spline] - relates to the shape of the frond/twig mesh in mode 1
[@ce 32 00 00][4 byte integer] - division level
[@cf 32 00 00][1 byte boolean] - toggle fronds/twigs on tree
[@9a 3a 00 00][1 byte boolean] - random texture offset-repeats itself the same number of times as there are iterations of the body
[29b 3a 00 00][4 byte float] - texture twirl around mesh, same as above
A Proper Tutorial[]
...Is under construction...
A Note On Clusters[]
You might be curious what is the difference between a single tree and a cluster of such. Interestingly there is none. quite interestingly the spread is produced by two spline iterations (trunk and first branch iteration) that for some reason remain unseen... though not always. When construction a cluster you will most likely want to start with a cluster. In such a case do not alter the first two sets of data and begin editing from the third. On a related note not only cluster feature disappearing elements. In some cases the same might happen with any other tree under random circumstances.
Making It Appear In Game[]
Both for testing purposes as well as to actually use the newly created file you will need to modify trees.2da. I will assume you already understand the structure of these files... This specific array holds three parameters:
LABEL - does not matter.
STRINGREF - either a .tlk reference or a string, this will be the name displayed for this entry in the appearance tab.
MODEL - the file name without the ".spt" extension.
After adding a new line the tree becomes available from in the appearance tab while editing trees.
On a interesting note, once the tree is present in the toolset it can be modified and viewed without restarting. To do so after saving any changes you might have made to either the main file or any texture simply reselect the appearance. If the toolset would then crash you will know that there is an error in your file... (This is why you should perhaps keep more than one instance at any time!) ...otherwise you will be able to see any changes made. Because of the somewhat eratic influence of various parameters I advise you do this often.