Package pyffi :: Package utils :: Module mopp
[hide private]
[frames] | no frames]

Source Code for Module pyffi.utils.mopp

  1  """Create mopps using mopper.exe""" 
  2   
  3  # ***** BEGIN LICENSE BLOCK ***** 
  4  # 
  5  # Copyright (c) 2007-2011, Python File Format Interface 
  6  # All rights reserved. 
  7  # 
  8  # Redistribution and use in source and binary forms, with or without 
  9  # modification, are permitted provided that the following conditions 
 10  # are met: 
 11  # 
 12  #    * Redistributions of source code must retain the above copyright 
 13  #      notice, this list of conditions and the following disclaimer. 
 14  # 
 15  #    * Redistributions in binary form must reproduce the above 
 16  #      copyright notice, this list of conditions and the following 
 17  #      disclaimer in the documentation and/or other materials provided 
 18  #      with the distribution. 
 19  # 
 20  #    * Neither the name of the Python File Format Interface 
 21  #      project nor the names of its contributors may be used to endorse 
 22  #      or promote products derived from this software without specific 
 23  #      prior written permission. 
 24  # 
 25  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 26  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 27  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 28  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 29  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 30  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 31  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 32  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 33  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 34  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 35  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 36  # POSSIBILITY OF SUCH DAMAGE. 
 37  # 
 38  # ***** END LICENSE BLOCK ***** 
 39   
 40  import os.path 
 41  import tempfile 
 42  import subprocess 
 43   
44 -def _skip_terminal_chars(stream):
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
52 -def getMopperPath():
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
68 -def getMopperCredits():
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+") # not binary 90 try: 91 # get license info, credit havok (raises OSError on failure) 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
100 -def getMopperOriginScaleCodeWelding(vertices, triangles, material_indices=None):
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+") # not binary 153 outfile = tempfile.TemporaryFile("w+") # not binary 154 try: 155 # set up input 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 # call mopper (raises OSError on failure) 167 subprocess.call([mopper, "--"], stdin=infile, stdout=outfile) 168 # process output 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 # conversion failed 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