Package pyffi :: Package spells :: Package cgf :: Module check
[hide private]
[frames] | no frames]

Source Code for Module pyffi.spells.cgf.check

  1  """Module which contains all spells that check something in a cgf file.""" 
  2   
  3  # -------------------------------------------------------------------------- 
  4  # ***** BEGIN LICENSE BLOCK ***** 
  5  # 
  6  # Copyright (c) 2007-2011, NIF File Format Library and Tools. 
  7  # All rights reserved. 
  8  # 
  9  # Redistribution and use in source and binary forms, with or without 
 10  # modification, are permitted provided that the following conditions 
 11  # are met: 
 12  # 
 13  #    * Redistributions of source code must retain the above copyright 
 14  #      notice, this list of conditions and the following disclaimer. 
 15  # 
 16  #    * Redistributions in binary form must reproduce the above 
 17  #      copyright notice, this list of conditions and the following 
 18  #      disclaimer in the documentation and/or other materials provided 
 19  #      with the distribution. 
 20  # 
 21  #    * Neither the name of the NIF File Format Library and Tools 
 22  #      project nor the names of its contributors may be used to endorse 
 23  #      or promote products derived from this software without specific 
 24  #      prior written permission. 
 25  # 
 26  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 27  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 28  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 29  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 30  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 31  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 32  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 33  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 34  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 35  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 36  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 37  # POSSIBILITY OF SUCH DAMAGE. 
 38  # 
 39  # ***** END LICENSE BLOCK ***** 
 40  # -------------------------------------------------------------------------- 
 41   
 42  from itertools import izip 
 43  from tempfile import TemporaryFile 
 44   
 45  from pyffi.formats.cgf import CgfFormat 
 46  from pyffi.spells.cgf import CgfSpell 
 47  # XXX do something about this... 
 48  from pyffi.utils.mathutils import * 
 49   
50 -class SpellReadWrite(CgfSpell):
51 """Like the original read-write spell, but with additional file size 52 check.""" 53 54 SPELLNAME = "check_readwrite" 55
56 - def dataentry(self):
57 self.toaster.msgblockbegin("writing to temporary file") 58 f_tmp = TemporaryFile() 59 try: 60 total_padding = self.data.write(f_tmp) 61 # comparing the files will usually be different because blocks may 62 # have been written back in a different order, so cheaply just compare 63 # file sizes 64 self.toaster.msg("comparing file sizes") 65 self.stream.seek(0, 2) 66 f_tmp.seek(0, 2) 67 if self.stream.tell() != f_tmp.tell(): 68 self.toaster.msg("original size: %i" % self.stream.tell()) 69 self.toaster.msg("written size: %i" % f_tmp.tell()) 70 self.toaster.msg("padding: %i" % total_padding) 71 if self.stream.tell() > f_tmp.tell() or self.stream.tell() + total_padding < f_tmp.tell(): 72 f_tmp.seek(0) 73 f_debug = open("debug.cgf", "wb") 74 f_debug.write(f_tmp.read(-1)) 75 f_debug.close() 76 raise Exception('write check failed: file sizes differ by more than padding') 77 finally: 78 f_tmp.close() 79 self.toaster.msgblockend() 80 81 # spell is finished: prevent recursing into the tree 82 return False
83
84 -class SpellCheckTangentSpace(CgfSpell):
85 """This spell checks the tangent space calculation. 86 Only useful for debugging. 87 """ 88 89 SPELLNAME = "check_tangentspace" 90 SENSITIVITY = 0.1 # admissible float error (relative to one) 91
92 - def datainspect(self):
94
95 - def branchinspect(self, branch):
96 return isinstance(branch, (CgfFormat.MeshChunk, CgfFormat.NodeChunk))
97
98 - def branchentry(self, branch):
99 if not isinstance(branch, CgfFormat.MeshChunk): 100 # keep recursing 101 return True 102 103 # get tangents and normals 104 if not (branch.normals_data and branch.tangents_data): 105 return True 106 107 oldtangents = [tangent for tangent in branch.tangents_data.tangents] 108 109 self.toaster.msg("recalculating new tangent space") 110 branch.update_tangent_space() 111 newtangents = [tangent for tangent in branch.tangents_data.tangents] 112 113 self.toaster.msgblockbegin("validating and checking old with new") 114 115 for norm, oldtangent, newtangent in izip(branch.normals_data.normals, 116 oldtangents, newtangents): 117 #self.toaster.msg("*** %s ***" % (norm,)) 118 # check old 119 norm = (norm.x, norm.y, norm.z) 120 tan = tuple(x / 32767.0 121 for x in (oldtangent[0].x, 122 oldtangent[0].y, 123 oldtangent[0].z)) 124 bin = tuple(x / 32767.0 125 for x in (oldtangent[1].x, 126 oldtangent[1].y, 127 oldtangent[1].z)) 128 if abs(vecNorm(norm) - 1) > self.SENSITIVITY: 129 self.toaster.logger.warn("normal has non-unit norm") 130 if abs(vecNorm(tan) - 1) > self.SENSITIVITY: 131 self.toaster.logger.warn("oldtangent has non-unit norm") 132 if abs(vecNorm(bin) - 1) > self.SENSITIVITY: 133 self.toaster.logger.warn("oldbinormal has non-unit norm") 134 if (oldtangent[0].w != oldtangent[1].w): 135 raise ValueError( 136 "inconsistent oldtangent w coordinate (%i != %i)" 137 % (oldtangent[0].w, oldtangent[1].w)) 138 if not (oldtangent[0].w in (-32767, 32767)): 139 raise ValueError( 140 "invalid oldtangent w coordinate (%i)" % oldtangent[0].w) 141 if oldtangent[0].w > 0: 142 cross = vecCrossProduct(tan, bin) 143 else: 144 cross = vecCrossProduct(bin, tan) 145 crossnorm = vecNorm(cross) 146 if abs(crossnorm - 1) > self.SENSITIVITY: 147 # a lot of these... 148 self.toaster.logger.warn("tan and bin not orthogonal") 149 self.toaster.logger.warn("%s %s" % (tan, bin)) 150 self.toaster.logger.warn("(error is %f)" 151 % abs(crossnorm - 1)) 152 cross = vecscalarMul(cross, 1.0/crossnorm) 153 if vecDistance(norm, cross) > self.SENSITIVITY: 154 self.toaster.logger.warn( 155 "norm not cross product of tangent and binormal") 156 #self.toaster.logger.warn("norm = %s" % (norm,)) 157 #self.toaster.logger.warn("tan = %s" % (tan,)) 158 #self.toaster.logger.warn("bin = %s" % (bin,)) 159 #self.toaster.logger.warn("tan bin cross prod = %s" % (cross,)) 160 self.toaster.logger.warn( 161 "(error is %f)" % vecDistance(norm, cross)) 162 163 # compare old with new 164 if sum((abs(oldtangent[0].x - newtangent[0].x), 165 abs(oldtangent[0].y - newtangent[0].y), 166 abs(oldtangent[0].z - newtangent[0].z), 167 abs(oldtangent[0].w - newtangent[0].w), 168 abs(oldtangent[1].x - newtangent[1].x), 169 abs(oldtangent[1].y - newtangent[1].y), 170 abs(oldtangent[1].z - newtangent[1].z), 171 abs(oldtangent[1].w - newtangent[1].w))) > self.SENSITIVITY * 32767.0: 172 ntan = tuple(x / 32767.0 for x in (newtangent[0].x, newtangent[0].y, newtangent[0].z)) 173 nbin = tuple(x / 32767.0 for x in (newtangent[1].x, newtangent[1].y, newtangent[1].z)) 174 self.toaster.logger.warn("old and new tangents differ substantially") 175 self.toaster.logger.warn("old tangent") 176 self.toaster.logger.warn("%s %s" % (tan, bin)) 177 self.toaster.logger.warn("new tangent") 178 self.toaster.logger.warn("%s %s" % (ntan, nbin)) 179 180 self.toaster.msgblockend()
181
182 -class SpellCheckHasVertexColors(CgfSpell):
183 """This spell checks if a model has vertex colors. 184 Only useful for debugging. 185 """ 186 # example: farcry/FCData/Objects/Buildings/M03/compound_area/coa_instantshelter_door_cloth.cgf 187 188 SPELLNAME = "check_vcols" 189
190 - def datainspect(self):
192
193 - def branchinspect(self, branch):
194 return isinstance(branch, (CgfFormat.MeshChunk, CgfFormat.NodeChunk))
195
196 - def branchentry(self, branch):
197 if isinstance(branch, CgfFormat.MeshChunk): 198 if branch.has_vertex_colors: 199 self.toaster.msg("has vertex colors!") 200 else: 201 # keep recursing 202 return True
203