pyffi.formats.tri — TRI (.tri)

Last Built: Mar 06, 2020

pyffi.formats.tri — TRI (.tri)

A .tri file contains facial expression data, that is, morphs for dynamic expressions such as smile, frown, and so on.

Implementation

class pyffi.formats.tri.TriFormat[source]

Bases: pyffi.object_models.xml.FileFormat

This class implements the TRI format.

Data

alias of Header

class FileSignature(**kwargs)[source]

Bases: pyffi.object_models.xml.basic.BasicBase

Basic type which implements the header of a TRI file.

get_detail_display()[source]

Return an object that can be used to display the instance.

get_hash(data=None)[source]

Return a hash value for this value.

Returns

An immutable object that can be used as a hash.

get_size(data=None)[source]

Return number of bytes the header string occupies in a file.

Returns

Number of bytes.

read(stream, data)[source]

Read header string from stream and check it.

Parameters

stream (file) – The stream to read from.

write(stream, data)[source]

Write the header string to stream.

Parameters

stream (file) – The stream to write to.

class FileVersion(template=None, argument=None, parent=None)[source]

Bases: pyffi.object_models.xml.basic.BasicBase

get_detail_display()[source]

Return an object that can be used to display the instance.

get_hash(data=None)[source]

Returns a hash value (an immutable object) that can be used to identify the object uniquely.

get_size(data=None)[source]

Returns size of the object in bytes.

get_value()[source]

Return object value.

read(stream, data)[source]

Read object from file.

set_value(value)[source]

Set object value.

write(stream, data)[source]

Write object to file.

class Header(template=None, argument=None, parent=None)[source]

Bases: pyffi.formats.tri._Header, pyffi.object_models.Data

A class to contain the actual tri data.

add_modifier(name=None, relative_vertices=None)[source]

Add a modifier.

add_morph(name=None, relative_vertices=None)[source]

Add a morph.

get_global_child_nodes(edge_filter=(True, True))[source]

Generator which yields all children of this item in the global view, of given edge type (default is edges of type 0).

Override this method.

Returns

Generator for global node children.

inspect(stream)[source]

Quickly checks if stream contains TRI data, and reads everything up to the arrays.

Parameters

stream (file) – The stream to inspect.

inspect_quick(stream)[source]

Quickly checks if stream contains TRI data, by looking at the first 8 bytes. Reads the signature and the version.

Parameters

stream (file) – The stream to inspect.

read(stream)[source]

Read a tri file.

Parameters

stream (file) – The stream from which to read.

write(stream)[source]

Write a tri file.

Parameters

stream (file) – The stream to which to write.

class ModifierRecord(template=None, argument=None, parent=None)

Bases: pyffi.object_models.xml.struct_.StructBase

A modifier replaces the vertices from the base model (Header.vertices) with those in Header.modifier_vertices. Note that Header.modifier_vertices counts up from the first modifier onwards. For example, if you were to take the 4th vertex to be modified in the 2nd modifier and the size of the 1st modifier was 10 vertices, then you would need Header.modifier_vertices[14]. Therefore, Header.num_modifier_vertices = sum(modifier.num_vertices_to_modify for modifier in Header.modifiers).

class MorphRecord(template=None, argument=None, parent=None)[source]

Bases: pyffi.formats.tri._MorphRecord, object

>>> # create morph with 3 vertices.
>>> morph = TriFormat.MorphRecord(argument=3)
>>> morph.set_relative_vertices(
...     [(3, 5, 2), (1, 3, 2), (-9, 3, -1)])
>>> # scale should be 9/32768.0 = 0.0002746...
>>> morph.scale 
0.0002746...
>>> for vert in morph.get_relative_vertices():
...     print([int(1000 * x + 0.5) for x in vert])
[3000, 5000, 2000]
[1000, 3000, 2000]
[-8999, 3000, -999]
apply_scale(scale)[source]

Apply scale factor to data.

>>> # create morph with 3 vertices.
>>> morph = TriFormat.MorphRecord(argument=3)
>>> morph.set_relative_vertices(
...     [(3, 5, 2), (1, 3, 2), (-9, 3, -1)])
>>> morph.apply_scale(2)
>>> for vert in morph.get_relative_vertices():
...     print([int(1000 * x + 0.5) for x in vert])
[6000, 10000, 4000]
[2000, 6000, 4000]
[-17999, 6000, -1999]
class QuadFace(template=None, argument=None, parent=None)

Bases: pyffi.object_models.xml.struct_.StructBase

Not used by the Oblivion engine as it’s tri based.

class SizedStringZ(**kwargs)[source]

Bases: pyffi.object_models.common.SizedString

get_size(data=None)[source]

Return number of bytes this type occupies in a file.

Returns

Number of bytes.

read(stream, data)[source]

Read string from stream.

Parameters

stream (file) – The stream to read from.

write(stream, data)[source]

Write string to stream.

Parameters

stream (file) – The stream to write to.

byte

alias of pyffi.object_models.common.Byte

char

alias of pyffi.object_models.common.Char

float

alias of pyffi.object_models.common.Float

int

alias of pyffi.object_models.common.Int

short

alias of pyffi.object_models.common.Short

ubyte

alias of pyffi.object_models.common.UByte

uint

alias of pyffi.object_models.common.UInt

ushort

alias of pyffi.object_models.common.UShort

static version_number(version_str)[source]

Converts version string into an integer.

Parameters

version_str (str) – The version string.

Returns

A version integer.

>>> TriFormat.version_number('003')
3
>>> TriFormat.version_number('XXX')
-1

Regression tests

Read a TRI file

>>> # check and read tri file
>>> from os.path import dirname
>>> dirpath = __file__
>>> for i in range(4): #recurse up to root repo dir
...     dirpath = dirname(dirpath)
>>> repo_root = dirpath
>>> format_root = os.path.join(repo_root, 'tests', 'formats', 'tri')
>>> file = os.path.join(format_root, 'mmouthxivilai.tri')
>>> stream = open(file, 'rb')
>>> data = TriFormat.Data()
>>> data.inspect(stream)
>>> # do some stuff with header?
>>> data.num_vertices
89
>>> data.num_tri_faces
215
>>> data.num_quad_faces
0
>>> data.num_uvs
89
>>> data.num_morphs
18
>>> data.read(stream) 
>>> print([str(morph.name.decode("ascii")) for morph in data.morphs])
['Fear', 'Surprise', 'Aah', 'BigAah', 'BMP', 'ChJSh', 'DST', 'Eee', 'Eh', 'FV', 'I', 'K', 'N', 'Oh', 'OohQ', 'R', 'Th', 'W']

Parse all TRI files in a directory tree

>>> for stream, data in TriFormat.walkData(format_root):
...     try:
...         # the replace call makes the doctest also pass on windows
...         os_path = stream.name
...         split = (os_path.split(os.sep))[-4:]
...         rejoin = os.path.join(*split).replace(os.sep, "/")
...         print("reading %s" % rejoin)
...     except Exception:
...         print(
...             "Warning: read failed due corrupt file,"
...             " corrupt format description, or bug.") 
reading tests/formats/tri/mmouthxivilai.tri

Create an TRI file from scratch and write to file

>>> data = TriFormat.Data()
>>> from tempfile import TemporaryFile
>>> stream = TemporaryFile()
>>> data.write(stream)