psemek/tools/convert-mesh/bin/convert-mesh.py

151 lines
3.4 KiB
Python

import bpy
import math
import sys
import struct
bpy.ops.object.mode_set(mode = 'OBJECT')
mesh = None
flat = False
if 'mesh' in bpy.data.objects:
mesh = bpy.data.objects['mesh'].data
print('Using smooth normals')
if 'mesh_flat' in bpy.data.objects:
mesh = bpy.data.objects['mesh_flat'].data
print('Using flat normals')
flat = True
assert mesh
colors = None
if len(mesh.vertex_colors) > 0:
colors = mesh.vertex_colors.active.data
print('Found vertex colors')
texcoords = None
if len(mesh.uv_layers) > 0:
texcoords = mesh.uv_layers.active.data
print('Found texture coordinates')
skeleton = None
if 'skeleton' in bpy.data.objects:
skeleton = bpy.data.objects['skeleton'].data
print('Found skeleton')
POSITION_MASK = 1
NORMAL_MASK = 2
COLOR_MASK = 4
TEXCOORD_MASK = 8
vertex_format = POSITION_MASK | NORMAL_MASK
if colors:
vertex_format |= COLOR_MASK
if texcoords:
vertex_format |= TEXCOORD_MASK
print("Using vertex format", format(vertex_format, '04b'))
vertex_coords = []
vertex_normals = []
vertex_colors = []
vertex_texcoords = []
indices = []
mesh.calc_loop_triangles()
if flat:
for p in mesh.loop_triangles:
for li in p.loops:
i = len(vertex_coords)
v = mesh.vertices[mesh.loops[li].vertex_index]
vertex_coords.append((v.co.x, v.co.y, v.co.z))
vertex_normals.append((p.normal.x, p.normal.y, p.normal.z))
if colors:
vertex_colors.append(tuple(colors[li].color))
if texcoords:
vertex_texcoords.append(tuple(texcoords[li].uv))
indices.append(i)
else:
for v in mesh.vertices:
vertex_coords.append((v.co.x, v.co.y, v.co.z))
vertex_normals.append((v.normal.x, v.normal.y, v.normal.z))
if colors:
vertex_colors = [None] * len(vertex_coords)
if texcoords:
vertex_texcoords = [None] * len(vertex_coords)
for p in mesh.loop_triangles:
for li in p.loops:
vi = mesh.loops[li].vertex_index
indices.append(vi)
v = mesh.vertices[vi]
if colors:
vertex_colors[vi] = tuple(colors[li].color)
if texcoords:
vertex_texcoords[vi] = tuple(texcoords[li].uv)
assert (len(indices) % 3) == 0
assert len(vertex_coords) == len(vertex_normals)
if colors:
assert len(vertex_coords) == len(vertex_colors)
if texcoords:
assert len(vertex_coords) == len(vertex_texcoords)
if colors:
for i in range(len(vertex_colors)):
c = 0
for k in (3, 2, 1, 0):
c = (c << 8) | int(max(0, min(255, vertex_colors[i][k] * 255)))
vertex_colors[i] = c
vertices = []
for i in range(len(vertex_coords)):
attribs = [vertex_coords[i], vertex_normals[i]]
if colors:
attribs.append(vertex_colors[i])
if texcoords:
attribs.append(vertex_texcoords[i])
vertices.append(tuple(attribs))
print(len(vertices), 'vertices')
print(len(indices), 'indices')
if skeleton is not None:
bones = []
for b in skeleton.data.bones:
if b.parent is None:
bones.append(-1)
else:
pi = list(skeleton.data.bones).index(b.parent)
bones.append(pi)
def to_bytes(obj):
if type(obj) == int:
if obj < 0:
return struct.pack('<i', obj)
else:
return struct.pack('<I', obj)
if type(obj) == float:
return struct.pack('<f', obj)
if type(obj) == tuple:
res = bytes()
for x in obj:
res += to_bytes(x)
return res
if type(obj) == list:
res = to_bytes(len(obj))
for x in obj:
res += to_bytes(x)
return res
if skeleton is not None:
# TODO: support skeletons
assert False
else:
data = to_bytes((vertex_format, vertices, indices))
filename = sys.argv[sys.argv.index('--') + 1]
with open(filename, 'wb') as f:
f.write(data)