mirror of https://github.com/AxioDL/metaforce.git
237 lines
9.6 KiB
Python
237 lines
9.6 KiB
Python
import bpy, struct, bmesh
|
|
from . import hmdl
|
|
from mathutils import Vector
|
|
VertPool = hmdl.HMDLMesh.VertPool
|
|
strip_next_loop = hmdl.HMDLMesh.strip_next_loop
|
|
|
|
def recursive_faces_islands(list_out, rem_list, face):
|
|
if face not in rem_list:
|
|
return []
|
|
|
|
list_out.append(face)
|
|
rem_list.remove(face)
|
|
next_faces = []
|
|
for e in face.edges:
|
|
if not e.is_contiguous or e.seam:
|
|
continue
|
|
for f in e.link_faces:
|
|
if f == face:
|
|
continue
|
|
next_faces.append(f)
|
|
return next_faces
|
|
|
|
def cook(writebuf, mesh_obj):
|
|
if mesh_obj.type != 'MESH':
|
|
raise RuntimeError("%s is not a mesh" % mesh_obj.name)
|
|
|
|
obj_vismodes = dict((i[0], i[3]) for i in bpy.types.Object.retro_mapobj_vis_mode[1]['items'])
|
|
|
|
# Write out visibility type
|
|
vis_types = dict((i[0], i[3]) for i in bpy.types.Scene.retro_map_vis_mode[1]['items'])
|
|
writebuf(struct.pack('I', vis_types[bpy.context.scene.retro_map_vis_mode]))
|
|
|
|
# Copy mesh (and apply mesh modifiers with triangulation)
|
|
copy_name = mesh_obj.name + "_hmdltri"
|
|
copy_mesh = bpy.data.meshes.new(copy_name)
|
|
copy_obj = bpy.data.objects.new(copy_name, copy_mesh)
|
|
copy_obj.data = mesh_obj.to_mesh(bpy.context.scene, True, 'RENDER')
|
|
copy_mesh = copy_obj.data
|
|
copy_obj.scale = mesh_obj.scale
|
|
bpy.context.scene.objects.link(copy_obj)
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
bpy.context.scene.objects.active = copy_obj
|
|
copy_obj.select = True
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
bpy.ops.mesh.select_all(action='SELECT')
|
|
bpy.ops.mesh.quads_convert_to_tris()
|
|
bpy.ops.mesh.select_all(action='DESELECT')
|
|
bpy.context.scene.update()
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
copy_mesh.calc_normals_split()
|
|
rna_loops = copy_mesh.loops
|
|
|
|
# Create master BMesh and VertPool
|
|
bm_master = bmesh.new()
|
|
bm_master.from_mesh(copy_obj.data)
|
|
vert_pool = VertPool(bm_master, rna_loops)
|
|
|
|
# Output vert pool
|
|
vert_pool.write_out_map(writebuf)
|
|
|
|
# Create map surfaces and borders
|
|
faces_rem = list(bm_master.faces)
|
|
loop_iter = 0
|
|
loop_ranges = []
|
|
while len(faces_rem):
|
|
island_faces = []
|
|
faces = [faces_rem[0]]
|
|
while len(faces):
|
|
next_faces = []
|
|
ret_faces = None
|
|
for f in faces:
|
|
ret_faces = recursive_faces_islands(island_faces, faces_rem, f)
|
|
if ret_faces == False:
|
|
break
|
|
next_faces.extend(ret_faces)
|
|
if ret_faces == False:
|
|
break
|
|
faces = next_faces
|
|
|
|
# island_faces now holds one island (map edge delimited)
|
|
prev_loop_emit = None
|
|
loop_set = set()
|
|
edge_set = set()
|
|
out_count = 0
|
|
loop_count = 0
|
|
while len(island_faces):
|
|
sel_lists_local = []
|
|
restore_out_count = out_count
|
|
for start_face in island_faces:
|
|
for l in start_face.loops:
|
|
out_count = restore_out_count
|
|
island_local = list(island_faces)
|
|
if out_count & 1:
|
|
prev_loop = l.link_loop_prev
|
|
loop = prev_loop.link_loop_prev
|
|
sel_list = [l, prev_loop, loop]
|
|
prev_loop = loop
|
|
else:
|
|
prev_loop = l.link_loop_next
|
|
loop = prev_loop.link_loop_next
|
|
sel_list = [l, prev_loop, loop]
|
|
out_count += 3
|
|
island_local.remove(start_face)
|
|
while True:
|
|
if not prev_loop.edge.is_contiguous or prev_loop.edge.seam:
|
|
break
|
|
loop, prev_loop = strip_next_loop(prev_loop, out_count)
|
|
face = loop.face
|
|
if face not in island_local:
|
|
break
|
|
sel_list.append(loop)
|
|
island_local.remove(face)
|
|
out_count += 1
|
|
sel_lists_local.append((sel_list, island_local, out_count))
|
|
max_count = 0
|
|
max_sl = None
|
|
max_island_faces = None
|
|
for sl in sel_lists_local:
|
|
if len(sl[0]) > max_count:
|
|
max_count = len(sl[0])
|
|
max_sl = sl[0]
|
|
max_island_faces = sl[1]
|
|
out_count = sl[2]
|
|
island_faces = max_island_faces
|
|
|
|
if prev_loop_emit:
|
|
vert_pool.loop_out_map(writebuf, prev_loop_emit)
|
|
vert_pool.loop_out_map(writebuf, max_sl[0])
|
|
loop_count += 2
|
|
loop_set.add(prev_loop_emit)
|
|
loop_set.add(max_sl[0])
|
|
loop_count += len(max_sl)
|
|
for loop in max_sl:
|
|
vert_pool.loop_out_map(writebuf, loop)
|
|
prev_loop_emit = loop
|
|
loop_set.add(loop)
|
|
for edge in loop.face.edges:
|
|
if edge.seam:
|
|
edge_set.add(edge)
|
|
|
|
# Create island surface with edges
|
|
if len(edge_set):
|
|
trace_edge = edge_set.pop()
|
|
else:
|
|
trace_edge = None
|
|
edge_ranges = []
|
|
edge_iter = loop_iter + loop_count
|
|
while trace_edge:
|
|
edge_count = 0
|
|
vert_pool.vert_out_map(writebuf, trace_edge.verts[0])
|
|
vert_pool.vert_out_map(writebuf, trace_edge.verts[1])
|
|
edge_count += 2
|
|
next_vert = trace_edge.verts[1]
|
|
found_edge = True
|
|
while found_edge:
|
|
found_edge = False
|
|
for edge in next_vert.link_edges:
|
|
if edge in edge_set:
|
|
edge_set.remove(edge)
|
|
next_vert = edge.other_vert(next_vert)
|
|
vert_pool.vert_out_map(writebuf, next_vert)
|
|
edge_count += 1
|
|
found_edge = True
|
|
break
|
|
if len(edge_set):
|
|
trace_edge = edge_set.pop()
|
|
else:
|
|
trace_edge = None
|
|
edge_ranges.append((edge_iter, edge_count))
|
|
edge_iter += edge_count
|
|
|
|
pos_avg = Vector()
|
|
norm_avg = Vector()
|
|
if len(loop_set):
|
|
for loop in loop_set:
|
|
pos_avg += loop.vert.co
|
|
norm_avg += loop.vert.normal
|
|
pos_avg /= len(loop_set)
|
|
norm_avg /= len(loop_set)
|
|
norm_avg.normalize()
|
|
|
|
loop_ranges.append((loop_iter, loop_count, edge_ranges, pos_avg, norm_avg))
|
|
loop_iter = edge_iter
|
|
|
|
# No more surfaces
|
|
writebuf(struct.pack('B', 0))
|
|
|
|
# Write out loop ranges and averages
|
|
writebuf(struct.pack('I', len(loop_ranges)))
|
|
for loop_range in loop_ranges:
|
|
writebuf(struct.pack('fff', loop_range[3][0], loop_range[3][1], loop_range[3][2]))
|
|
writebuf(struct.pack('fff', loop_range[4][0], loop_range[4][1], loop_range[4][2]))
|
|
writebuf(struct.pack('II', loop_range[0], loop_range[1]))
|
|
writebuf(struct.pack('I', len(loop_range[2])))
|
|
for edge_range in loop_range[2]:
|
|
writebuf(struct.pack('II', edge_range[0], edge_range[1]))
|
|
|
|
# Write out mappable objects
|
|
poi_count = 0
|
|
for obj in bpy.context.scene.objects:
|
|
if obj.retro_mappable_type != -1:
|
|
poi_count += 1
|
|
|
|
writebuf(struct.pack('I', poi_count))
|
|
for obj in bpy.context.scene.objects:
|
|
if obj.retro_mappable_type != -1:
|
|
writebuf(struct.pack('III',
|
|
obj.retro_mappable_type, obj_vismodes[obj.retro_mapobj_vis_mode], int(obj.retro_mappable_sclyid, 0)))
|
|
writebuf(struct.pack('ffffffffffffffff',
|
|
obj.matrix_world[0][0], obj.matrix_world[0][1], obj.matrix_world[0][2], obj.matrix_world[0][3],
|
|
obj.matrix_world[1][0], obj.matrix_world[1][1], obj.matrix_world[1][2], obj.matrix_world[1][3],
|
|
obj.matrix_world[2][0], obj.matrix_world[2][1], obj.matrix_world[2][2], obj.matrix_world[2][3],
|
|
obj.matrix_world[3][0], obj.matrix_world[3][1], obj.matrix_world[3][2], obj.matrix_world[3][3]))
|
|
|
|
def draw(layout, context):
|
|
obj = context.active_object
|
|
layout.prop(context.scene, 'retro_map_vis_mode', text='Visibility Mode')
|
|
if obj and obj.retro_mappable_type != -1:
|
|
layout.prop(obj, 'retro_mappable_type', text='Object Type')
|
|
layout.prop(obj, 'retro_mapobj_vis_mode', text='Object Visibility Mode')
|
|
layout.prop(obj, 'retro_mappable_sclyid', text='Object ID')
|
|
|
|
def register():
|
|
bpy.types.Object.retro_mappable_type = bpy.props.IntProperty(name='Retro: MAPA object type', default=-1)
|
|
bpy.types.Object.retro_mappable_sclyid = bpy.props.StringProperty(name='Retro: MAPA object SCLY ID')
|
|
bpy.types.Scene.retro_map_vis_mode = bpy.props.EnumProperty(items=[('ALWAYS', 'Always', 'Always Visible', 0),
|
|
('MAPSTATIONORVISIT', 'Map Station or Visit', 'Visible after Map Station or Visit', 1),
|
|
('VISIT', 'Visit', 'Visible after Visit', 2),
|
|
('NEVER', 'Never', 'Never Visible', 3)],
|
|
name='Retro: Map Visibility Mode')
|
|
bpy.types.Object.retro_mapobj_vis_mode = bpy.props.EnumProperty(items=[('ALWAYS', 'Always', 'Always Visible', 0),
|
|
('MAPSTATIONORVISIT', 'Map Station or Visit', 'Visible after Map Station or Visit', 1),
|
|
('VISIT', 'Visit', 'Visible after Door Visit', 2),
|
|
('NEVER', 'Never', 'Never Visible', 3),
|
|
('MAPSTATIONORVISIT2', 'Map Station or Visit 2', 'Visible after Map Station or Visit', 4)],
|
|
name='Retro: Map Object Visibility Mode')
|