1 """Create mopps using mopper.exe"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 import os.path
41 import tempfile
42 import subprocess
43
45 """Skip initial terminal characters (happens when mopper runs via wine)."""
46 firstline = stream.readline()
47 if '\x1b' in firstline:
48 stream.seek(firstline.rfind('\x1b') + 2)
49 else:
50 stream.seek(0)
51
53 """Get path to the mopper.
54
55 >>> path = getMopperPath()
56 >>> path.endswith("mopper.exe")
57 True
58
59 :raise ``OSError``: If mopper.exe is not found.
60 :return: Path to mopper.exe.
61 :rtype: ``str``
62 """
63 mopper = os.path.join(os.path.dirname(__file__), "mopper.exe")
64 if not os.path.exists(mopper):
65 raise OSError("mopper.exe not found at %s" % mopper)
66 return mopper
67
69 """Get info about mopper, and credit havok.
70
71 >>> print(getMopperCredits())
72 Mopper. Copyright (c) 2008, NIF File Format Library and Tools.
73 All rights reserved.
74 <BLANKLINE>
75 Options:
76 --help for usage help
77 --license for licensing details
78 <BLANKLINE>
79 Mopper uses havok. Copyright 1999-2008 Havok.com Inc. (and its Licensors).
80 All Rights Reserved. See www.havok.com for details.
81 <BLANKLINE>
82 <BLANKLINE>
83
84 :raise ``OSError``: If mopper.exe is not found or cannot run.
85 :return: Credits string.
86 :rtype: ``str``
87 """
88 mopper = getMopperPath()
89 outfile = tempfile.TemporaryFile("w+")
90 try:
91
92 subprocess.call([mopper], stdout=outfile)
93 outfile.seek(0)
94 _skip_terminal_chars(outfile)
95 creditstr = outfile.read().replace("\r\n", "\n")
96 finally:
97 outfile.close()
98 return creditstr
99
101 """Generate mopp code and welding info for given geometry. Raises
102 RuntimeError if something goes wrong (e.g. if mopp generator fails, or if
103 mopper.exe cannot be run on the current platform).
104
105 Call L{getMopperCredits} before calling this function if you need to credit
106 havok in a console application that uses this function.
107
108 For example, creating a mopp for the standard cube:
109
110 >>> expected_moppcode = [
111 ... 40, 0, 255, 39, 0, 255, 38, 0, 255, 19, 129, 125, 41, 22, 130,
112 ... 125, 12, 24, 130, 125, 4, 38, 0, 5, 51, 39, 0, 5, 50, 24, 130,
113 ... 125, 4, 40, 0, 5, 59, 16, 255, 249, 12, 20, 130, 125, 4, 39,
114 ... 0, 5, 53, 40, 0, 5, 49, 54, 22, 130, 125, 25, 24, 130, 125, 17,
115 ... 17, 255, 249, 12, 21, 129, 125, 4, 38, 0, 5, 57, 40, 249, 255,
116 ... 58, 56, 40, 249, 255, 52, 24, 130, 125, 4, 39, 249, 255, 55, 38,
117 ... 249, 255, 48]
118 >>> orig, scale, moppcode, welding_info = getMopperOriginScaleCodeWelding(
119 ... [(1, 1, 1), (0, 0, 0), (0, 0, 1), (0, 1, 0),
120 ... (1, 0, 1), (0, 1, 1), (1, 1, 0), (1, 0, 0)],
121 ... [(0, 4, 6), (1, 6, 7), (2, 1, 4), (3, 1, 2),
122 ... (0, 2, 4), (4, 1, 7), (6, 4, 7), (3, 0, 6),
123 ... (0, 3, 5), (3, 2, 5), (2, 0, 5), (1, 3, 6)])
124 >>> scale
125 16319749.0
126 >>> ["%6.3f" % value for value in orig]
127 ['-0.010', '-0.010', '-0.010']
128 >>> moppcode == expected_moppcode
129 True
130 >>> welding_info
131 [23030, 23247, 23030, 16086, 23247, 23247, 23247, 23247, 23247, 23247, 23247, 16086]
132
133 :raise ``RuntimeError``: If the mopper has bad output.
134 :raise ``OSError``: If the mopper is not found or cannot run.
135 :param vertices: List of vertices.
136 :type vertices: list of tuples of floats
137 :param triangles: List of triangles (indices referring back to vertex list).
138 :type triangles: list of tuples of ints
139 :param material_indices: List of material indices (optional).
140 :type material_indices: list of ints
141 :return: The origin as a tuple of floats, the mopp scale as a float,
142 the mopp code as a list of ints, and the welding info as a list of
143 ints.
144 :rtype: ``tuple`` of ``float``\ s, ``float``, ``list`` of ``int``\ s, and ``list``
145 of ``int``\ s
146 """
147
148 if material_indices is None:
149 material_indices = []
150
151 mopper = getMopperPath()
152 infile = tempfile.TemporaryFile("w+")
153 outfile = tempfile.TemporaryFile("w+")
154 try:
155
156 infile.write("%i\n" % len(vertices))
157 for vert in vertices:
158 infile.write("%f %f %f\n" % vert)
159 infile.write("\n%i\n" % len(triangles))
160 for tri in triangles:
161 infile.write("%i %i %i\n" % tri)
162 infile.write("\n%i\n" % len(material_indices))
163 for matindex in material_indices:
164 infile.write("%i\n" % matindex)
165 infile.seek(0)
166
167 subprocess.call([mopper, "--"], stdin=infile, stdout=outfile)
168
169 outfile.seek(0)
170 _skip_terminal_chars(outfile)
171 try:
172 origin = tuple(float(outfile.readline()) for i in xrange(3))
173 scale = float(outfile.readline())
174 moppcodelen = int(outfile.readline())
175 moppcode = [int(outfile.readline()) for i in xrange(moppcodelen)]
176 welding_info_len = int(outfile.readline())
177 welding_info = [int(outfile.readline())
178 for i in xrange(welding_info_len)]
179 except ValueError:
180
181 raise RuntimeError("invalid mopper output (mopper failed?)")
182 finally:
183 infile.close()
184 outfile.close()
185 return origin, scale, moppcode, welding_info
186
187 if __name__ == "__main__":
188 import doctest
189 doctest.testmod()
190