niftools / pyffi

PyFFI is a Python library for processing block structured files.
http://www.niftools.org/pyffi
Other
48 stars 26 forks source link

Added support for array notations of ARGs #24

Closed Dexesttp closed 8 years ago

Dexesttp commented 8 years ago

Scope

Figment's version of nifxml and the max plugin added a new way to deal with the fact that there is several ARGs needed for a cond to take place. He allowed an array to be given as an ARG and use the ARG[n] variable as a COND variable to be used to select the right array member.

To anticipate a possible merge of the nif.xml files, this PR adds support for the presented new nif.xml feature.

New supported feature description

When a member has an argument, the arg is passed via the "arg" attribute of the member's XML node. The arg attribute is either a previous node or a constant.

<add name="Rotation Keys" type="QuatKey" template="Quaternion" arg="1" arr1="Num Rotation Keys">The particle rotation keys.</add>

Until now, the node was assumed to always be a direct integer or string value.
The new format would allow to pass as arg values an array of values

<niobject name="BSTriShape" inherit="BSShape">
        <add name="Vertex Flags" type="byte" arr1="8"/>
        <add name="Vertex Data" type="BSVertexData" arr1="Num Vertices" arg="Vertex Flags" cond="Data Size &gt; 0"/>
</niobject>

This value would then be used in future cond checks with the bracketed access notation ARG[n]

<compound name="BSVertexData">
        <add name="Vertex" type="HalfVector3" cond="(!(ARG[6] &amp; 64))"/>
</compound>

Solution

The solution is to add new functionality to the expression resolution function, specifically the left and right members resolution, when these members are variables. This takes place in the pyffi/object_models/xml/expression.py file

A new check was added when a variable was solved, checking first if there's the possibility of it being an an ARG to help reduce the operation cost, then matching the variable name (with the /ARG\[(*)+\]/s/ regexpr) and either getting the proper position or getting the raw argument (old behavior)

The cost of this check is still pretty high, about 0.04s by variable resolution when an ARG member is present, and 0.0003s when an ARG member doesn't exist. These values are "at-most" values.

No other functionality is needed, as the ARG attribute resolution already handled ARG variable as arrays, even if the cond analysis would have failed later. This isn't a concern as the nif.xml format would have been wrong based of the previous format anyways.

Extension

This approach was chosen because it allows to easily add support for array notations for all variables. It is indeed just a matter of pushing the pattern matching up and using the /(*)+\[(.)+]/s/ regexpr instead of the current one.
This new feature wasn't considered yet as it isn't needed.

Contributions

This feature was proposed by @jonwd7 and @neomonkeus, as a way to standardize the nif.xml file across all sources.

hexabits commented 7 years ago

@neomonkeus @Dexesttp We never actually went this direction with nif.xml and we may want to discuss reverting these changes. Passing in the array of bytes ended up being entirely unnecessary (for niflib and Max too).