You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
5.5 KiB
Python

import functools
def weight_cmp(a, b):
return a[1] < b[1] or (a[1] == b[1] and a[0] < b[0])
def tuple_weights(weights):
return tuple((tuple(w) for w in weights))
class GeoVertex:
def __init__(self, coord, normal, uv, weights):
self.coord = coord
self.normal = normal
self.uv = uv
self.weights = tuple(weights)
def __eq__(self, other):
return self.coord == other.coord and self.normal == other.normal and self.uv == other.uv and self.weights == other.weights
def __hash__(self):
#print("__hash__: %s" % ((tuple(self.coord), tuple(self.normal), tuple(self.uv), tuple(self.weights)), ))
#self.dump()
return hash((tuple(self.coord), tuple(self.normal), tuple(self.uv), tuple_weights(self.weights)))
def selectWeights(self, count = None):
"""Returns the list of weights attached to this vertex. List is sorted by weight, with the strongest first. If 'count' is given, only 'count' strongest are return. The final list is normalized so the sum is 1."""
if len(self.weights) <= 0:
return []
weights = list(self.weights)
#sort by weight
weights.sort(key = functools.cmp_to_key(weight_cmp), reverse = True)
if count is not None and len(weights) > count:
weights = weights[0:count]
nw = 0.0
for w in weights:
nw += w[1]
if nw <= 0:
for w in weights:
w[1] = 0
weights[0][1] = 1
else:
for w in weights:
w[1] /= nw
return weights
def dump(self):
print(" GeoVertex: coord: %s normal: %s uv: %s weights: %s" % (self.coord, self.normal, self.uv, self.weights))
class GeoFace:
def __init__(self, vert_indexes, texture_index):
self.vert_indexes = vert_indexes
self.texture_index = texture_index
def __eq__(self, other):
return self.vert_indexes == other.vert_indexes and self.texture_index == other.texture_index
def dump(self):
print(" GeoFace: vertex indexes: %s texture index: %s" % (self.vert_indexes, self.texture_index))
class GeoMesh:
def __init__(self):
self.geovertex = []
self.geovertex_map = {}
self.textures = []
self.textures_map = {}
self.weights = []
self.weights_map = {}
self.face = []
self.have_weights = False
self.have_uvs = True
def getGeoVertexIndexNew(self, gv):
index = self.geovertex_map.get(gv, len(self.geovertex))
if index == len(self.geovertex):
self.geovertex_map[gv] = index
index = len(self.geovertex)
self.geovertex.append(gv)
return index
def getGeoVertexIndex(self, gv):
index = self.geovertex_map.get(gv, len(self.geovertex))
if index == len(self.geovertex):
self.geovertex_map[gv] = index
self.geovertex.append(gv)
return index
def getTextureIndex(self, name):
index = self.textures_map.get(name, len(self.textures))
if index == len(self.textures):
self.textures_map[name] = index
self.textures.append(name)
return index
def getWeightIndex(self, name):
index = self.weights_map.get(name, len(self.weights))
if index == len(self.weights):
self.weights_map[name] = index
self.weights.append(name)
return index
def addFace(self, geovertices, texture_name):
l = len(geovertices)
if l > 3:
#Do a naive conversion to a triangle fan, add each of those triangles as a face. Will give bad results in shape is not convex.
#Choose the start point as the one closest to the origin. Ties are resolved by lexical comparison of the coordinates.
start = 0
start_dist = geovertices[0].coord.magnitude
for i in range(1, len(geovertices)):
dist = geovertices[i].coord.magnitude
if dist < start_dist:
start = i
start_dist = dist
elif dist == start_dist:
for j in range(3):
if geovertices[i].coord[j] < geovertices[start].coord[j]:
start = i
start_dist = dist
break
for i in range(2, len(geovertices)):
i1 = (start + i - 1) % l
i2 = (start + i) % l
self.addFace([geovertices[start], geovertices[i1], geovertices[i2]], texture_name)
return
elif l < 3:
return
for i in range(3):
for w in geovertices[i].weights:
# w_index = self.getWeightIndex(w[0])
self.have_weights = True
geovertices_index = [self.getGeoVertexIndex(geovertices[0]),
self.getGeoVertexIndex(geovertices[1]),
self.getGeoVertexIndex(geovertices[2])]
self.face.append(GeoFace(geovertices_index, self.getTextureIndex(texture_name)))
pass
def sortFaces(self):
#Sort faces so they're grouped by texture index.
#todo:
pass
def dump(self):
print("GeoMesh:")
print(" Textures: %s" % (self.textures, ))
print(" Weights: %s" % (self.weights, ))
print(" Vertices:")
for i, v in enumerate(self.geovertex):
v.dump()
print(" Faces:")
for i, f in enumerate(self.face):
f.dump()