quakeforge/tools/io_mesh_qfmdl/import_mdl.py

305 lines
9.8 KiB
Python
Raw Normal View History

# vim:ts=4:et
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import bpy
from bpy_extras.object_utils import object_data_add
from mathutils import Vector,Matrix
from .quakepal import palette
from .mdl import MDL
2011-09-15 04:21:08 +00:00
def make_verts(mdl, framenum, subframenum=0):
frame = mdl.frames[framenum]
if frame.type:
frame = frame.frames[subframenum]
verts = []
s = Vector(mdl.scale)
o = Vector(mdl.scale_origin)
m = Matrix(((s.x, 0, 0,o.x),
( 0,s.y, 0,o.y),
( 0, 0,s.z,o.z),
( 0, 0, 0, 1)))
for v in frame.verts:
verts.append(m * Vector(v.r))
2011-09-15 04:21:08 +00:00
return verts
def make_faces(mdl):
faces = []
uvs = []
for tri in mdl.tris:
tv = list(tri.verts)
2011-09-15 04:21:08 +00:00
sts = []
for v in tri.verts:
stv = mdl.stverts[v]
s = stv.s
t = stv.t
if stv.onseam and not tri.facesfront:
s += mdl.skinwidth / 2
# quake textures are top to bottom, but blender images
# are bottom to top
sts.append((s * 1.0 / mdl.skinwidth, 1 - t * 1.0 / mdl.skinheight))
# blender's and quake's vertex order seem to be opposed
tv.reverse()
sts.reverse()
# annoyingly, blender can't have 0 in the final vertex, so rotate the
# face vertices and uvs
if not tv[2]:
tv = [tv[2]] + tv[:2]
sts = [sts[2]] + sts[:2]
faces.append (tv)
2011-09-15 04:21:08 +00:00
uvs.append(sts)
return faces, uvs
def load_skins(mdl):
def load_skin(skin, name):
img = bpy.data.images.new(name, mdl.skinwidth, mdl.skinheight)
mdl.images.append(img)
p = [0.0] * mdl.skinwidth * mdl.skinheight * 4
d = skin.pixels
for j in range(mdl.skinheight):
for k in range(mdl.skinwidth):
c = palette[d[j * mdl.skinwidth + k]]
# quake textures are top to bottom, but blender images
# are bottom to top
l = ((mdl.skinheight - 1 - j) * mdl.skinwidth + k) * 4
p[l + 0] = c[0] / 255.0
p[l + 1] = c[1] / 255.0
p[l + 2] = c[2] / 255.0
p[l + 3] = 1.0
img.pixels[:] = p[:]
if hasattr(img, "pack"):
img.pack(True)
mdl.images=[]
for i, skin in enumerate(mdl.skins):
if skin.type:
for j, subskin in enumerate(skin.skins):
load_skin (subskin, "%s_%d_%d" % (mdl.name, i, j))
else:
load_skin (skin, "%s_%d" % (mdl.name, i))
def setup_skins (mdl, uvs):
load_skins (mdl)
img = mdl.images[0] # use the first skin for now
uvlay = mdl.mesh.uv_textures.new(mdl.name)
uvloop = mdl.mesh.uv_loop_layers[0]
for i, texpoly in enumerate(uvlay.data):
poly = mdl.mesh.polygons[i]
2011-09-15 04:21:08 +00:00
mdl_uv = uvs[i]
texpoly.image = img
for j,k in enumerate(poly.loop_indices):
uvloop.data[k].uv = mdl_uv[j]
mat = bpy.data.materials.new(mdl.name)
mat.diffuse_color = (1,1,1)
mat.use_raytrace = False
tex = bpy.data.textures.new(mdl.name, 'IMAGE')
tex.extension = 'CLIP'
tex.use_preview_alpha = True
tex.image = img
mat.texture_slots.add()
ts = mat.texture_slots[0]
ts.texture = tex
ts.use_map_alpha = True
ts.texture_coords = 'UV'
mdl.mesh.materials.append(mat)
def make_shape_key(mdl, framenum, subframenum=0):
frame = mdl.frames[framenum]
name = "%s_%d" % (mdl.name, framenum)
if frame.type:
frame = frame.frames[subframenum]
name = "%s_%d_%d" % (mdl.name, framenum, subframenum)
if frame.name:
name = frame.name
else:
frame.name = name
frame.key = mdl.obj.shape_key_add(name)
frame.key.value = 0.0
mdl.keys.append (frame.key)
s = Vector(mdl.scale)
o = Vector(mdl.scale_origin)
m = Matrix(((s.x, 0, 0,o.x),
( 0,s.y, 0,o.y),
( 0, 0,s.z,o.z),
( 0, 0, 0, 1)))
for i, v in enumerate(frame.verts):
frame.key.data[i].co = m * Vector(v.r)
2011-09-15 04:21:08 +00:00
def build_shape_keys(mdl):
mdl.keys = []
2011-09-20 10:32:49 +00:00
mdl.obj.shape_key_add("Basis")
mdl.obj.active_shape_key_index = 0
for i, frame in enumerate(mdl.frames):
frame = mdl.frames[i]
if frame.type:
for j in range(len(frame.frames)):
make_shape_key(mdl, i, j)
else:
make_shape_key(mdl, i)
def set_keys(act, data):
for d in data:
key, co = d
dp = """key_blocks["%s"].value""" % key.name
fc = act.fcurves.new(data_path = dp)
fc.keyframe_points.add(len(co))
for i in range(len(co)):
fc.keyframe_points[i].co = co[i]
def build_actions(mdl):
sk = mdl.mesh.shape_keys
for frame in mdl.frames:
sk.animation_data_create()
sk.animation_data.action = bpy.data.actions.new(frame.name)
act=sk.animation_data.action
act.use_fake_user = True
data = []
2011-09-18 06:37:17 +00:00
other_keys = mdl.keys[:]
if frame.type:
for j, subframe in enumerate(frame.frames):
co = []
if j > 1:
co.append ((1.0, 0.0))
if j > 0:
co.append ((j * 1.0, 0.0))
co.append (((j + 1) * 1.0, 1.0))
if j < len(frame.frames) - 2:
co.append (((j + 2) * 1.0, 0.0))
if j < len(frame.frames) - 1:
co.append ((len(frame.frames) * 1.0, 0.0))
data.append((subframe.key, co))
if subframe.key in other_keys:
del(other_keys[other_keys.index(subframe.key)])
co = [(1.0, 0.0), (len(frame.frames) * 1.0, 0.0)]
2011-09-18 06:37:17 +00:00
for k in other_keys:
data.append((k, co))
else:
data.append((frame.key, [(1.0, 1.0)]))
2011-09-18 06:37:17 +00:00
if frame.key in other_keys:
del(other_keys[other_keys.index(frame.key)])
co = [(1.0, 0.0)]
for k in other_keys:
data.append((k, co))
set_keys (act, data)
def merge_frames(mdl):
2011-09-20 10:32:49 +00:00
def get_base(name):
i = 0
while i < len(name) and name[i] not in "0123456789":
i += 1
return name[:i]
i = 0
while i < len(mdl.frames):
if mdl.frames[i].type:
i += 1
continue
base = get_base(mdl.frames[i].name)
j = i + 1
while j < len(mdl.frames):
if mdl.frames[j].type:
break
if get_base(mdl.frames[j].name) != base:
break
j += 1
f = MDL.Frame()
f.name = base
f.type = 1
f.frames = mdl.frames[i:j]
mdl.frames[i:j] = [f]
i += 1
def write_text(mdl):
string = "$eyeposition %g %g %g\n" % mdl.eyeposition
string += "$flags %d\n" % mdl.flags
if mdl.synctype:
string += "$sync\n"
txt = bpy.data.texts.new(mdl.name)
txt.from_string(string)
return txt.name
def parse_flags(flags):
#NOTE these are in QuakeForge priority order; a little different to id.
# id has rocket and grenate between tracer2 and tracer3
if flags & MDL.EF_ROCKET:
return 'EF_ROCKET'
elif flags & MDL.EF_GRENADE:
return 'EF_GRENADE'
elif flags & MDL.EF_GIB:
return 'EF_GIB'
elif flags & MDL.EF_ZOMGIB:
return 'EF_ZOMGIB'
elif flags & MDL.EF_TRACER:
return 'EF_TRACER'
elif flags & MDL.EF_TRACER2:
return 'EF_TRACER2'
elif flags & MDL.EF_TRACER3:
return 'EF_TRACER3'
else:
return 'EF_NONE'
def set_properties(mdl):
mdl.obj.qfmdl.eyeposition = mdl.eyeposition
try:
mdl.obj.qfmdl.synctype = MDL.SYNCTYPE[mdl.synctype]
except IndexError:
mdl.obj.qfmdl.synctype = 'ST_SYNC'
mdl.obj.qfmdl.rotate = (mdl.flags & MDL.EF_ROTATE) and True or False
mdl.obj.qfmdl.effects = parse_flags(mdl.flags)
def import_mdl(operator, context, filepath):
bpy.context.user_preferences.edit.use_global_undo = False
for obj in bpy.context.scene.objects:
obj.select = False
mdl = MDL()
if not mdl.read(filepath):
2011-09-20 04:34:12 +00:00
operator.report({'ERROR'},
"Unrecognized format: %s %d" % (mdl.ident, mdl.version))
return {'CANCELLED'}
faces, uvs = make_faces (mdl)
verts = make_verts (mdl, 0)
mdl.mesh = bpy.data.meshes.new(mdl.name)
mdl.mesh.from_pydata(verts, [], faces)
mdl.obj = bpy.data.objects.new(mdl.name, mdl.mesh)
bpy.context.scene.objects.link(mdl.obj)
bpy.context.scene.objects.active = mdl.obj
mdl.obj.select = True
setup_skins (mdl, uvs)
if mdl.images and not hasattr(mdl.images[0], "pack"):
operator.report({'WARNING'},
"Unable to pack skins. They must be packed by hand."
+" Some may have been lost")
if len(mdl.frames) > 1 or mdl.frames[0].type:
build_shape_keys(mdl)
merge_frames(mdl)
build_actions(mdl)
#operator.report({'INFO'},
# "Extra settings saved in the %s text block." % write_text(mdl))
set_properties(mdl)
mdl.mesh.update()
bpy.context.user_preferences.edit.use_global_undo = True
return {'FINISHED'}