home *** CD-ROM | disk | FTP | other *** search
- #
- # PYTHON IMPORTS
- #
- import array
- import collections
- import math
- import os
- import struct
- import sys
-
- #
- # BLENDER IMPORTS
- #
- import Blender
- from Blender import Image
- from Blender import Material
- from Blender import Mesh
- from Blender import Modifier
- from Blender import Mathutils
- from Blender.Mathutils import *
- from Blender import Texture
- from Blender import Types
- from Blender import Window
- import bpy
-
- #
- # MATH UTILITIES
- #
-
- def Array4x4ToBlenderMatrix(data):
-
- r1 = [data[ 0], data[ 1], data[ 2], data[ 3]]
- r2 = [data[ 4], data[ 5], data[ 6], data[ 7]]
- r3 = [data[ 8], data[ 9], data[10], data[11]]
- r4 = [data[12], data[13], data[14], data[15]]
- return Blender.Mathutils.Matrix(r1, r2, r3, r4)
-
- def NormalizeVector(data):
-
- norm = math.sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2])
- temp = [data[0]/norm, data[1]/norm, data[2]/norm]
- return temp
-
- #
- # STRING UTILITIES
- #
-
- def StripNullsFromStr(str):
- '''
- Strips null characters from a string.
- Notes: Blender does not like strings that contain null characters. This can
- happen when we load strings from binary files that were created using lang-
- uages such as C or C++.
- '''
- # make a copy, removing null characters
- retval = ''
- for c in str:
- if c != '\x00':
- retval += c
- return retval
-
- #
- # INPUT FILE STREAM
- #
-
- class InputFileStream:
- '''
- '''
-
- # CONSTRUCTOR
- def __init__(self):
-
- pass
-
- # PUBLIC METHOD: OPEN
- def open(self, filename):
-
- # open file
- try: self.ifile = open(filename, "rb")
- except: raise Exception('SMC Import Error: Failed to open file.')
-
- # PUBLIC METHOD: TELL
- def tell(self):
-
- return self.ifile.tell()
-
- # PUBLIC METHOD: SEEK
- def seek(self, position):
-
- # seek position
- self.ifile.seek(position)
-
- # PUBLIC METHOD: SKIP
- def skip(self, offset):
-
- # seek position
- self.ifile.seek(offset, 1)
-
- # PUBLIC METHOD: READ STRING
- def read_string(self, n):
-
- tmp = array.array('c')
- tmp.fromfile(self.ifile, n)
- ret = ''.join(tmp)
- return StripNullsFromStr(ret)
-
- # PUBLIC METHOD: READ UINT08
- def LE_read_uint08(self):
-
- tmp = self.ifile.read(1)
- if len(tmp) == 1: return struct.unpack('<B', tmp)[0];
- raise EOFError()
-
- # PUBLIC METHOD: READ UINT16
- def LE_read_uint16(self):
-
- tmp = self.ifile.read(2)
- if len(tmp) == 2: return struct.unpack('<H', tmp)[0];
- raise EOFError()
-
- # PUBLIC METHOD: READ UINT32
- def LE_read_uint32(self):
-
- tmp = self.ifile.read(4);
- if len(tmp) == 4: return struct.unpack('<I', tmp)[0];
- raise EOFError()
-
- # PUBLIC METHOD: READ UINT64
- def LE_read_uint64(self):
-
- tmp = self.ifile.read(8);
- if len(tmp) == 8: return struct.unpack('<Q', tmp)[0];
- raise EOFError()
-
- # PUBLIC METHOD: READ UINT08 ARRAY
- def LE_read_uint08_array(self, n):
-
- if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')
- ret = array.array('B')
- ret.fromfile(self.ifile, n)
- return ret;
-
- # PUBLIC METHOD: READ UINT16 ARRAY
- def LE_read_uint16_array(self, n):
-
- if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')
- ret = array.array('H')
- ret.fromfile(self.ifile, n)
- if sys.byteorder == "big": ret.byteswap()
- return ret;
-
- # PUBLIC METHOD: READ UINT32 ARRAY
- def LE_read_uint32_array(self, n):
-
- if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')
- ret = array.array('I')
- ret.fromfile(self.ifile, n)
- if sys.byteorder == "big": ret.byteswap()
- return ret;
-
- # PUBLIC METHOD: READ UINT64 ARRAY
- def LE_read_uint64_array(self, n):
-
- if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')
- ret = array.array('Q')
- ret.fromfile(self.ifile, n)
- if sys.byteorder == "big": ret.byteswap()
- return ret;
-
- # PUBLIC METHOD: READ REAL32
- def LE_read_real32(self):
-
- tmp = self.ifile.read(4);
- if len(tmp) == 4: return struct.unpack('<f', tmp)[0];
- raise EOFError()
-
- # PUBLIC METHOD: READ REAL64
- def LE_read_real64(self):
-
- tmp = self.ifile.read(8);
- if len(tmp) == 8: return struct.unpack('<d', tmp)[0];
- raise EOFError()
-
- # PUBLIC METHOD: READ REAL32 ARRAY
- def LE_read_real32_array(self, n):
-
- if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')
- ret = array.array('f')
- ret.fromfile(self.ifile, n)
- if sys.byteorder == "big": ret.byteswap()
- return ret;
-
- # PUBLIC METHOD: READ REAL64 ARRAY
- def LE_read_real64_array(self, n):
-
- if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')
- ret = array.array('d')
- ret.fromfile(self.ifile, n)
- if sys.byteorder == "big": ret.byteswap()
- return ret;
-
- #
- # STRUCTURES
- #
-
- class SMCHEADER:
- # uint32 magic
- # uint16 major_version
- # uint16 minor_version
- # uint32 n_vbuffers
- # uint32 n_ibuffers
- # uint32 n_images
- # uint32 n_surfaces
- # uint32 n_surfmats
- # uint32 n_skeletons
- # uint32 n_animations
- # uint32 reserved1
- # uint32 reserved2
- # uint32 reserved3
- # uint32 reserved4
- # uint32 reserved5
- # uint32 reserved6
- # uint32 reserved7
- pass
-
- class SMCVTXBUFFER:
- # uint32 flags
- # string name
- # uint16 uvchan
- # uint16 uvtype[i]
- # uint16 colors
- # uint32 elem
- # real32 positions[[]]
- # real32 normals[[]]
- # real32 tangents[[]]
- # real32 binormals[[]]
- # real32 blendweights[[]]
- # uint16 blendindices[[]]
- # real32 texcoords[[]]
- # real32 vtxcolors[[]]
- pass
-
- class SMCIDXBUFFER:
- # uint08 format
- # uint08 primitive
- # uint08 direction
- # string name
- # uint32 elem
- # T data[]
- pass
-
- class SMCSURFMAT:
- # string name
- # uint08 twoside
- # uint08 unused1
- # uint08 unused2
- # uint08 unused3
- # uint16 basemap
- # uint16 specmap
- # uint16 tranmap
- # uint16 bumpmap
- # uint16 normmap
- # uint16 lgthmap
- # uint16 envimap
- # uint16 glssmap
- # uint16 resmap1
- # uint16 resmap2
- # uint16 resmap3
- # uint16 resmap4
- # uint16 resmap5
- # uint16 resmap6
- # uint16 resmap7
- # uint16 resmap8
- # uint08 basemapchan
- # uint08 specmapchan
- # uint08 tranmapchan
- # uint08 bumpmapchan
- # uint08 normmapchan
- # uint08 lghtmapchan
- # uint08 envimapchan
- # uint08 glssmapchan
- # uint08 resmapchan1
- # uint08 resmapchan2
- # uint08 resmapchan3
- # uint08 resmapchan4
- # uint08 resmapchan5
- # uint08 resmapchan6
- # uint08 resmapchan7
- # uint08 resmapchan8
- pass
-
- class SMCSURFACE:
- # string name
- # uint32 references
- # SMCREFERENCE reflist[]
- # uint16 surfmat
- pass
-
- class SMCSURFREF:
- # uint32 vb_index
- # uint32 vb_start
- # uint32 vb_width
- # uint32 ib_index
- # uint32 ib_start
- # uint32 ib_width
- # uint32 jm_index
- pass
-
- class SMCJOINT:
- # string name
- # uint32 id
- # uint32 parent
- # real32 matrix[16]
- # real32 quaternion[4]
- # real32 position[4]
- pass
-
- class SMCJOINTNODE:
- # Blender.Mathutils.Vector p_world
- # Blender.Mathutils.Matrix m_world
- pass
-
- class SMCSKELETON:
- # uint16 format
- # real32 tiplen (optional)
- # string name
- # uint32 n_joints
- # SMCJOINT joints[]
- pass
-
- #
- # JOINT TRAVERSAL CLASS
- #
- class SMCJointVisitor:
-
- # dictionary self.jntmap[joint_id] -> [jnt_index, [list of children joint ids]];
- # SMCSKELETON self.skeleton;
- # SMCJOINT self.joints[];
- # Blender.Armature self.armature;
-
- DEFAULT_JOINT_LENGTH = 0.1
-
- # CONSTRUCTOR
- def __init__(self, jntmap, skeleton, armature):
- """
-
- """
-
- self.jntmap = jntmap
- self.joints = skeleton.joints
- self.secmap = {}
- self.skeleton = skeleton
- self.armature = armature
-
- # PUBLIC METHOD: VISIT
- def visit(self, jntid, parentBone):
- """
- Visits a joint node and recursively visits child joints.
- node -> The uint32 identifier of the node to visit.
- """
-
- # joint must be present
- if not(jntid in self.jntmap):
- raise Exception('SMC Import Error: Joint identifier not found.')
-
- # tree must not be cyclic and joints cannot have multiple parents
- # each one of these conditions would cause us to process the same
- # joint more than once during depth first search
- if jntid in self.secmap:
- raise Exception('SMC Import Error: Invalid joint tree.')
-
- #
- nodedata = self.jntmap[jntid]
- jntindex = nodedata[0]
- children = nodedata[1]
-
- # if parent joint exists
- jntdata = self.joints[jntindex]
- jntnode = SMCJOINTNODE()
- if jntdata.parent != SMC.INVALID_JOINT:
-
- # secondary parent data must exist
- parent_id = jntdata.parent
- if not(parent_id in self.secmap):
- raise Exception('SMC Import Error: Invalid joint tree; secondary parent data is missing.')
-
- # get parent data
- pardata = self.joints[self.jntmap[parent_id][0]]
- parnode = self.secmap[parent_id]
-
- # get matrix (child)
- matrix = Array4x4ToBlenderMatrix(jntdata.matrix)
- matrix[0][3] = jntdata.position[0]
- matrix[1][3] = jntdata.position[1]
- matrix[2][3] = jntdata.position[2]
-
- # compute joint position in world coordinates
- if self.skeleton.format & SMC.JOINT_FORMAT_ABSOLUTE:
- jntnode.m_world = matrix
- else:
- jntnode.m_world = parnode.m_world * matrix
-
- # joint coordinate system
- x = [matrix[0][0], matrix[0][1], matrix[0][2]]
- y = [matrix[1][0], matrix[1][1], matrix[1][2]]
- z = [matrix[2][0], matrix[2][1], matrix[2][2]]
- joint_X_axis = Blender.Mathutils.Vector(NormalizeVector(x))
- joint_Y_axis = Blender.Mathutils.Vector(NormalizeVector(y))
- joint_Z_axis = Blender.Mathutils.Vector(NormalizeVector(z))
-
- # joint position
- jntnode.p_world = Blender.Mathutils.Vector([0.0, 0.0, 0.0])
- jntnode.p_world[0] = jntnode.m_world[0][3]
- jntnode.p_world[1] = jntnode.m_world[1][3]
- jntnode.p_world[2] = jntnode.m_world[2][3]
-
- # create blender bone
- bone = Blender.Armature.Editbone()
- bone.head = jntnode.p_world
- bone.tail = jntnode.p_world + SMCJointVisitor.DEFAULT_JOINT_LENGTH*joint_X_axis
- bone.roll = 0
- if parentBone != None: bone.parent = parentBone
-
- # assign bone to armature
- bonename = jntdata.name
- self.armature.bones[bonename] = bone
-
- # insert joint into secondary map
- self.secmap[jntid] = jntnode
-
- # recursively visit children
- for child in children:
- self.visit(child, bone)
-
- # parent joint does not exists
- else:
-
- # get joint matrix
- matrix = Array4x4ToBlenderMatrix(jntdata.matrix)
- matrix[0][3] = jntdata.position[0]
- matrix[1][3] = jntdata.position[1]
- matrix[2][3] = jntdata.position[2]
- matrix[3][3] = 1.0
-
- # set joint's orientation in world space
- jntnode.m_world = matrix
-
- # set joint's position in world space
- jntnode.p_world = Blender.Mathutils.Vector([0.0, 0.0, 0.0])
- jntnode.p_world[0] = jntdata.position[0]
- jntnode.p_world[1] = jntdata.position[1]
- jntnode.p_world[2] = jntdata.position[2]
-
- # get joint coordinate system
- x = [matrix[0][0], matrix[0][1], matrix[0][2]]
- y = [matrix[1][0], matrix[1][1], matrix[1][2]]
- z = [matrix[2][0], matrix[2][1], matrix[2][2]]
- joint_X_axis = Blender.Mathutils.Vector(NormalizeVector(x))
- joint_Y_axis = Blender.Mathutils.Vector(NormalizeVector(y))
- joint_Z_axis = Blender.Mathutils.Vector(NormalizeVector(z))
-
- # create blender bone
- bone = Blender.Armature.Editbone()
- bone.head = jntnode.p_world
- bone.tail = jntnode.p_world + SMCJointVisitor.DEFAULT_JOINT_LENGTH*joint_X_axis
- bone.roll = 0
-
- # assign bone to armature
- bonename = jntdata.name
- self.armature.bones[bonename] = bone
-
- # insert joint into secondary map
- self.secmap[jntid] = jntnode
-
- # recursively visit children
- for child in children:
- self.visit(child, bone)
-
- #
- # IMPORT SMC CLASS
- #
-
- class SMC:
-
- # CONSTANTS (VERTEX BUFFER FLAGS)
- VERTEX_POSITION = 0x01
- VERTEX_NORMAL = 0x02
- VERTEX_TANGENT = 0x04
- VERTEX_BINORMAL = 0x08
- VERTEX_WEIGHTS = 0x10
- VERTEX_UV = 0x20
- VERTEX_COLORS = 0x40
- VERTEX_SKELETON = 0x80
-
- # CONSTANTS (INDEX BUFFER INDEX FORMAT)
- UINT08 = 0x00
- UINT16 = 0x01
- UINT32 = 0x02
-
- # CONSTANTS (INDEX BUFFER PRIMITIVE TYPE)
- TRIANGLES = 0x00
- TRISTRIP = 0x01
- TRISTRIPCUT = 0x02
-
- # CONSTANTS (INDEX BUFFER WINDING ORDER)
- CW = 0x00
- CCW = 0x01
-
- # CONSTANTS (INVALID VALUES)
- INVALID_SURFMAT = 0xFFFF
- INVALID_TEXTURE = 0xFFFF
- INVALID_BLENDINDEX = 0xFFFF
- INVALID_JOINT = 0xFFFFFFFF
- INVALID_INDEX = 0xFFFFFFFF
- INVALID_JMAP_INDEX = 0xFFFFFFFF
-
- # CONSTANTS (TEXTURE MAPS)
- DIFFUSE_MAP = 0x0001
- SPECULAR_MAP = 0x0002
- BUMP_MAP = 0x0004
- NORMAL_MAP = 0x0008
- ALPHA_MAP = 0x0010
- LIGHT_MAP = 0x0020
- GLOSS_MAP = 0x0040
- ENVIRONMENT_MAP = 0x0080
- INVALID_MAP = 0x8000
-
- # CONSTANTS (SKELETONS)
- JOINT_FORMAT_ABSOLUTE = 0x0001
- JOINT_FORMAT_RELATIVE = 0x0002
- JOINT_FORMAT_MATRIX = 0x0004
- JOINT_FORMAT_QUATERNION = 0x0008
- JOINT_FORMAT_TIP_LENGTH = 0x0010
- JOINT_FORMAT_X_BONEAXIS = 0x0020
- JOINT_FORMAT_Y_BONEAXIS = 0x0040
- JOINT_FORMAT_Z_BONEAXIS = 0x0080
-
- class SMCImporter:
-
- # CONSTRUCTOR
- def __init__(self):
-
- self.flip_U = False
- self.flip_V = True
-
- # PRIVATE METHOD:
- def __readString(self, defaultValue):
-
- # validate length of default value
- if len(defaultValue) == 0:
- raise Exception('SMC Import Error: Default string values cannot be null.')
-
- # read length
- namelen = self.ifile.LE_read_uint32()
- if namelen == 0: return defaultValue
-
- # excessively long string
- if namelen > 0xFF:
- raise Exception('SMC Import Error: The maximum length for all names is 255 characters.')
-
- # read string
- name = self.ifile.read_string(namelen)
- if len(name) < 1: raise Exception('SMC Import Error: String values cannot be null.')
-
- # return string
- return name
-
- # PRIVATE METHOD:
- def __processSMCHeader(self):
-
- # read magic number
- self.header = SMCHEADER()
- self.header.magic = self.ifile.LE_read_uint32()
- if self.header.magic != 0x20434D53: raise Exception('SMC Import Error: Invalid SMC file.')
-
- # read version
- self.header.major_version = self.ifile.LE_read_uint16()
- self.header.minor_version = self.ifile.LE_read_uint16()
- if self.header.major_version != 0x01:
- raise Exception('SMC Import Error: Script is meant for SMC files of versions 1.0 and lower.')
- if self.header.minor_version != 0x00:
- raise Exception('SMC Import Error: Script is meant for SMC files of versions 1.0 and lower.')
-
- # read number of buffers
- self.header.n_vbuffers = self.ifile.LE_read_uint32()
- self.header.n_ibuffers = self.ifile.LE_read_uint32()
-
- # read number of images
- self.header.n_images = self.ifile.LE_read_uint32()
-
- # read number of surfaces and materials
- self.header.n_surfaces = self.ifile.LE_read_uint32()
- self.header.n_surfmats = self.ifile.LE_read_uint32()
-
- # read number of skeletons
- self.header.n_skeletons = self.ifile.LE_read_uint32()
- if (self.header.n_skeletons != 0 and self.header.n_skeletons != 1):
- raise Exception('SMC Import Error: Invalid number of skeletons; this value must be 0 or 1.')
-
- # read number of joint maps
- self.header.n_jointmaps = self.ifile.LE_read_uint32()
-
- # read number of animations
- self.header.n_animations = self.ifile.LE_read_uint32()
- if self.header.n_animations != 0:
- raise Exception('SMC Import Error: Animations are not yet supported.')
-
- # read reserved values
- self.header.reserved1 = self.ifile.LE_read_uint32()
- self.header.reserved2 = self.ifile.LE_read_uint32()
- self.header.reserved3 = self.ifile.LE_read_uint32()
- self.header.reserved4 = self.ifile.LE_read_uint32()
- self.header.reserved5 = self.ifile.LE_read_uint32()
- self.header.reserved6 = self.ifile.LE_read_uint32()
-
- return True
-
- # PRIVATE METHOD:
- def __processFileList(self):
-
- # construct filelist
- self.images = []
- for i in range(self.header.n_images):
- namelen = self.ifile.LE_read_uint32()
- if namelen < 0x001: raise Exception('SMC Import Error: Invalid filename.')
- if namelen > 0x400: raise Exception('SMC Import Error: Invalid filename.')
- namedat = self.ifile.read_string(namelen)
- self.images.append(namedat)
-
- return True
-
- # PRIVATE METHOD:
- def __processVBuffers(self):
-
- # initialize vertex buffer list
- self.vblist = []
-
- # for each vertex buffer
- for i in range(self.header.n_vbuffers):
-
- # read vertex buffer flags
- vb = SMCVTXBUFFER()
- vb.flags = self.ifile.LE_read_uint32()
-
- # read vertex buffer name
- len = self.ifile.LE_read_uint32()
- if (len < 0x01) or (len > 0xFF): raise Exception('SMC Import Error: Invalid vertex buffer name.')
- vb.name = self.ifile.read_string(len)
-
- # read number and type of texture channels
- vb.uvchan = self.ifile.LE_read_uint16()
- if vb.uvchan > 8: raise Exception('SMC Import Error: Invalid number of UV channels.')
- vb.uvtype = self.ifile.LE_read_uint16_array(8)
-
- # read number of color channels
- vb.colors = self.ifile.LE_read_uint16()
- if vb.colors > 8: raise Exception('SMC Import Error: Invalid number of color channels.')
-
- # read number of vertices
- vb.elem = self.ifile.LE_read_uint32()
- if vb.elem == 0: raise Exception('SMC Import Error: Vertex buffers must have at least one vertex.')
-
- # initialize vertex data
- vb.positions = []
- vb.normals = []
- vb.tangents = []
- vb.binormals = []
- vb.blendweights = []
- vb.blendindices = []
- vb.texcoords = [[], [], [], [], [], [], [], []]
- vb.vtxcolors = [[], [], [], [], [], [], [], []]
-
- # read vertices
- vb.data = []
- for j in range(vb.elem):
-
- # read position
- if (vb.flags & SMC.VERTEX_POSITION):
- vb.positions.append(self.ifile.LE_read_real32_array(3))
-
- # read normal
- if (vb.flags & SMC.VERTEX_NORMAL):
- vb.normals.append(self.ifile.LE_read_real32_array(3))
-
- # read tangent
- if (vb.flags & SMC.VERTEX_TANGENT):
- vb.tangents.append(self.ifile.LE_read_real32_array(3))
-
- # read binormal
- if (vb.flags & SMC.VERTEX_BINORMAL):
- vb.binormals.append(self.ifile.LE_read_real32_array(3))
-
- # read blend weights
- if (vb.flags & SMC.VERTEX_WEIGHTS):
- vb.blendweights.append(self.ifile.LE_read_real32_array(8))
- vb.blendindices.append(self.ifile.LE_read_uint16_array(8))
-
- # read texture coordinates
- if (vb.flags & SMC.VERTEX_UV):
- for k in range(vb.uvchan):
- tmp = self.ifile.LE_read_real32_array(2)
- if self.flip_U: tmp[0] = 1.0 - tmp[0]
- if self.flip_V: tmp[1] = 1.0 - tmp[1]
- vb.texcoords[k].append(tmp)
-
- # read vertex colors
- if vb.colors > 0:
- for k in range(vb.colors):
- tmp = self.ifile.LE_read_real32_array(4)
- vb.vtxcolors[k].append(tmp)
-
- # append vertex buffer
- self.vblist.append(vb)
-
- return True
-
- # PRIVATE METHOD:
- def __processIBuffers(self):
-
- # initialize index buffer list
- self.iblist = []
-
- # for each index buffer
- for i in range(self.header.n_ibuffers):
-
- # read index buffer format
- ib = SMCIDXBUFFER()
- ib.format = self.ifile.LE_read_uint08()
- if (ib.format < SMC.UINT08) or (ib.format > SMC.UINT32):
- raise Exception('SMC Import Error: Invalid index buffer format.')
-
- # read index buffer primitive type
- ib.primitive = self.ifile.LE_read_uint08()
- if (ib.primitive < SMC.TRIANGLES) or (ib.primitive > SMC.TRISTRIPCUT):
- raise Exception('SMC Import Error: Invalid index buffer primitive type.')
-
- # read winding order
- ib.direction = self.ifile.LE_read_uint08()
- if (ib.direction != SMC.CW) and (ib.direction != SMC.CCW):
- ss = 'SMC Import Error: Invalid winding order ' + str(ib.direction) + ' at ' + str(self.ifile.tell()) + '.'
- raise Exception(ss)
-
- # read reserved byte
- ib.reserved = self.ifile.LE_read_uint08()
- if ib.reserved != 0: ib.reserved = 0
-
- # read index buffer name
- len = self.ifile.LE_read_uint32()
- if (len < 0x01) or (len > 0xFF): raise Exception('SMC Import Error: Invalid index buffer name.')
- ib.name = self.ifile.read_string(len)
-
- # read number of indices
- ib.elem = self.ifile.LE_read_uint32()
- ib.data = []
-
- # read indices
- if ib.elem > 0:
- if ib.format == SMC.UINT08:
- ib.data = self.ifile.LE_read_uint08_array(ib.elem)
- elif ib.format == SMC.UINT16:
- ib.data = self.ifile.LE_read_uint16_array(ib.elem)
- elif ib.format == SMC.UINT32:
- ib.data = self.ifile.LE_read_uint32_array(ib.elem)
-
- # read extra byte for odd number of AMC_UINT08 indices
- if (ib.format == SMC.UINT08) and (ib.elem % 2 == 1):
- self.ifile.skip(1)
-
- # append index buffer
- self.iblist.append(ib)
-
- return True
-
- # PRIVATE METHOD:
- def __processSurfmats(self):
-
- # initialize material list
- self.surfmats = []
-
- # for each material
- for i in range(self.header.n_surfmats):
-
- # read material name
- sm = SMCSURFMAT()
- len = self.ifile.LE_read_uint32()
- if (len < 0x01) or (len > 0xFF): raise Exception('SMC Import Error: Invalid material name.')
- sm.name = self.ifile.read_string(len)
-
- # read material properties
- sm.twoside = self.ifile.LE_read_uint08()
- sm.unused1 = self.ifile.LE_read_uint08()
- sm.unused2 = self.ifile.LE_read_uint08()
- sm.unused3 = self.ifile.LE_read_uint08()
-
- # read texture references
- sm.basemap = self.ifile.LE_read_uint16()
- sm.specmap = self.ifile.LE_read_uint16()
- sm.tranmap = self.ifile.LE_read_uint16()
- sm.bumpmap = self.ifile.LE_read_uint16()
- sm.normmap = self.ifile.LE_read_uint16()
- sm.lgthmap = self.ifile.LE_read_uint16()
- sm.envimap = self.ifile.LE_read_uint16()
- sm.glssmap = self.ifile.LE_read_uint16()
- sm.resmap1 = self.ifile.LE_read_uint16()
- sm.resmap2 = self.ifile.LE_read_uint16()
- sm.resmap3 = self.ifile.LE_read_uint16()
- sm.resmap4 = self.ifile.LE_read_uint16()
- sm.resmap5 = self.ifile.LE_read_uint16()
- sm.resmap6 = self.ifile.LE_read_uint16()
- sm.resmap7 = self.ifile.LE_read_uint16()
- sm.resmap8 = self.ifile.LE_read_uint16()
-
- # read texture channel references
- sm.basemapchan = self.ifile.LE_read_uint08()
- sm.specmapchan = self.ifile.LE_read_uint08()
- sm.tranmapchan = self.ifile.LE_read_uint08()
- sm.bumpmapchan = self.ifile.LE_read_uint08()
- sm.normmapchan = self.ifile.LE_read_uint08()
- sm.lghtmapchan = self.ifile.LE_read_uint08()
- sm.envimapchan = self.ifile.LE_read_uint08()
- sm.glssmapchan = self.ifile.LE_read_uint08()
- sm.resmapchan1 = self.ifile.LE_read_uint08()
- sm.resmapchan2 = self.ifile.LE_read_uint08()
- sm.resmapchan3 = self.ifile.LE_read_uint08()
- sm.resmapchan4 = self.ifile.LE_read_uint08()
- sm.resmapchan5 = self.ifile.LE_read_uint08()
- sm.resmapchan6 = self.ifile.LE_read_uint08()
- sm.resmapchan7 = self.ifile.LE_read_uint08()
- sm.resmapchan8 = self.ifile.LE_read_uint08()
-
- # append material
- self.surfmats.append(sm)
-
- return True
-
- # PRIVATE METHOD:
- def __processSurfaces(self):
-
- # initialize surface list
- self.surfaces = []
-
- # for each surface
- for i in range(self.header.n_surfaces):
-
- # read surface name
- surf = SMCSURFACE()
- tmp = self.ifile.LE_read_uint32()
- if (tmp < 0x01) or (tmp > 0xFF): raise Exception('SMC Import Error: Invalid surface name.')
- surf.name = self.ifile.read_string(tmp)
- if len(surf.name) < 1: raise Exception('SMC Import Error: Invalid surface name.')
-
- # read number of buffer references
- surf.references = self.ifile.LE_read_uint32()
- if surf.references < 1: raise Exception('SMC Import Error: A surface must have at least one buffer reference.')
-
- # read references
- surf.reflist = []
- for j in range(surf.references):
-
- # read vertex buffer index
- ref = SMCSURFREF()
- ref.vb_index = self.ifile.LE_read_uint32()
- if ref.vb_index < 0:
- raise Exception('SMC Import Error: Invalid vertex buffer reference.')
- if not(ref.vb_index < self.header.n_vbuffers):
- raise Exception('SMC Import Error: Invalid vertex buffer reference.')
-
- # read vertex buffer start index
- ref.vb_start = self.ifile.LE_read_uint32()
- if ref.vb_start < 0:
- raise Exception('SMC Import Error: Invalid vertex buffer start index.')
- if not(ref.vb_start < self.vblist[ref.vb_index].elem):
- raise Exception('SMC Import Error: Invalid vertex buffer start index.')
-
- # read vertex buffer width
- ref.vb_width = self.ifile.LE_read_uint32()
- if ref.vb_width < 1:
- raise Exception('SMC Import Error: Invalid vertex buffer surface width.')
- if self.vblist[ref.vb_index].elem < ref.vb_width:
- raise Exception('SMC Import Error: Invalid vertex buffer surface width.')
- if self.vblist[ref.vb_index].elem < (ref.vb_start + ref.vb_width):
- raise Exception('SMC Import Error: Invalid vertex buffer surface width.')
-
- # read index buffer index, start index, and width
- ref.ib_index = self.ifile.LE_read_uint32()
- ref.ib_start = self.ifile.LE_read_uint32()
- ref.ib_width = self.ifile.LE_read_uint32()
-
- # read joint map index (0xFFFFFFFF if not using a joint map)
- ref.jm_index = self.ifile.LE_read_uint32()
-
- # validate
- # note that if the index is invalid, this surface only contains points!
- if ref.ib_index != SMC.INVALID_INDEX:
-
- # validate index buffer index
- if ref.ib_index < 0:
- raise Exception('SMC Import Error: Invalid index buffer reference.')
- if not(ref.ib_index < self.header.n_ibuffers):
- raise Exception('SMC Import Error: Invalid index buffer reference.')
-
- # validate index buffer start index
- if ref.ib_start < 0:
- raise Exception('SMC Import Error: Invalid index buffer start index.')
- if not(ref.ib_start < self.iblist[ref.ib_index].elem):
- raise Exception('SMC Import Error: Invalid index buffer start index.')
-
- # validate index buffer width
- if ref.ib_width < 1:
- raise Exception('SMC Import Error: Invalid index buffer surface width.')
- if self.iblist[ref.ib_index].elem < ref.ib_width:
- raise Exception('SMC Import Error: Invalid index buffer surface width.')
- if self.iblist[ref.ib_index].elem < (ref.ib_start + ref.ib_width):
- raise Exception('SMC Import Error: Invalid index buffer surface width.')
-
- # append reference
- surf.reflist.append(ref)
-
- # read surface material
- surf.surfmat = self.ifile.LE_read_uint16()
- if surf.surfmat != SMC.INVALID_SURFMAT:
- if surf.surfmat < 0: raise Exception('SMC Import Error: Invalid material reference.')
- if not(surf.surfmat < self.header.n_surfmats): raise Exception('SMC Import Error: Invalid material reference.')
-
- # append surface
- self.surfaces.append(surf)
-
- return True
-
- # PRIVATE METHOD:
- def __processSkeleton(self):
-
- # initialize surface list
- self.skeletons = []
-
- # for each skeleton
- for i in range(self.header.n_skeletons):
-
- # read format
- skel = SMCSKELETON()
- skel.format = self.ifile.LE_read_uint16()
-
- # validate format
- if skel.format & SMC.JOINT_FORMAT_ABSOLUTE:
- if skel.format & SMC.JOINT_FORMAT_RELATIVE:
- raise Exception('SMC Import Error: Skeletons cannot be absolute and relative.')
- elif skel.format & SMC.JOINT_FORMAT_RELATIVE:
- if skel.format & SMC.JOINT_FORMAT_ABSOLUTE:
- raise Exception('SMC Import Error: Skeletons cannot be absolute and relative.')
- else:
- raise Exception('SMC Import Error: Skeletons must be absolute or relative.')
-
- # validate format
- if skel.format & SMC.JOINT_FORMAT_MATRIX:
- if skel.format & SMC.JOINT_FORMAT_QUATERNION:
- raise Exception('SMC Import Error: Skeletons cannot use matrices and quaternions.')
- elif skel.format & SMC.JOINT_FORMAT_QUATERNION:
- if skel.format & SMC.JOINT_FORMAT_MATRIX:
- raise Exception('SMC Import Error: Skeletons cannot use matrices and quaternions.')
- else:
- raise Exception('SMC Import Error: Skeletons must use matrices or quaternions.')
-
- # validate format
- if skel.format & SMC.JOINT_FORMAT_X_BONEAXIS:
- if (skel.format & SMC.JOINT_FORMAT_Y_BONEAXIS) or (skel.format & SMC.JOINT_FORMAT_Z_BONEAXIS):
- raise Exception('SMC Import Error: Skeletons cannot use more than one bone axis.')
- elif skel.format & SMC.JOINT_FORMAT_Y_BONEAXIS:
- if (skel.format & SMC.JOINT_FORMAT_X_BONEAXIS) or (skel.format & SMC.JOINT_FORMAT_Z_BONEAXIS):
- raise Exception('SMC Import Error: Skeletons cannot use more than one bone axis.')
- elif skel.format & SMC.JOINT_FORMAT_Z_BONEAXIS:
- if (skel.format & SMC.JOINT_FORMAT_X_BONEAXIS) or (skel.format & SMC.JOINT_FORMAT_Y_BONEAXIS):
- raise Exception('SMC Import Error: Skeletons cannot use more than one bone axis.')
- else:
- raise Exception('SMC Import Error: Skeletons must define a bone axis.')
-
- # read tip length
- if skel.format & SMC.JOINT_FORMAT_TIP_LENGTH:
- skel.tiplen = self.ifile.LE_read_real32()
- if skel.tiplen < 0.0:
- raise Exception('SMC Import Error: Skeleton tip lengths must be positive.')
- elif skel.tiplen > 1024.0:
- raise Exception('SMC Import Error: Skeleton tip lengths must be shorter than 1024.')
-
- # read name
- skel.name = self.__readString('default')
-
- # read joints
- skel.n_joints = self.ifile.LE_read_uint32()
- skel.joints = []
- for j in range(skel.n_joints):
-
- # read name
- jnt = SMCJOINT()
- defaultValue = 'jnt_' + str(j)
- jnt.name = self.__readString(defaultValue)
-
- # read id
- jnt.id = self.ifile.LE_read_uint32()
- if jnt.id == SMC.INVALID_JOINT:
- raise Exception('SMC Import Error: Invalid joint identifier.')
-
- # read parent
- jnt.parent = self.ifile.LE_read_uint32()
-
- # read matrix or quaternion
- if skel.format & SMC.JOINT_FORMAT_MATRIX:
- jnt.matrix = self.ifile.LE_read_real32_array(16)
- elif skel.format & SMC.JOINT_FORMAT_QUATERNION:
- jnt.quaternion = self.ifile.LE_read_real32_array(4)
-
- # read position
- jnt.position = self.ifile.LE_read_real32_array(4)
-
- # insert joint
- skel.joints.append(jnt)
-
- # insert skeleton
- self.skeletons.append(skel)
-
- return True
-
- # PRIVATE METHOD:
- def __processJointMap(self):
-
- # initialize surface list
- self.jntmaplist = []
-
- # for each joint map
- for i in range(self.header.n_jointmaps):
- n_items = self.ifile.LE_read_uint32()
- items = []
- for j in range(n_items):
- temp = self.ifile.LE_read_uint32()
- items.append(temp)
- self.jntmaplist.append(items)
-
- # PRIVATE METHOD:
- def __processAnimList(self):
-
- return True
-
- # PRIVATE METHOD:
- def __buildVBuffer(self, surf):
-
- # for each reference
- for index, ref in enumerate(surf.reflist):
-
- # create name for mesh object
- meshname = surf.name
- meshname += '_ref_'
- meshname += str(index)
-
- # create Blender mesh for this vertex buffer
- mesh = Blender.Mesh.New()
- mesh.name = meshname
-
- # vertex and index buffers
- vb = self.vblist[ref.vb_index]
- ib = self.iblist[ref.ib_index]
-
- # positions
- verts = []
- for dst_index in range(ref.vb_width):
- src_index = ref.vb_start + dst_index
- verts.append(vb.positions[src_index])
- mesh.verts.extend(verts)
-
- # normals
- if vb.flags & SMC.VERTEX_NORMAL:
- for vertex in mesh.verts:
- nx = vb.normals[ref.vb_start + vertex.index][0]
- ny = vb.normals[ref.vb_start + vertex.index][1]
- nz = vb.normals[ref.vb_start + vertex.index][2]
- vertex.no = Blender.Mathutils.Vector(nx, ny, nz)
-
- # texture coordinates
- uvmap = [[], [], [], [], [], [], [], []]
- if vb.flags & SMC.VERTEX_UV:
-
- # for each UV channel
- for i in range(vb.uvchan):
-
- # copy UVs if UV map channel exists
- if vb.uvtype[i] != SMC.INVALID_MAP:
-
- # copy UVs
- for dst_index in range(ref.vb_width):
- src_index = ref.vb_start + dst_index
- uvmap[i].append(vb.texcoords[i][src_index])
-
- # faces
- faces = []
- if ref.ib_index != SMC.INVALID_INDEX:
-
- # from triangle list
- if ib.primitive == SMC.TRIANGLES:
-
- # must have triangles
- if ref.ib_width < 3:
- raise Exception('SMC Import Error: The number of triangle indices must be greater than three.')
- if ref.ib_width % 3:
- raise Exception('SMC Import Error: The number of triangle indices must be divisible by three.')
-
- # build triangles
- for i in range((ref.ib_width / 3)):
-
- # triangle indices
- src_index = ref.ib_start + i * 3
- a = ib.data[src_index + 0]
- b = ib.data[src_index + 1]
- c = ib.data[src_index + 2]
- if not(a < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
- if not(b < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
- if not(c < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
-
- # insert triangle
- if (a != b) and (a != c) and (b != c):
- if ib.direction == SMC.CW:
- faces.append([a, b, c])
- else:
- faces.append([a, c, b])
-
- elif ib.primitive == SMC.TRISTRIP:
-
- # first triangle
- a = ib.data[ref.ib_start + 0]
- b = ib.data[ref.ib_start + 1]
- c = ib.data[ref.ib_start + 2]
- if not(a < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
- if not(b < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
- if not(c < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
-
- # insert first triangle
- if (a != b) and (a != c) and (b != c):
- if ib.direction == SMC.CW:
- faces.append([a, b, c])
- else:
- faces.append([a, c, b])
-
- # reamaining triangles
- for i in range(3, ref.ib_width):
-
- # triangle indices
- a = b
- b = c
- c = ib.data[ref.ib_start + i]
- if not(c < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
-
- # insert triangle
- if (a != b) and (a != c) and (b != c):
- if i % 2:
- if ib.direction == SMC.CW:
- faces.append([a, c, b])
- else:
- faces.append([a, b, c])
- else:
- if ib.direction == SMC.CW:
- faces.append([a, b, c])
- else:
- faces.append([a, c, b])
-
- elif ib.primitive == SMC.TRISTRIPCUT:
-
- # maintain a tristrip index
- tristrip_data = []
- tristrip_curr = []
-
- # value of restart index depends on the data type
- strip_index = 0xFFFFFFFF
- if ib.format == SMC.UINT08:
- strip_index = 0xFF
- elif ib.format == SMC.UINT16:
- strip_index = 0xFFFF
- elif ib.format == SMC.UINT32:
- strip_index = 0xFFFFFFFF
-
- # create a list of triangle strips
- for i in range(ref.ib_width):
-
- temp = ib.data[ref.ib_start + i]
- if temp == strip_index:
- if len(tristrip_curr) < 3: raise Exception('SMC Import Error: Not enough indices for a triangle strip.')
- tristrip_data.append(tristrip_curr)
- tristrip_curr = []
- else:
- tristrip_curr.append(temp)
- if ((i + 1) == ref.ib_width): # last index is not an strip index
- tristrip_data.append(tristrip_curr)
- tristrip_curr = []
-
- # process triangle strips
- for tristrip in tristrip_data:
-
- # first triangle
- a = tristrip[0]
- b = tristrip[1]
- c = tristrip[2]
- if not(a < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
- if not(b < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
- if not(c < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
- if (a != b) and (a != c) and (b != c):
- if ib.direction == SMC.CW: faces.append([a, b, c])
- else: faces.append([a, c, b])
-
- # remaining triangles
- for i in range(3, len(tristrip)):
- a = b
- b = c
- c = tristrip[i]
- if not(c < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
- if (a != b) and (a != c) and (b != c):
- if i % 2:
- if ib.direction == SMC.CW: faces.append([a, c, b])
- else: faces.append([a, b, c])
- else:
- if ib.direction == SMC.CW: faces.append([a, b, c])
- else: faces.append([a, c, b])
-
- # construct blender mesh faces
- mesh.faces.extend(faces)
-
- # smooth vertex normals
- if vb.flags & SMC.VERTEX_NORMAL:
- for face in mesh.faces:
- face.smooth = 1
-
- # assign texture coordinates
- if vb.flags & SMC.VERTEX_UV:
-
- # for each UV channel
- for i in range(8):
-
- # if UV channel exists
- if vb.uvtype[i] != SMC.INVALID_MAP:
-
- # create UV layer
- mapname = 'uvmap_channel_' + str(i)
- mesh.addUVLayer(mapname)
- mesh.activeUVLayer = mapname
-
- # assign texture coordinates to faces
- # WARNING: THIS IS OLD CODE THAT CAUSED ROTATED UV COORDINATES!!!
- #for face in mesh.faces:
- # a = faces[face.index][0]
- # b = faces[face.index][1]
- # c = faces[face.index][2]
- # uv_a = Mathutils.Vector(uvmap[i][a][0], uvmap[i][a][1])
- # uv_b = Mathutils.Vector(uvmap[i][b][0], uvmap[i][b][1])
- # uv_c = Mathutils.Vector(uvmap[i][c][0], uvmap[i][c][1])
- # face.uv = [ uv_a, uv_b, uv_c ]
-
- # set sticky per-vertex UV coordinates
- mesh.vertexUV = True
- for j in range(len(mesh.verts)):
- mesh.verts[j].uvco = Blender.Mathutils.Vector(uvmap[i][j])
- mesh.update()
-
- # set face UV coordinates
- # NOTE: copies UV coordinates from sticky coordinates
- mesh.faceUV = True;
- for face in mesh.faces:
- face.uv = [v.uvco for v in face.verts]
- face.smooth = 1
-
- # update mesh
- mesh.update()
-
- # assign colors
- # NOTE: You do not need to check AMC_VERTEX_COLORS flag to determine if there are
- # vertex colors present.
- if vb.colors > 0:
-
- # enable vertex colors
- mesh.vertexColors = True
-
- # for each color channel
- for i in range(vb.colors):
-
- # create color layer and make active
- mapname = 'color_channel_' + str(i)
- mesh.addColorLayer(mapname)
- mesh.activeColorLayer = mapname
-
- # create an array of colors
- colorarr = [None] * len(mesh.verts)
- for j in range(len(mesh.verts)):
- colorarr[j] = [int(vb.vtxcolors[i][j][0] * 255.0),
- int(vb.vtxcolors[i][j][1] * 255.0),
- int(vb.vtxcolors[i][j][2] * 255.0),
- int(vb.vtxcolors[i][j][3] * 255.0)]
-
- # set face color coordinates
- # NOTE: This is very interesting how it works!
- # http://www.blender.org/documentation/249PythonDoc/Mesh.MFace-class.html#col
- for face in mesh.faces:
- for j, v in enumerate(face):
- face.col[j].r = colorarr[v.index][0]
- face.col[j].g = colorarr[v.index][1]
- face.col[j].b = colorarr[v.index][2]
- face.col[j].a = colorarr[v.index][3]
-
- # update mesh
- mesh.update()
-
- # update Blender mesh object
- mesh.update()
-
- # add mesh to current scene and make mesh active
- scene = Blender.Scene.GetCurrent()
- meshobject = scene.objects.new(mesh, meshname)
- scene.objects.active = meshobject
- self.meshlist.append(meshobject)
-
- # assign material to mesh object
- if surf.surfmat != SMC.INVALID_SURFMAT:
- meshobject.colbits = 1
- meshobject.setMaterials([self.materials[surf.surfmat]])
- mesh.update()
-
- # blend weights
- # NOTE: blend weights must be added after a mesh has been associated with a mesh object!
- bidict = {}
- if vb.flags & SMC.VERTEX_WEIGHTS:
-
- # for each set of blendweights and blendindices
- for dst_index in range(ref.vb_width):
-
- src_index = ref.vb_start + dst_index
- for i in range(8):
-
- # get blend weight and blend index
- bw = vb.blendweights[src_index][i]
- bi = vb.blendindices[src_index][i]
-
- # if blend index is valid
- if bi != SMC.INVALID_BLENDINDEX:
-
- # if this surface reference uses a joint map
- # remap the blend index using the map
- if ref.jm_index != SMC.INVALID_JMAP_INDEX:
-
- if not(ref.jm_index < len(self.jntmaplist)):
- raise Exception('SMC Import Error: Joint map index out of range.')
-
- # given a blend index, look it up in an array to get new blend index
- if not(bi < len(self.jntmaplist[ref.jm_index])):
- error = 'SMC Import Error: Joint map blending index '
- error = error + str(bi)
- error = error + ' out of range. The joint map only has '
- error = error + str(len(self.jntmaplist[ref.jm_index]))
- error = error + ' elements.'
- raise Exception(error)
-
- # remap blend index
- bi = self.jntmaplist[ref.jm_index][bi]
-
- # associate blend weight with blend index
- # 2014-04-11: DO NOT INSERT <BI, <index, BW>> PAIR IF BW = 0
- if not (bi in bidict): bidict[bi] = []
- #bidict[bi].append([dst_index, bw])
- if bw > 0.0: bidict[bi].append([dst_index, bw])
-
- # for each vertex weight map
- for dk, dv in bidict.iteritems():
-
- # create vertex group and assign weights
- mapname = 'jnt_' + ('%(value)03d' % {'value':dk}) # + str(dk)
- mesh.addVertGroup(mapname)
- for item in dv:
- try:
- mesh.assignVertsToGroup(mapname, [item[0]], item[1], Blender.Mesh.AssignModes.ADD)#REPLACE)
- except Exception as e:
- print('item = ' + str(item[0]) + ', ' + str(item[1]))
- print('vertices = ' + str(vb.elem) + ', ' + str(len(mesh.verts)))
- raise e
-
- # PRIVATE METHOD:
- def __buildMeshTextures(self):
-
- # construct textures from filelist using relative directories
- # this is why we preface filename with '//'
- # see http://www.blender.org/documentation/blender_python_api_2_59_0/bpy.path.html
- self.texlist = []
- for index, filename in enumerate(self.images):
- try:
- # create texture name based on index
- name = 'texture_' + str(index)
- # create texture
- temp = Blender.Image.Load('//' + filename)
- texture = Blender.Texture.New(name)
- texture.setImage(temp)
- # append data
- self.texlist.append(texture)
- except Exception as e:
- self.texlist.append(None)
- print('Failed to load texture file ' + filename + '.')
-
- def __buildMeshMaterials(self):
-
- def isTextureValid(textureIndex):
- if textureIndex == SMC.INVALID_TEXTURE: return False
- if not (textureIndex < len(self.texlist)): return False
- if self.texlist[textureIndex] is None: return False
- return True
-
- # for each surface material
- self.materials = []
- for surfmat in self.surfmats:
-
- # create new material
- # set material to shadeless so we can see texture using Blender GLSL Materials
- mat = Blender.Material.New(surfmat.name)
- mat.setMode(Blender.Material.Modes['SHADELESS'])
-
- # each material supports up to ten texture layters
- index = 0
- if isTextureValid(surfmat.basemap):
- mat.setTexture(index, self.texlist[surfmat.basemap], Texture.TexCo.UV, Texture.MapTo.COL)
- mattex = mat.getTextures()
- mattex[index].uvlayer = 'uvmap_channel_' + str(surfmat.basemapchan)
- index = index + 1
- if isTextureValid(surfmat.specmap):
- mat.setTexture(index, self.texlist[surfmat.specmap], Texture.TexCo.UV, Texture.MapTo.SPEC)
- mattex = mat.getTextures()
- mattex[index].uvlayer = 'uvmap_channel_' + str(surfmat.specmapchan)
- index = index + 1
- if isTextureValid(surfmat.normmap):
- mat.setTexture(index, self.texlist[surfmat.normmap], Texture.TexCo.UV, Texture.MapTo.NOR)
- mattex = mat.getTextures()
- mattex[index].uvlayer = 'uvmap_channel_' + str(surfmat.normmapchan)
- index = index + 1
-
- # append material
- self.materials.append(mat)
-
- # PRIVATE METHOD:
- def __buildMeshObjects(self):
-
- # save blender mesh objects
- self.meshlist = []
-
- # for each surface
- for surf in self.surfaces:
-
- self.__buildVBuffer(surf)
-
- return True
-
- def __buildArmatureObjects(self):
-
- # for each skeleton
- for skel in self.skeletons:
-
- # keep track of all root nodes
- root_nodes = []
- for jnt in skel.joints:
- if jnt.parent == SMC.INVALID_JOINT:
- root_nodes.append(jnt.id)
-
- # must have at least one root node
- if len(root_nodes) == 0:
- raise Exception('SMC Import Error: A skeleton was defined with no root node.')
-
- # now that we know we have good root nodes, let's create a diction-
- # ary where given a joint ID we can index its data and find out how
- # many children joint IDs it has
- jntmap = {}
- for (jnt_index, jnt) in enumerate(skel.joints):
-
- # joint identifier must be unique
- if jnt.id in jntmap:
- raise Exception('SMC Import Error: Joint identifiers must be unique.')
-
- # insert joint to map with empty child list
- jntmap[jnt.id] = [jnt_index, []]
-
- # insert joints into their parent's list of children
- for jnt in skel.joints:
- if jnt.parent != SMC.INVALID_JOINT:
- if not(jnt.parent in jntmap): raise Exception('SMC Import Error: Invalid parent joint identifier.')
- jntmap[jnt.parent][1].append(jnt.id)
-
- # create blender armature
- armature = Blender.Armature.New(skel.name)
- armature.drawType = Blender.Armature.STICK
- armature.envelopes = False
- armature.vertexGroups = False
-
- # create blender armature object
- scene = Blender.Scene.GetCurrent()
- armatureObjectName = skel.name + '_object'
- armatureObject = scene.objects.new(armature, armatureObjectName)
-
- # set armature object to use vertex groups (not envelopes)
- for meshobj in self.meshlist:
- mod = meshobj.modifiers.append(Modifier.Types.ARMATURE)
- mod[Blender.Modifier.Settings.OBJECT] = armatureObject
- mod[Blender.Modifier.Settings.ENVELOPES] = False
- mod[Blender.Modifier.Settings.VGROUPS] = True
-
- # make armature editable before adding bones
- armature.makeEditable()
-
- # traverse joints to add bones
- jvisitor = SMCJointVisitor(jntmap, skel, armature)
- for root in root_nodes: jvisitor.visit(root, None)
-
- # update armature
- armature.update()
-
- # parent mesh objects to armature so it can modify the meshes
- armatureObject.makeParent(self.meshlist)
-
- return True
-
- # PUBLIC METHOD: IMPORT
- def run(self, filename):
-
- # open file
- self.ifile = InputFileStream()
- self.ifile.open(filename)
-
- # file processing
- if self.__processSMCHeader() == False: return False
- if self.__processFileList() == False: return False
- if self.__processVBuffers() == False: return False
- if self.__processIBuffers() == False: return False
- if self.__processSurfmats() == False: return False
- if self.__processSurfaces() == False: return False
- if self.__processSkeleton() == False: return False
- if self.__processJointMap() == False: return False
- if self.__processAnimList() == False: return False
-
- # model construction
- self.__buildMeshTextures()
- self.__buildMeshMaterials()
- self.__buildMeshObjects()
- self.__buildArmatureObjects()
-
- # success
- print "SMC import successful."
- Window.RedrawAll()
- return True
-
- #
- # IMPORT SMC
- #
-
- def importSMC(filename):
-
- obj = SMCImporter()
- obj.run(filename)
-
- #
- # CONTROL EXECUTION
- # main() is called if and only if module is not imported
- #
-
- def main():
-
- Blender.Window.FileSelector(importSMC, "Import SMC", '*.smc')
-
- if __name__ == '__main__':
-
- main()