home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 7567 / beta.7z / smcimport.py next >
Encoding:
Python Source  |  2014-04-20  |  47.1 KB  |  1,565 lines

  1. #
  2. # PYTHON IMPORTS
  3. #
  4. import array
  5. import collections
  6. import math
  7. import os
  8. import struct
  9. import sys
  10.  
  11. #
  12. # BLENDER IMPORTS
  13. #
  14. import Blender
  15. from Blender import Image
  16. from Blender import Material
  17. from Blender import Mesh
  18. from Blender import Modifier
  19. from Blender import Mathutils
  20. from Blender.Mathutils import *
  21. from Blender import Texture
  22. from Blender import Types
  23. from Blender import Window
  24. import bpy
  25.  
  26. #
  27. # MATH UTILITIES
  28. #
  29.  
  30. def Array4x4ToBlenderMatrix(data):
  31.  
  32.     r1 = [data[ 0], data[ 1], data[ 2], data[ 3]]
  33.     r2 = [data[ 4], data[ 5], data[ 6], data[ 7]]
  34.     r3 = [data[ 8], data[ 9], data[10], data[11]]
  35.     r4 = [data[12], data[13], data[14], data[15]]
  36.     return Blender.Mathutils.Matrix(r1, r2, r3, r4)
  37.  
  38. def NormalizeVector(data):
  39.  
  40.     norm = math.sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2])
  41.     temp = [data[0]/norm, data[1]/norm, data[2]/norm]
  42.     return temp
  43.         
  44. #
  45. # STRING UTILITIES
  46. #
  47.  
  48. def StripNullsFromStr(str):
  49.     '''
  50.     Strips null characters from a string.
  51.     Notes: Blender does not like strings that contain null characters. This can
  52.     happen when we load strings from binary files that were created using lang-
  53.     uages such as C or C++.
  54.     '''
  55.     # make a copy, removing null characters
  56.     retval = ''
  57.     for c in str:
  58.         if c != '\x00':
  59.             retval += c
  60.     return retval
  61.  
  62. #
  63. # INPUT FILE STREAM
  64. #
  65.  
  66. class InputFileStream:
  67.     '''
  68.     '''
  69.  
  70.     # CONSTRUCTOR
  71.     def __init__(self):
  72.         
  73.         pass
  74.     
  75.     # PUBLIC METHOD: OPEN
  76.     def open(self, filename):
  77.         
  78.         # open file
  79.         try: self.ifile = open(filename, "rb")
  80.         except: raise Exception('SMC Import Error: Failed to open file.')
  81.  
  82.     # PUBLIC METHOD: TELL
  83.     def tell(self):
  84.     
  85.         return self.ifile.tell()
  86.         
  87.     # PUBLIC METHOD: SEEK
  88.     def seek(self, position):
  89.     
  90.         # seek position
  91.         self.ifile.seek(position)
  92.         
  93.     # PUBLIC METHOD: SKIP
  94.     def skip(self, offset):
  95.     
  96.         # seek position
  97.         self.ifile.seek(offset, 1)
  98.  
  99.     # PUBLIC METHOD: READ STRING
  100.     def read_string(self, n):
  101.     
  102.         tmp = array.array('c')
  103.         tmp.fromfile(self.ifile, n)
  104.         ret = ''.join(tmp)
  105.         return StripNullsFromStr(ret)
  106.     
  107.     # PUBLIC METHOD: READ UINT08
  108.     def LE_read_uint08(self):
  109.         
  110.         tmp = self.ifile.read(1)
  111.         if len(tmp) == 1: return struct.unpack('<B', tmp)[0];
  112.         raise EOFError()
  113.  
  114.     # PUBLIC METHOD: READ UINT16
  115.     def LE_read_uint16(self):
  116.         
  117.         tmp = self.ifile.read(2)
  118.         if len(tmp) == 2: return struct.unpack('<H', tmp)[0];
  119.         raise EOFError()
  120.  
  121.     # PUBLIC METHOD: READ UINT32
  122.     def LE_read_uint32(self):
  123.         
  124.         tmp = self.ifile.read(4);
  125.         if len(tmp) == 4: return struct.unpack('<I', tmp)[0];
  126.         raise EOFError()
  127.  
  128.     # PUBLIC METHOD: READ UINT64
  129.     def LE_read_uint64(self):
  130.         
  131.         tmp = self.ifile.read(8);
  132.         if len(tmp) == 8: return struct.unpack('<Q', tmp)[0];
  133.         raise EOFError()
  134.  
  135.     # PUBLIC METHOD: READ UINT08 ARRAY
  136.     def LE_read_uint08_array(self, n):
  137.  
  138.         if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')
  139.         ret = array.array('B')
  140.         ret.fromfile(self.ifile, n)
  141.         return ret;
  142.         
  143.     # PUBLIC METHOD: READ UINT16 ARRAY
  144.     def LE_read_uint16_array(self, n):
  145.  
  146.         if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')
  147.         ret = array.array('H')
  148.         ret.fromfile(self.ifile, n)
  149.         if sys.byteorder == "big": ret.byteswap()
  150.         return ret;
  151.  
  152.     # PUBLIC METHOD: READ UINT32 ARRAY
  153.     def LE_read_uint32_array(self, n):
  154.  
  155.         if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')        
  156.         ret = array.array('I')
  157.         ret.fromfile(self.ifile, n)
  158.         if sys.byteorder == "big": ret.byteswap()
  159.         return ret;
  160.     
  161.     # PUBLIC METHOD: READ UINT64 ARRAY
  162.     def LE_read_uint64_array(self, n):
  163.  
  164.         if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')
  165.         ret = array.array('Q')
  166.         ret.fromfile(self.ifile, n)
  167.         if sys.byteorder == "big": ret.byteswap()
  168.         return ret;
  169.  
  170.     # PUBLIC METHOD: READ REAL32
  171.     def LE_read_real32(self):
  172.         
  173.         tmp = self.ifile.read(4);
  174.         if len(tmp) == 4: return struct.unpack('<f', tmp)[0];
  175.         raise EOFError()
  176.  
  177.     # PUBLIC METHOD: READ REAL64
  178.     def LE_read_real64(self):
  179.         
  180.         tmp = self.ifile.read(8);
  181.         if len(tmp) == 8: return struct.unpack('<d', tmp)[0];
  182.         raise EOFError()
  183.  
  184.     # PUBLIC METHOD: READ REAL32 ARRAY
  185.     def LE_read_real32_array(self, n):
  186.  
  187.         if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')        
  188.         ret = array.array('f')
  189.         ret.fromfile(self.ifile, n)
  190.         if sys.byteorder == "big": ret.byteswap()
  191.         return ret;
  192.     
  193.     # PUBLIC METHOD: READ REAL64 ARRAY
  194.     def LE_read_real64_array(self, n):
  195.         
  196.         if(n == 0): raise Exception('SMC Import Error: Arrays must have at least one item.')
  197.         ret = array.array('d')
  198.         ret.fromfile(self.ifile, n)
  199.         if sys.byteorder == "big": ret.byteswap()
  200.         return ret;
  201.  
  202. #
  203. # STRUCTURES
  204. #
  205.  
  206. class SMCHEADER:
  207.     # uint32 magic
  208.     # uint16 major_version
  209.     # uint16 minor_version
  210.     # uint32 n_vbuffers
  211.     # uint32 n_ibuffers
  212.     # uint32 n_images
  213.     # uint32 n_surfaces
  214.     # uint32 n_surfmats
  215.     # uint32 n_skeletons
  216.     # uint32 n_animations
  217.     # uint32 reserved1
  218.     # uint32 reserved2
  219.     # uint32 reserved3
  220.     # uint32 reserved4
  221.     # uint32 reserved5
  222.     # uint32 reserved6
  223.     # uint32 reserved7
  224.     pass
  225.  
  226. class SMCVTXBUFFER:
  227.     # uint32 flags
  228.     # string name
  229.     # uint16 uvchan
  230.     # uint16 uvtype[i]
  231.     # uint16 colors
  232.     # uint32 elem
  233.     # real32 positions[[]]
  234.     # real32 normals[[]]
  235.     # real32 tangents[[]]
  236.     # real32 binormals[[]]
  237.     # real32 blendweights[[]]
  238.     # uint16 blendindices[[]]
  239.     # real32 texcoords[[]]
  240.     # real32 vtxcolors[[]]
  241.     pass
  242.  
  243. class SMCIDXBUFFER:
  244.     # uint08 format
  245.     # uint08 primitive
  246.     # uint08 direction
  247.     # string name
  248.     # uint32 elem
  249.     # T data[]
  250.     pass
  251.  
  252. class SMCSURFMAT:
  253.     # string name
  254.     # uint08 twoside
  255.     # uint08 unused1
  256.     # uint08 unused2
  257.     # uint08 unused3
  258.     # uint16 basemap
  259.     # uint16 specmap
  260.     # uint16 tranmap
  261.     # uint16 bumpmap
  262.     # uint16 normmap
  263.     # uint16 lgthmap
  264.     # uint16 envimap
  265.     # uint16 glssmap
  266.     # uint16 resmap1
  267.     # uint16 resmap2
  268.     # uint16 resmap3
  269.     # uint16 resmap4
  270.     # uint16 resmap5
  271.     # uint16 resmap6
  272.     # uint16 resmap7
  273.     # uint16 resmap8
  274.     # uint08 basemapchan
  275.     # uint08 specmapchan
  276.     # uint08 tranmapchan
  277.     # uint08 bumpmapchan
  278.     # uint08 normmapchan
  279.     # uint08 lghtmapchan
  280.     # uint08 envimapchan
  281.     # uint08 glssmapchan
  282.     # uint08 resmapchan1
  283.     # uint08 resmapchan2
  284.     # uint08 resmapchan3
  285.     # uint08 resmapchan4
  286.     # uint08 resmapchan5
  287.     # uint08 resmapchan6
  288.     # uint08 resmapchan7
  289.     # uint08 resmapchan8
  290.     pass
  291.  
  292. class SMCSURFACE:
  293.     # string name
  294.     # uint32 references
  295.     # SMCREFERENCE reflist[]
  296.     # uint16 surfmat
  297.     pass
  298.  
  299. class SMCSURFREF:
  300.     # uint32 vb_index
  301.     # uint32 vb_start
  302.     # uint32 vb_width
  303.     # uint32 ib_index
  304.     # uint32 ib_start
  305.     # uint32 ib_width
  306.     # uint32 jm_index
  307.     pass
  308.  
  309. class SMCJOINT:
  310.     # string name
  311.     # uint32 id
  312.     # uint32 parent
  313.     # real32 matrix[16]
  314.     # real32 quaternion[4]
  315.     # real32 position[4]
  316.     pass
  317.  
  318. class SMCJOINTNODE:
  319.     # Blender.Mathutils.Vector p_world
  320.     # Blender.Mathutils.Matrix m_world
  321.     pass
  322.  
  323. class SMCSKELETON:
  324.     # uint16 format
  325.     # real32 tiplen (optional)
  326.     # string name
  327.     # uint32 n_joints
  328.     # SMCJOINT joints[]
  329.     pass
  330.  
  331. #
  332. # JOINT TRAVERSAL CLASS
  333. #
  334. class SMCJointVisitor:
  335.  
  336.     # dictionary self.jntmap[joint_id] -> [jnt_index, [list of children joint ids]];
  337.     # SMCSKELETON self.skeleton;
  338.     # SMCJOINT self.joints[];
  339.     # Blender.Armature self.armature;
  340.  
  341.     DEFAULT_JOINT_LENGTH = 0.1
  342.     
  343.     # CONSTRUCTOR
  344.     def __init__(self, jntmap, skeleton, armature):
  345.         """
  346.         
  347.         """
  348.         
  349.         self.jntmap = jntmap
  350.         self.joints = skeleton.joints
  351.         self.secmap = {}
  352.         self.skeleton = skeleton
  353.         self.armature = armature
  354.     
  355.     # PUBLIC METHOD: VISIT
  356.     def visit(self, jntid, parentBone):
  357.         """
  358.         Visits a joint node and recursively visits child joints.
  359.         node -> The uint32 identifier of the node to visit.
  360.         """
  361.         
  362.         # joint must be present
  363.         if not(jntid in self.jntmap):
  364.             raise Exception('SMC Import Error: Joint identifier not found.')
  365.         
  366.         # tree must not be cyclic and joints cannot have multiple parents
  367.         # each one of these conditions would cause us to process the same
  368.         # joint more than once during depth first search
  369.         if jntid in self.secmap:
  370.             raise Exception('SMC Import Error: Invalid joint tree.')
  371.         
  372.         #
  373.         nodedata = self.jntmap[jntid]
  374.         jntindex = nodedata[0]
  375.         children = nodedata[1]
  376.  
  377.         # if parent joint exists
  378.         jntdata = self.joints[jntindex]
  379.         jntnode = SMCJOINTNODE()
  380.         if jntdata.parent != SMC.INVALID_JOINT:
  381.  
  382.             # secondary parent data must exist
  383.             parent_id = jntdata.parent
  384.             if not(parent_id in self.secmap):
  385.                 raise Exception('SMC Import Error: Invalid joint tree; secondary parent data is missing.')
  386.  
  387.             # get parent data
  388.             pardata = self.joints[self.jntmap[parent_id][0]]
  389.             parnode = self.secmap[parent_id]
  390.  
  391.             # get matrix (child)
  392.             matrix = Array4x4ToBlenderMatrix(jntdata.matrix)
  393.             matrix[0][3] = jntdata.position[0]
  394.             matrix[1][3] = jntdata.position[1]
  395.             matrix[2][3] = jntdata.position[2]
  396.  
  397.             # compute joint position in world coordinates
  398.             if self.skeleton.format & SMC.JOINT_FORMAT_ABSOLUTE:
  399.                 jntnode.m_world = matrix
  400.             else:
  401.                 jntnode.m_world = parnode.m_world * matrix
  402.  
  403.             # joint coordinate system
  404.             x = [matrix[0][0], matrix[0][1], matrix[0][2]]
  405.             y = [matrix[1][0], matrix[1][1], matrix[1][2]]
  406.             z = [matrix[2][0], matrix[2][1], matrix[2][2]]
  407.             joint_X_axis = Blender.Mathutils.Vector(NormalizeVector(x))
  408.             joint_Y_axis = Blender.Mathutils.Vector(NormalizeVector(y))
  409.             joint_Z_axis = Blender.Mathutils.Vector(NormalizeVector(z))
  410.             
  411.             # joint position
  412.             jntnode.p_world = Blender.Mathutils.Vector([0.0, 0.0, 0.0])
  413.             jntnode.p_world[0] = jntnode.m_world[0][3]
  414.             jntnode.p_world[1] = jntnode.m_world[1][3]
  415.             jntnode.p_world[2] = jntnode.m_world[2][3]
  416.  
  417.             # create blender bone
  418.             bone = Blender.Armature.Editbone()
  419.             bone.head = jntnode.p_world
  420.             bone.tail = jntnode.p_world + SMCJointVisitor.DEFAULT_JOINT_LENGTH*joint_X_axis
  421.             bone.roll = 0
  422.             if parentBone != None: bone.parent = parentBone
  423.             
  424.             # assign bone to armature
  425.             bonename = jntdata.name
  426.             self.armature.bones[bonename] = bone
  427.  
  428.             # insert joint into secondary map
  429.             self.secmap[jntid] = jntnode
  430.             
  431.             # recursively visit children
  432.             for child in children:
  433.                 self.visit(child, bone)
  434.                 
  435.         # parent joint does not exists
  436.         else:
  437.  
  438.             # get joint matrix
  439.             matrix = Array4x4ToBlenderMatrix(jntdata.matrix)
  440.             matrix[0][3] = jntdata.position[0]
  441.             matrix[1][3] = jntdata.position[1]
  442.             matrix[2][3] = jntdata.position[2]
  443.             matrix[3][3] = 1.0
  444.             
  445.             # set joint's orientation in world space
  446.             jntnode.m_world = matrix
  447.  
  448.             # set joint's position in world space
  449.             jntnode.p_world = Blender.Mathutils.Vector([0.0, 0.0, 0.0])
  450.             jntnode.p_world[0] = jntdata.position[0]
  451.             jntnode.p_world[1] = jntdata.position[1]
  452.             jntnode.p_world[2] = jntdata.position[2]
  453.  
  454.             # get joint coordinate system
  455.             x = [matrix[0][0], matrix[0][1], matrix[0][2]]
  456.             y = [matrix[1][0], matrix[1][1], matrix[1][2]]
  457.             z = [matrix[2][0], matrix[2][1], matrix[2][2]]
  458.             joint_X_axis = Blender.Mathutils.Vector(NormalizeVector(x))
  459.             joint_Y_axis = Blender.Mathutils.Vector(NormalizeVector(y))
  460.             joint_Z_axis = Blender.Mathutils.Vector(NormalizeVector(z))
  461.             
  462.             # create blender bone
  463.             bone = Blender.Armature.Editbone()
  464.             bone.head = jntnode.p_world
  465.             bone.tail = jntnode.p_world + SMCJointVisitor.DEFAULT_JOINT_LENGTH*joint_X_axis
  466.             bone.roll = 0
  467.             
  468.             # assign bone to armature
  469.             bonename = jntdata.name
  470.             self.armature.bones[bonename] = bone
  471.             
  472.             # insert joint into secondary map
  473.             self.secmap[jntid] = jntnode
  474.             
  475.             # recursively visit children
  476.             for child in children:
  477.                 self.visit(child, bone)
  478.             
  479. #
  480. # IMPORT SMC CLASS
  481. #
  482.  
  483. class SMC:
  484.  
  485.     # CONSTANTS (VERTEX BUFFER FLAGS)
  486.     VERTEX_POSITION = 0x01
  487.     VERTEX_NORMAL   = 0x02
  488.     VERTEX_TANGENT  = 0x04
  489.     VERTEX_BINORMAL = 0x08
  490.     VERTEX_WEIGHTS  = 0x10
  491.     VERTEX_UV       = 0x20
  492.     VERTEX_COLORS   = 0x40
  493.     VERTEX_SKELETON = 0x80
  494.     
  495.     # CONSTANTS (INDEX BUFFER INDEX FORMAT)
  496.     UINT08 = 0x00
  497.     UINT16 = 0x01
  498.     UINT32 = 0x02
  499.  
  500.     # CONSTANTS (INDEX BUFFER PRIMITIVE TYPE)
  501.     TRIANGLES   = 0x00
  502.     TRISTRIP    = 0x01
  503.     TRISTRIPCUT = 0x02
  504.     
  505.     # CONSTANTS (INDEX BUFFER WINDING ORDER)
  506.     CW  = 0x00
  507.     CCW = 0x01
  508.     
  509.     # CONSTANTS (INVALID VALUES)
  510.     INVALID_SURFMAT    = 0xFFFF
  511.     INVALID_TEXTURE    = 0xFFFF
  512.     INVALID_BLENDINDEX = 0xFFFF
  513.     INVALID_JOINT      = 0xFFFFFFFF
  514.     INVALID_INDEX      = 0xFFFFFFFF
  515.     INVALID_JMAP_INDEX = 0xFFFFFFFF
  516.  
  517.     # CONSTANTS (TEXTURE MAPS)
  518.     DIFFUSE_MAP     = 0x0001
  519.     SPECULAR_MAP    = 0x0002
  520.     BUMP_MAP        = 0x0004
  521.     NORMAL_MAP      = 0x0008
  522.     ALPHA_MAP       = 0x0010
  523.     LIGHT_MAP       = 0x0020
  524.     GLOSS_MAP       = 0x0040
  525.     ENVIRONMENT_MAP = 0x0080
  526.     INVALID_MAP     = 0x8000
  527.     
  528.     # CONSTANTS (SKELETONS)
  529.     JOINT_FORMAT_ABSOLUTE   = 0x0001
  530.     JOINT_FORMAT_RELATIVE   = 0x0002
  531.     JOINT_FORMAT_MATRIX     = 0x0004
  532.     JOINT_FORMAT_QUATERNION = 0x0008
  533.     JOINT_FORMAT_TIP_LENGTH = 0x0010
  534.     JOINT_FORMAT_X_BONEAXIS = 0x0020
  535.     JOINT_FORMAT_Y_BONEAXIS = 0x0040
  536.     JOINT_FORMAT_Z_BONEAXIS = 0x0080
  537.     
  538. class SMCImporter:
  539.  
  540.     # CONSTRUCTOR
  541.     def __init__(self):
  542.         
  543.         self.flip_U = False
  544.         self.flip_V = True
  545.  
  546.     # PRIVATE METHOD:
  547.     def __readString(self, defaultValue):
  548.  
  549.         # validate length of default value
  550.         if len(defaultValue) == 0:
  551.             raise Exception('SMC Import Error: Default string values cannot be null.')
  552.             
  553.         # read length
  554.         namelen = self.ifile.LE_read_uint32()
  555.         if namelen == 0: return defaultValue
  556.         
  557.         # excessively long string
  558.         if namelen > 0xFF:
  559.             raise Exception('SMC Import Error: The maximum length for all names is 255 characters.')
  560.  
  561.         # read string
  562.         name = self.ifile.read_string(namelen)
  563.         if len(name) < 1: raise Exception('SMC Import Error: String values cannot be null.')
  564.         
  565.         # return string
  566.         return name
  567.         
  568.     # PRIVATE METHOD: 
  569.     def __processSMCHeader(self):
  570.  
  571.         # read magic number
  572.         self.header = SMCHEADER()
  573.         self.header.magic = self.ifile.LE_read_uint32()
  574.         if self.header.magic != 0x20434D53: raise Exception('SMC Import Error: Invalid SMC file.')
  575.         
  576.         # read version
  577.         self.header.major_version = self.ifile.LE_read_uint16()
  578.         self.header.minor_version = self.ifile.LE_read_uint16()
  579.         if self.header.major_version != 0x01:
  580.             raise Exception('SMC Import Error: Script is meant for SMC files of versions 1.0 and lower.')
  581.         if self.header.minor_version != 0x00:
  582.             raise Exception('SMC Import Error: Script is meant for SMC files of versions 1.0 and lower.')
  583.         
  584.         # read number of buffers
  585.         self.header.n_vbuffers = self.ifile.LE_read_uint32()
  586.         self.header.n_ibuffers = self.ifile.LE_read_uint32()
  587.         
  588.         # read number of images
  589.         self.header.n_images = self.ifile.LE_read_uint32()
  590.         
  591.         # read number of surfaces and materials
  592.         self.header.n_surfaces = self.ifile.LE_read_uint32()
  593.         self.header.n_surfmats = self.ifile.LE_read_uint32()
  594.         
  595.         # read number of skeletons
  596.         self.header.n_skeletons = self.ifile.LE_read_uint32()
  597.         if (self.header.n_skeletons != 0 and self.header.n_skeletons != 1):
  598.             raise Exception('SMC Import Error: Invalid number of skeletons; this value must be 0 or 1.')
  599.  
  600.         # read number of joint maps
  601.         self.header.n_jointmaps = self.ifile.LE_read_uint32()
  602.             
  603.         # read number of animations
  604.         self.header.n_animations = self.ifile.LE_read_uint32()
  605.         if self.header.n_animations != 0:
  606.             raise Exception('SMC Import Error: Animations are not yet supported.')
  607.         
  608.         # read reserved values
  609.         self.header.reserved1 = self.ifile.LE_read_uint32()
  610.         self.header.reserved2 = self.ifile.LE_read_uint32()
  611.         self.header.reserved3 = self.ifile.LE_read_uint32()
  612.         self.header.reserved4 = self.ifile.LE_read_uint32()
  613.         self.header.reserved5 = self.ifile.LE_read_uint32()
  614.         self.header.reserved6 = self.ifile.LE_read_uint32()
  615.  
  616.         return True
  617.     
  618.     # PRIVATE METHOD: 
  619.     def __processFileList(self):
  620.  
  621.         # construct filelist
  622.         self.images = []
  623.         for i in range(self.header.n_images):
  624.             namelen = self.ifile.LE_read_uint32()
  625.             if namelen < 0x001: raise Exception('SMC Import Error: Invalid filename.')
  626.             if namelen > 0x400: raise Exception('SMC Import Error: Invalid filename.')
  627.             namedat = self.ifile.read_string(namelen)
  628.             self.images.append(namedat)
  629.         
  630.         return True
  631.  
  632.     # PRIVATE METHOD: 
  633.     def __processVBuffers(self):
  634.  
  635.         # initialize vertex buffer list
  636.         self.vblist = []
  637.         
  638.         # for each vertex buffer
  639.         for i in range(self.header.n_vbuffers):
  640.             
  641.             # read vertex buffer flags
  642.             vb = SMCVTXBUFFER()
  643.             vb.flags = self.ifile.LE_read_uint32()
  644.             
  645.             # read vertex buffer name
  646.             len = self.ifile.LE_read_uint32()
  647.             if (len < 0x01) or (len > 0xFF): raise Exception('SMC Import Error: Invalid vertex buffer name.')
  648.             vb.name = self.ifile.read_string(len)
  649.         
  650.             # read number and type of texture channels
  651.             vb.uvchan = self.ifile.LE_read_uint16()
  652.             if vb.uvchan > 8: raise Exception('SMC Import Error: Invalid number of UV channels.')
  653.             vb.uvtype = self.ifile.LE_read_uint16_array(8)
  654.  
  655.             # read number of color channels
  656.             vb.colors = self.ifile.LE_read_uint16()
  657.             if vb.colors > 8: raise Exception('SMC Import Error: Invalid number of color channels.')
  658.  
  659.             # read number of vertices
  660.             vb.elem = self.ifile.LE_read_uint32()
  661.             if vb.elem == 0: raise Exception('SMC Import Error: Vertex buffers must have at least one vertex.')
  662.  
  663.             # initialize vertex data
  664.             vb.positions = []
  665.             vb.normals = []
  666.             vb.tangents = []
  667.             vb.binormals = []
  668.             vb.blendweights = []
  669.             vb.blendindices = []
  670.             vb.texcoords = [[], [], [], [], [], [], [], []]
  671.             vb.vtxcolors = [[], [], [], [], [], [], [], []]
  672.  
  673.             # read vertices
  674.             vb.data = []
  675.             for j in range(vb.elem):
  676.  
  677.                 # read position
  678.                 if (vb.flags & SMC.VERTEX_POSITION):
  679.                     vb.positions.append(self.ifile.LE_read_real32_array(3))
  680.  
  681.                 # read normal
  682.                 if (vb.flags & SMC.VERTEX_NORMAL):
  683.                     vb.normals.append(self.ifile.LE_read_real32_array(3))
  684.  
  685.                 # read tangent
  686.                 if (vb.flags & SMC.VERTEX_TANGENT):
  687.                     vb.tangents.append(self.ifile.LE_read_real32_array(3))
  688.  
  689.                 # read binormal
  690.                 if (vb.flags & SMC.VERTEX_BINORMAL):
  691.                     vb.binormals.append(self.ifile.LE_read_real32_array(3))
  692.  
  693.                 # read blend weights
  694.                 if (vb.flags & SMC.VERTEX_WEIGHTS):
  695.                     vb.blendweights.append(self.ifile.LE_read_real32_array(8))
  696.                     vb.blendindices.append(self.ifile.LE_read_uint16_array(8))
  697.  
  698.                 # read texture coordinates
  699.                 if (vb.flags & SMC.VERTEX_UV):
  700.                     for k in range(vb.uvchan):
  701.                         tmp = self.ifile.LE_read_real32_array(2)
  702.                         if self.flip_U: tmp[0] = 1.0 - tmp[0]
  703.                         if self.flip_V: tmp[1] = 1.0 - tmp[1]
  704.                         vb.texcoords[k].append(tmp)
  705.  
  706.                 # read vertex colors
  707.                 if vb.colors > 0:
  708.                     for k in range(vb.colors):
  709.                         tmp = self.ifile.LE_read_real32_array(4)
  710.                         vb.vtxcolors[k].append(tmp)
  711.  
  712.             # append vertex buffer
  713.             self.vblist.append(vb)
  714.  
  715.         return True
  716.  
  717.     # PRIVATE METHOD: 
  718.     def __processIBuffers(self):
  719.  
  720.         # initialize index buffer list
  721.         self.iblist = []
  722.  
  723.         # for each index buffer
  724.         for i in range(self.header.n_ibuffers):
  725.  
  726.             # read index buffer format
  727.             ib = SMCIDXBUFFER()
  728.             ib.format = self.ifile.LE_read_uint08()
  729.             if (ib.format < SMC.UINT08) or (ib.format > SMC.UINT32):
  730.                 raise Exception('SMC Import Error: Invalid index buffer format.')
  731.  
  732.             # read index buffer primitive type
  733.             ib.primitive = self.ifile.LE_read_uint08()
  734.             if (ib.primitive < SMC.TRIANGLES) or (ib.primitive > SMC.TRISTRIPCUT):
  735.                 raise Exception('SMC Import Error: Invalid index buffer primitive type.')
  736.  
  737.             # read winding order
  738.             ib.direction = self.ifile.LE_read_uint08()
  739.             if (ib.direction != SMC.CW) and (ib.direction != SMC.CCW):
  740.                 ss = 'SMC Import Error: Invalid winding order ' + str(ib.direction) + ' at ' + str(self.ifile.tell()) + '.'
  741.                 raise Exception(ss)
  742.  
  743.             # read reserved byte
  744.             ib.reserved = self.ifile.LE_read_uint08()
  745.             if ib.reserved != 0: ib.reserved = 0                
  746.                 
  747.             # read index buffer name
  748.             len = self.ifile.LE_read_uint32()
  749.             if (len < 0x01) or (len > 0xFF): raise Exception('SMC Import Error: Invalid index buffer name.')
  750.             ib.name = self.ifile.read_string(len)
  751.  
  752.             # read number of indices
  753.             ib.elem = self.ifile.LE_read_uint32()
  754.             ib.data = []
  755.  
  756.             # read indices
  757.             if ib.elem > 0:
  758.                 if ib.format == SMC.UINT08:
  759.                     ib.data = self.ifile.LE_read_uint08_array(ib.elem)
  760.                 elif ib.format == SMC.UINT16:
  761.                     ib.data = self.ifile.LE_read_uint16_array(ib.elem)
  762.                 elif ib.format == SMC.UINT32:
  763.                     ib.data = self.ifile.LE_read_uint32_array(ib.elem)
  764.  
  765.             # read extra byte for odd number of AMC_UINT08 indices
  766.             if (ib.format == SMC.UINT08) and (ib.elem % 2 == 1):
  767.                 self.ifile.skip(1)            
  768.             
  769.             # append index buffer
  770.             self.iblist.append(ib)
  771.  
  772.         return True
  773.  
  774.     # PRIVATE METHOD: 
  775.     def __processSurfmats(self):
  776.  
  777.         # initialize material list
  778.         self.surfmats = []
  779.         
  780.         # for each material
  781.         for i in range(self.header.n_surfmats):
  782.  
  783.             # read material name
  784.             sm = SMCSURFMAT()
  785.             len = self.ifile.LE_read_uint32()
  786.             if (len < 0x01) or (len > 0xFF): raise Exception('SMC Import Error: Invalid material name.')
  787.             sm.name = self.ifile.read_string(len)
  788.  
  789.             # read material properties
  790.             sm.twoside = self.ifile.LE_read_uint08()
  791.             sm.unused1 = self.ifile.LE_read_uint08()
  792.             sm.unused2 = self.ifile.LE_read_uint08()
  793.             sm.unused3 = self.ifile.LE_read_uint08()
  794.             
  795.             # read texture references
  796.             sm.basemap = self.ifile.LE_read_uint16()
  797.             sm.specmap = self.ifile.LE_read_uint16()
  798.             sm.tranmap = self.ifile.LE_read_uint16()
  799.             sm.bumpmap = self.ifile.LE_read_uint16()
  800.             sm.normmap = self.ifile.LE_read_uint16()
  801.             sm.lgthmap = self.ifile.LE_read_uint16()
  802.             sm.envimap = self.ifile.LE_read_uint16()
  803.             sm.glssmap = self.ifile.LE_read_uint16()
  804.             sm.resmap1 = self.ifile.LE_read_uint16()
  805.             sm.resmap2 = self.ifile.LE_read_uint16()
  806.             sm.resmap3 = self.ifile.LE_read_uint16()
  807.             sm.resmap4 = self.ifile.LE_read_uint16()
  808.             sm.resmap5 = self.ifile.LE_read_uint16()
  809.             sm.resmap6 = self.ifile.LE_read_uint16()
  810.             sm.resmap7 = self.ifile.LE_read_uint16()
  811.             sm.resmap8 = self.ifile.LE_read_uint16()
  812.             
  813.             # read texture channel references
  814.             sm.basemapchan = self.ifile.LE_read_uint08()
  815.             sm.specmapchan = self.ifile.LE_read_uint08()
  816.             sm.tranmapchan = self.ifile.LE_read_uint08()
  817.             sm.bumpmapchan = self.ifile.LE_read_uint08()
  818.             sm.normmapchan = self.ifile.LE_read_uint08()
  819.             sm.lghtmapchan = self.ifile.LE_read_uint08()
  820.             sm.envimapchan = self.ifile.LE_read_uint08()
  821.             sm.glssmapchan = self.ifile.LE_read_uint08()
  822.             sm.resmapchan1 = self.ifile.LE_read_uint08()
  823.             sm.resmapchan2 = self.ifile.LE_read_uint08()
  824.             sm.resmapchan3 = self.ifile.LE_read_uint08()
  825.             sm.resmapchan4 = self.ifile.LE_read_uint08()
  826.             sm.resmapchan5 = self.ifile.LE_read_uint08()
  827.             sm.resmapchan6 = self.ifile.LE_read_uint08()
  828.             sm.resmapchan7 = self.ifile.LE_read_uint08()
  829.             sm.resmapchan8 = self.ifile.LE_read_uint08()
  830.     
  831.             # append material
  832.             self.surfmats.append(sm)
  833.             
  834.         return True
  835.     
  836.     # PRIVATE METHOD: 
  837.     def __processSurfaces(self):
  838.  
  839.         # initialize surface list
  840.         self.surfaces = []
  841.         
  842.         # for each surface
  843.         for i in range(self.header.n_surfaces):
  844.  
  845.             # read surface name
  846.             surf = SMCSURFACE()
  847.             tmp = self.ifile.LE_read_uint32()
  848.             if (tmp < 0x01) or (tmp > 0xFF): raise Exception('SMC Import Error: Invalid surface name.')
  849.             surf.name = self.ifile.read_string(tmp)
  850.             if len(surf.name) < 1: raise Exception('SMC Import Error: Invalid surface name.')
  851.  
  852.             # read number of buffer references
  853.             surf.references = self.ifile.LE_read_uint32()
  854.             if surf.references < 1: raise Exception('SMC Import Error: A surface must have at least one buffer reference.')
  855.                         
  856.             # read references
  857.             surf.reflist = []
  858.             for j in range(surf.references):
  859.             
  860.                 # read vertex buffer index
  861.                 ref = SMCSURFREF()
  862.                 ref.vb_index = self.ifile.LE_read_uint32()
  863.                 if ref.vb_index < 0:
  864.                     raise Exception('SMC Import Error: Invalid vertex buffer reference.')
  865.                 if not(ref.vb_index < self.header.n_vbuffers):
  866.                     raise Exception('SMC Import Error: Invalid vertex buffer reference.')
  867.                 
  868.                 # read vertex buffer start index
  869.                 ref.vb_start = self.ifile.LE_read_uint32()
  870.                 if ref.vb_start < 0:
  871.                     raise Exception('SMC Import Error: Invalid vertex buffer start index.')
  872.                 if not(ref.vb_start < self.vblist[ref.vb_index].elem):
  873.                     raise Exception('SMC Import Error: Invalid vertex buffer start index.')
  874.                 
  875.                 # read vertex buffer width
  876.                 ref.vb_width = self.ifile.LE_read_uint32()
  877.                 if ref.vb_width < 1:
  878.                     raise Exception('SMC Import Error: Invalid vertex buffer surface width.')
  879.                 if self.vblist[ref.vb_index].elem < ref.vb_width:
  880.                     raise Exception('SMC Import Error: Invalid vertex buffer surface width.')
  881.                 if self.vblist[ref.vb_index].elem < (ref.vb_start + ref.vb_width):
  882.                     raise Exception('SMC Import Error: Invalid vertex buffer surface width.')
  883.  
  884.                 # read index buffer index, start index, and width
  885.                 ref.ib_index = self.ifile.LE_read_uint32()
  886.                 ref.ib_start = self.ifile.LE_read_uint32()
  887.                 ref.ib_width = self.ifile.LE_read_uint32()
  888.                 
  889.                 # read joint map index (0xFFFFFFFF if not using a joint map)
  890.                 ref.jm_index = self.ifile.LE_read_uint32()
  891.  
  892.                 # validate
  893.                 # note that if the index is invalid, this surface only contains points!
  894.                 if ref.ib_index != SMC.INVALID_INDEX:
  895.                 
  896.                     # validate index buffer index
  897.                     if ref.ib_index < 0:
  898.                         raise Exception('SMC Import Error: Invalid index buffer reference.')
  899.                     if not(ref.ib_index < self.header.n_ibuffers):
  900.                         raise Exception('SMC Import Error: Invalid index buffer reference.')
  901.                 
  902.                     # validate index buffer start index
  903.                     if ref.ib_start < 0:
  904.                         raise Exception('SMC Import Error: Invalid index buffer start index.')
  905.                     if not(ref.ib_start < self.iblist[ref.ib_index].elem):
  906.                         raise Exception('SMC Import Error: Invalid index buffer start index.')
  907.                 
  908.                     # validate index buffer width
  909.                     if ref.ib_width < 1:
  910.                         raise Exception('SMC Import Error: Invalid index buffer surface width.')
  911.                     if self.iblist[ref.ib_index].elem < ref.ib_width:
  912.                         raise Exception('SMC Import Error: Invalid index buffer surface width.')
  913.                     if self.iblist[ref.ib_index].elem < (ref.ib_start + ref.ib_width):
  914.                         raise Exception('SMC Import Error: Invalid index buffer surface width.')
  915.                     
  916.                 # append reference
  917.                 surf.reflist.append(ref)
  918.             
  919.             # read surface material
  920.             surf.surfmat = self.ifile.LE_read_uint16()
  921.             if surf.surfmat != SMC.INVALID_SURFMAT:
  922.                 if surf.surfmat < 0: raise Exception('SMC Import Error: Invalid material reference.')
  923.                 if not(surf.surfmat < self.header.n_surfmats): raise Exception('SMC Import Error: Invalid material reference.')
  924.  
  925.             # append surface
  926.             self.surfaces.append(surf)
  927.  
  928.         return True
  929.  
  930.     # PRIVATE METHOD: 
  931.     def __processSkeleton(self):
  932.  
  933.         # initialize surface list
  934.         self.skeletons = []
  935.         
  936.         # for each skeleton
  937.         for i in range(self.header.n_skeletons):
  938.  
  939.             # read format
  940.             skel = SMCSKELETON()
  941.             skel.format = self.ifile.LE_read_uint16()
  942.  
  943.             # validate format
  944.             if skel.format & SMC.JOINT_FORMAT_ABSOLUTE:
  945.                 if skel.format & SMC.JOINT_FORMAT_RELATIVE:
  946.                     raise Exception('SMC Import Error: Skeletons cannot be absolute and relative.')
  947.             elif skel.format & SMC.JOINT_FORMAT_RELATIVE:
  948.                 if skel.format & SMC.JOINT_FORMAT_ABSOLUTE:
  949.                     raise Exception('SMC Import Error: Skeletons cannot be absolute and relative.')
  950.             else:
  951.                 raise Exception('SMC Import Error: Skeletons must be absolute or relative.')
  952.             
  953.             # validate format
  954.             if skel.format & SMC.JOINT_FORMAT_MATRIX:
  955.                 if skel.format & SMC.JOINT_FORMAT_QUATERNION:
  956.                     raise Exception('SMC Import Error: Skeletons cannot use matrices and quaternions.')
  957.             elif skel.format & SMC.JOINT_FORMAT_QUATERNION:
  958.                 if skel.format & SMC.JOINT_FORMAT_MATRIX:
  959.                     raise Exception('SMC Import Error: Skeletons cannot use matrices and quaternions.')
  960.             else:
  961.                 raise Exception('SMC Import Error: Skeletons must use matrices or quaternions.')
  962.             
  963.             # validate format
  964.             if skel.format & SMC.JOINT_FORMAT_X_BONEAXIS:
  965.                 if (skel.format & SMC.JOINT_FORMAT_Y_BONEAXIS) or (skel.format & SMC.JOINT_FORMAT_Z_BONEAXIS):
  966.                     raise Exception('SMC Import Error: Skeletons cannot use more than one bone axis.')
  967.             elif skel.format & SMC.JOINT_FORMAT_Y_BONEAXIS:
  968.                 if (skel.format & SMC.JOINT_FORMAT_X_BONEAXIS) or (skel.format & SMC.JOINT_FORMAT_Z_BONEAXIS):
  969.                     raise Exception('SMC Import Error: Skeletons cannot use more than one bone axis.')
  970.             elif skel.format & SMC.JOINT_FORMAT_Z_BONEAXIS:
  971.                 if (skel.format & SMC.JOINT_FORMAT_X_BONEAXIS) or (skel.format & SMC.JOINT_FORMAT_Y_BONEAXIS):
  972.                     raise Exception('SMC Import Error: Skeletons cannot use more than one bone axis.')
  973.             else:
  974.                 raise Exception('SMC Import Error: Skeletons must define a bone axis.')
  975.  
  976.             # read tip length
  977.             if skel.format & SMC.JOINT_FORMAT_TIP_LENGTH:
  978.                 skel.tiplen = self.ifile.LE_read_real32()
  979.                 if skel.tiplen < 0.0:
  980.                     raise Exception('SMC Import Error: Skeleton tip lengths must be positive.')
  981.                 elif skel.tiplen > 1024.0:
  982.                     raise Exception('SMC Import Error: Skeleton tip lengths must be shorter than 1024.')
  983.             
  984.             # read name
  985.             skel.name = self.__readString('default')
  986.  
  987.             # read joints
  988.             skel.n_joints = self.ifile.LE_read_uint32()
  989.             skel.joints = []
  990.             for j in range(skel.n_joints):
  991.  
  992.                 # read name
  993.                 jnt = SMCJOINT()
  994.                 defaultValue = 'jnt_' + str(j)
  995.                 jnt.name = self.__readString(defaultValue)
  996.  
  997.                 # read id
  998.                 jnt.id = self.ifile.LE_read_uint32()
  999.                 if jnt.id == SMC.INVALID_JOINT:
  1000.                     raise Exception('SMC Import Error: Invalid joint identifier.')
  1001.  
  1002.                 # read parent
  1003.                 jnt.parent = self.ifile.LE_read_uint32()
  1004.  
  1005.                 # read matrix or quaternion
  1006.                 if skel.format & SMC.JOINT_FORMAT_MATRIX:
  1007.                     jnt.matrix = self.ifile.LE_read_real32_array(16)
  1008.                 elif skel.format & SMC.JOINT_FORMAT_QUATERNION:
  1009.                     jnt.quaternion = self.ifile.LE_read_real32_array(4)
  1010.  
  1011.                 # read position
  1012.                 jnt.position = self.ifile.LE_read_real32_array(4)
  1013.                 
  1014.                 # insert joint
  1015.                 skel.joints.append(jnt)
  1016.  
  1017.             # insert skeleton
  1018.             self.skeletons.append(skel)
  1019.             
  1020.         return True
  1021.  
  1022.     # PRIVATE METHOD:
  1023.     def __processJointMap(self):
  1024.  
  1025.         # initialize surface list
  1026.         self.jntmaplist = []
  1027.         
  1028.         # for each joint map
  1029.         for i in range(self.header.n_jointmaps):
  1030.             n_items = self.ifile.LE_read_uint32()
  1031.             items = []
  1032.             for j in range(n_items):
  1033.                 temp = self.ifile.LE_read_uint32()
  1034.                 items.append(temp)
  1035.             self.jntmaplist.append(items)
  1036.     
  1037.     # PRIVATE METHOD: 
  1038.     def __processAnimList(self):
  1039.         
  1040.         return True
  1041.  
  1042.     # PRIVATE METHOD:
  1043.     def __buildVBuffer(self, surf):
  1044.  
  1045.         # for each reference
  1046.         for index, ref in enumerate(surf.reflist):
  1047.         
  1048.             # create name for mesh object
  1049.             meshname = surf.name
  1050.             meshname += '_ref_'
  1051.             meshname += str(index)
  1052.  
  1053.             # create Blender mesh for this vertex buffer
  1054.             mesh = Blender.Mesh.New()
  1055.             mesh.name = meshname
  1056.  
  1057.             # vertex and index buffers
  1058.             vb = self.vblist[ref.vb_index]
  1059.             ib = self.iblist[ref.ib_index]
  1060.             
  1061.             # positions
  1062.             verts = []
  1063.             for dst_index in range(ref.vb_width):
  1064.                 src_index = ref.vb_start + dst_index
  1065.                 verts.append(vb.positions[src_index])
  1066.             mesh.verts.extend(verts)
  1067.  
  1068.             # normals
  1069.             if vb.flags & SMC.VERTEX_NORMAL:
  1070.                 for vertex in mesh.verts:
  1071.                     nx = vb.normals[ref.vb_start + vertex.index][0]
  1072.                     ny = vb.normals[ref.vb_start + vertex.index][1]
  1073.                     nz = vb.normals[ref.vb_start + vertex.index][2]
  1074.                     vertex.no = Blender.Mathutils.Vector(nx, ny, nz)
  1075.             
  1076.             # texture coordinates
  1077.             uvmap = [[], [], [], [], [], [], [], []]
  1078.             if vb.flags & SMC.VERTEX_UV:
  1079.  
  1080.                 # for each UV channel
  1081.                 for i in range(vb.uvchan):
  1082.                 
  1083.                     # copy UVs if UV map channel exists
  1084.                     if vb.uvtype[i] != SMC.INVALID_MAP:
  1085.  
  1086.                         # copy UVs
  1087.                         for dst_index in range(ref.vb_width):
  1088.                             src_index = ref.vb_start + dst_index
  1089.                             uvmap[i].append(vb.texcoords[i][src_index])
  1090.  
  1091.             # faces
  1092.             faces = []
  1093.             if ref.ib_index != SMC.INVALID_INDEX:
  1094.  
  1095.                 # from triangle list
  1096.                 if ib.primitive == SMC.TRIANGLES:
  1097.                 
  1098.                     # must have triangles
  1099.                     if ref.ib_width < 3:
  1100.                         raise Exception('SMC Import Error: The number of triangle indices must be greater than three.')
  1101.                     if ref.ib_width % 3:
  1102.                         raise Exception('SMC Import Error: The number of triangle indices must be divisible by three.')
  1103.                     
  1104.                     # build triangles
  1105.                     for i in range((ref.ib_width / 3)):
  1106.                     
  1107.                         # triangle indices
  1108.                         src_index = ref.ib_start + i * 3
  1109.                         a = ib.data[src_index + 0]
  1110.                         b = ib.data[src_index + 1]
  1111.                         c = ib.data[src_index + 2]
  1112.                         if not(a < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1113.                         if not(b < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1114.                         if not(c < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1115.                         
  1116.                         # insert triangle
  1117.                         if (a != b) and (a != c) and (b != c):
  1118.                             if ib.direction == SMC.CW:
  1119.                                 faces.append([a, b, c])
  1120.                             else:
  1121.                                 faces.append([a, c, b])
  1122.                     
  1123.                 elif ib.primitive == SMC.TRISTRIP:
  1124.     
  1125.                     # first triangle
  1126.                     a = ib.data[ref.ib_start + 0]
  1127.                     b = ib.data[ref.ib_start + 1]
  1128.                     c = ib.data[ref.ib_start + 2]
  1129.                     if not(a < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1130.                     if not(b < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1131.                     if not(c < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1132.                     
  1133.                     # insert first triangle
  1134.                     if (a != b) and (a != c) and (b != c):
  1135.                         if ib.direction == SMC.CW:
  1136.                             faces.append([a, b, c])
  1137.                         else:
  1138.                             faces.append([a, c, b])
  1139.                     
  1140.                     # reamaining triangles
  1141.                     for i in range(3, ref.ib_width):
  1142.                     
  1143.                         # triangle indices
  1144.                         a = b
  1145.                         b = c
  1146.                         c = ib.data[ref.ib_start + i]
  1147.                         if not(c < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1148.                         
  1149.                         # insert triangle
  1150.                         if (a != b) and (a != c) and (b != c):
  1151.                             if i % 2:
  1152.                                 if ib.direction == SMC.CW:
  1153.                                     faces.append([a, c, b])
  1154.                                 else:
  1155.                                     faces.append([a, b, c])
  1156.                             else:
  1157.                                 if ib.direction == SMC.CW:
  1158.                                     faces.append([a, b, c])
  1159.                                 else:
  1160.                                     faces.append([a, c, b])
  1161.                         
  1162.                 elif ib.primitive == SMC.TRISTRIPCUT:
  1163.  
  1164.                     # maintain a tristrip index
  1165.                     tristrip_data = []
  1166.                     tristrip_curr = []
  1167.                     
  1168.                     # value of restart index depends on the data type
  1169.                     strip_index = 0xFFFFFFFF
  1170.                     if ib.format == SMC.UINT08:
  1171.                         strip_index = 0xFF
  1172.                     elif ib.format == SMC.UINT16:
  1173.                         strip_index = 0xFFFF
  1174.                     elif ib.format == SMC.UINT32:
  1175.                         strip_index = 0xFFFFFFFF
  1176.                         
  1177.                     # create a list of triangle strips
  1178.                     for i in range(ref.ib_width):
  1179.                     
  1180.                         temp = ib.data[ref.ib_start + i]
  1181.                         if temp == strip_index:
  1182.                             if len(tristrip_curr) < 3: raise Exception('SMC Import Error: Not enough indices for a triangle strip.')
  1183.                             tristrip_data.append(tristrip_curr)
  1184.                             tristrip_curr = []
  1185.                         else:
  1186.                             tristrip_curr.append(temp)
  1187.                             if ((i + 1) == ref.ib_width): # last index is not an strip index
  1188.                                 tristrip_data.append(tristrip_curr)
  1189.                                 tristrip_curr = []                                
  1190.  
  1191.                     # process triangle strips
  1192.                     for tristrip in tristrip_data:
  1193.  
  1194.                         # first triangle
  1195.                         a = tristrip[0]
  1196.                         b = tristrip[1]
  1197.                         c = tristrip[2]
  1198.                         if not(a < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1199.                         if not(b < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1200.                         if not(c < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1201.                         if (a != b) and (a != c) and (b != c):
  1202.                             if ib.direction == SMC.CW: faces.append([a, b, c])
  1203.                             else: faces.append([a, c, b])
  1204.                         
  1205.                         # remaining triangles
  1206.                         for i in range(3, len(tristrip)):
  1207.                             a = b
  1208.                             b = c
  1209.                             c = tristrip[i]
  1210.                             if not(c < ref.vb_width): raise Exception('SMC Import Error: Triangle index out of bounds.')
  1211.                             if (a != b) and (a != c) and (b != c):
  1212.                                 if i % 2:
  1213.                                     if ib.direction == SMC.CW: faces.append([a, c, b])
  1214.                                     else: faces.append([a, b, c])
  1215.                                 else:
  1216.                                     if ib.direction == SMC.CW: faces.append([a, b, c])
  1217.                                     else: faces.append([a, c, b])
  1218.  
  1219.                 # construct blender mesh faces
  1220.                 mesh.faces.extend(faces)
  1221.                 
  1222.                 # smooth vertex normals
  1223.                 if vb.flags & SMC.VERTEX_NORMAL:
  1224.                     for face in mesh.faces:
  1225.                         face.smooth = 1
  1226.  
  1227.                 # assign texture coordinates
  1228.                 if vb.flags & SMC.VERTEX_UV:
  1229.     
  1230.                     # for each UV channel
  1231.                     for i in range(8):
  1232.  
  1233.                         # if UV channel exists
  1234.                         if vb.uvtype[i] != SMC.INVALID_MAP:
  1235.                         
  1236.                             # create UV layer
  1237.                             mapname = 'uvmap_channel_' + str(i)
  1238.                             mesh.addUVLayer(mapname)
  1239.                             mesh.activeUVLayer = mapname
  1240.                     
  1241.                             # assign texture coordinates to faces
  1242.                             # WARNING: THIS IS OLD CODE THAT CAUSED ROTATED UV COORDINATES!!!
  1243.                             #for face in mesh.faces:
  1244.                             #    a = faces[face.index][0]
  1245.                             #    b = faces[face.index][1]
  1246.                             #    c = faces[face.index][2]
  1247.                             #    uv_a = Mathutils.Vector(uvmap[i][a][0], uvmap[i][a][1])
  1248.                             #    uv_b = Mathutils.Vector(uvmap[i][b][0], uvmap[i][b][1])
  1249.                             #    uv_c = Mathutils.Vector(uvmap[i][c][0], uvmap[i][c][1])
  1250.                             #    face.uv = [ uv_a, uv_b, uv_c ]
  1251.  
  1252.                             # set sticky per-vertex UV coordinates
  1253.                             mesh.vertexUV = True
  1254.                             for j in range(len(mesh.verts)):
  1255.                                 mesh.verts[j].uvco = Blender.Mathutils.Vector(uvmap[i][j])
  1256.                             mesh.update()
  1257.                             
  1258.                             # set face UV coordinates
  1259.                             # NOTE: copies UV coordinates from sticky coordinates
  1260.                             mesh.faceUV = True;
  1261.                             for face in mesh.faces:
  1262.                                 face.uv = [v.uvco for v in face.verts]
  1263.                                 face.smooth = 1
  1264.                         
  1265.                             # update mesh                        
  1266.                             mesh.update()
  1267.  
  1268.                 # assign colors
  1269.                 # NOTE: You do not need to check AMC_VERTEX_COLORS flag to determine if there are
  1270.                 # vertex colors present.
  1271.                 if vb.colors > 0:
  1272.  
  1273.                     # enable vertex colors
  1274.                     mesh.vertexColors = True
  1275.  
  1276.                     # for each color channel
  1277.                     for i in range(vb.colors):
  1278.                     
  1279.                         # create color layer and make active
  1280.                         mapname = 'color_channel_' + str(i)
  1281.                         mesh.addColorLayer(mapname)
  1282.                         mesh.activeColorLayer = mapname
  1283.  
  1284.                         # create an array of colors
  1285.                         colorarr = [None] * len(mesh.verts)
  1286.                         for j in range(len(mesh.verts)):
  1287.                             colorarr[j] = [int(vb.vtxcolors[i][j][0] * 255.0),
  1288.                                            int(vb.vtxcolors[i][j][1] * 255.0),
  1289.                                            int(vb.vtxcolors[i][j][2] * 255.0),
  1290.                                            int(vb.vtxcolors[i][j][3] * 255.0)]
  1291.                         
  1292.                         # set face color coordinates
  1293.                         # NOTE: This is very interesting how it works!
  1294.                         # http://www.blender.org/documentation/249PythonDoc/Mesh.MFace-class.html#col
  1295.                         for face in mesh.faces:
  1296.                             for j, v in enumerate(face):
  1297.                                 face.col[j].r = colorarr[v.index][0]
  1298.                                 face.col[j].g = colorarr[v.index][1]
  1299.                                 face.col[j].b = colorarr[v.index][2]
  1300.                                 face.col[j].a = colorarr[v.index][3]
  1301.                         
  1302.                         # update mesh
  1303.                         mesh.update()
  1304.                 
  1305.             # update Blender mesh object
  1306.             mesh.update()
  1307.         
  1308.             # add mesh to current scene and make mesh active
  1309.             scene = Blender.Scene.GetCurrent()
  1310.             meshobject = scene.objects.new(mesh, meshname)
  1311.             scene.objects.active = meshobject
  1312.             self.meshlist.append(meshobject)
  1313.  
  1314.             # assign material to mesh object
  1315.             if surf.surfmat != SMC.INVALID_SURFMAT:
  1316.                 meshobject.colbits = 1
  1317.                 meshobject.setMaterials([self.materials[surf.surfmat]])
  1318.                 mesh.update()
  1319.         
  1320.             # blend weights
  1321.             # NOTE: blend weights must be added after a mesh has been associated with a mesh object!
  1322.             bidict = {}
  1323.             if vb.flags & SMC.VERTEX_WEIGHTS:
  1324.             
  1325.                 # for each set of blendweights and blendindices
  1326.                 for dst_index in range(ref.vb_width):
  1327.  
  1328.                     src_index = ref.vb_start + dst_index
  1329.                     for i in range(8):
  1330.                     
  1331.                         # get blend weight and blend index
  1332.                         bw = vb.blendweights[src_index][i]
  1333.                         bi = vb.blendindices[src_index][i]
  1334.  
  1335.                         # if blend index is valid
  1336.                         if bi != SMC.INVALID_BLENDINDEX:
  1337.                         
  1338.                             # if this surface reference uses a joint map
  1339.                             # remap the blend index using the map
  1340.                             if ref.jm_index != SMC.INVALID_JMAP_INDEX:
  1341.                             
  1342.                                 if not(ref.jm_index < len(self.jntmaplist)):
  1343.                                     raise Exception('SMC Import Error: Joint map index out of range.')
  1344.                                     
  1345.                                 # given a blend index, look it up in an array to get new blend index
  1346.                                 if not(bi < len(self.jntmaplist[ref.jm_index])):
  1347.                                     error = 'SMC Import Error: Joint map blending index '
  1348.                                     error = error + str(bi)
  1349.                                     error = error + ' out of range. The joint map only has '
  1350.                                     error = error + str(len(self.jntmaplist[ref.jm_index]))
  1351.                                     error = error + ' elements.'
  1352.                                     raise Exception(error)
  1353.  
  1354.                                 # remap blend index
  1355.                                 bi = self.jntmaplist[ref.jm_index][bi]
  1356.  
  1357.                             # associate blend weight with blend index
  1358.                             # 2014-04-11: DO NOT INSERT <BI, <index, BW>> PAIR IF BW = 0
  1359.                             if not (bi in bidict): bidict[bi] = []
  1360.                             #bidict[bi].append([dst_index, bw])
  1361.                             if bw > 0.0: bidict[bi].append([dst_index, bw])
  1362.  
  1363.                 # for each vertex weight map
  1364.                 for dk, dv in bidict.iteritems():
  1365.                 
  1366.                     # create vertex group and assign weights
  1367.                     mapname = 'jnt_' + ('%(value)03d' % {'value':dk}) # + str(dk)
  1368.                     mesh.addVertGroup(mapname)
  1369.                     for item in dv:
  1370.                         try:
  1371.                             mesh.assignVertsToGroup(mapname, [item[0]], item[1], Blender.Mesh.AssignModes.ADD)#REPLACE)
  1372.                         except Exception as e:
  1373.                             print('item = ' + str(item[0]) + ', ' + str(item[1]))
  1374.                             print('vertices = ' + str(vb.elem) + ', ' + str(len(mesh.verts)))
  1375.                             raise e
  1376.                         
  1377.     # PRIVATE METHOD:
  1378.     def __buildMeshTextures(self):
  1379.  
  1380.         # construct textures from filelist using relative directories
  1381.         # this is why we preface filename with '//'
  1382.         # see http://www.blender.org/documentation/blender_python_api_2_59_0/bpy.path.html
  1383.         self.texlist = []
  1384.         for index, filename in enumerate(self.images):
  1385.             try:
  1386.                 # create texture name based on index
  1387.                 name = 'texture_' + str(index)
  1388.                 # create texture
  1389.                 temp = Blender.Image.Load('//' + filename)
  1390.                 texture = Blender.Texture.New(name)
  1391.                 texture.setImage(temp)
  1392.                 # append data
  1393.                 self.texlist.append(texture)
  1394.             except Exception as e:
  1395.                 self.texlist.append(None)
  1396.                 print('Failed to load texture file ' + filename + '.')
  1397.     
  1398.     def __buildMeshMaterials(self):
  1399.  
  1400.         def isTextureValid(textureIndex):
  1401.             if textureIndex == SMC.INVALID_TEXTURE: return False
  1402.             if not (textureIndex < len(self.texlist)): return False
  1403.             if self.texlist[textureIndex] is None: return False
  1404.             return True
  1405.         
  1406.         # for each surface material
  1407.         self.materials = []
  1408.         for surfmat in self.surfmats:
  1409.  
  1410.             # create new material
  1411.             # set material to shadeless so we can see texture using Blender GLSL Materials 
  1412.             mat = Blender.Material.New(surfmat.name)
  1413.             mat.setMode(Blender.Material.Modes['SHADELESS'])
  1414.  
  1415.             # each material supports up to ten texture layters
  1416.             index = 0
  1417.             if isTextureValid(surfmat.basemap):
  1418.                 mat.setTexture(index, self.texlist[surfmat.basemap], Texture.TexCo.UV, Texture.MapTo.COL)
  1419.                 mattex = mat.getTextures()
  1420.                 mattex[index].uvlayer = 'uvmap_channel_' + str(surfmat.basemapchan)
  1421.                 index = index + 1
  1422.             if isTextureValid(surfmat.specmap):
  1423.                 mat.setTexture(index, self.texlist[surfmat.specmap], Texture.TexCo.UV, Texture.MapTo.SPEC)
  1424.                 mattex = mat.getTextures()
  1425.                 mattex[index].uvlayer = 'uvmap_channel_' + str(surfmat.specmapchan)
  1426.                 index = index + 1
  1427.             if isTextureValid(surfmat.normmap):
  1428.                 mat.setTexture(index, self.texlist[surfmat.normmap], Texture.TexCo.UV, Texture.MapTo.NOR)
  1429.                 mattex = mat.getTextures()
  1430.                 mattex[index].uvlayer = 'uvmap_channel_' + str(surfmat.normmapchan)
  1431.                 index = index + 1
  1432.  
  1433.             # append material
  1434.             self.materials.append(mat)
  1435.         
  1436.     # PRIVATE METHOD:
  1437.     def __buildMeshObjects(self):
  1438.  
  1439.         # save blender mesh objects
  1440.         self.meshlist = []
  1441.         
  1442.         # for each surface
  1443.         for surf in self.surfaces:
  1444.         
  1445.             self.__buildVBuffer(surf)
  1446.  
  1447.         return True
  1448.     
  1449.     def __buildArmatureObjects(self):
  1450.  
  1451.         # for each skeleton
  1452.         for skel in self.skeletons:
  1453.  
  1454.             # keep track of all root nodes
  1455.             root_nodes = []
  1456.             for jnt in skel.joints:
  1457.                 if jnt.parent == SMC.INVALID_JOINT:
  1458.                     root_nodes.append(jnt.id)
  1459.                     
  1460.             # must have at least one root node
  1461.             if len(root_nodes) == 0:
  1462.                 raise Exception('SMC Import Error: A skeleton was defined with no root node.')
  1463.                 
  1464.             # now that we know we have good root nodes, let's create a diction-
  1465.             # ary where given a joint ID we can index its data and find out how
  1466.             # many children joint IDs it has
  1467.             jntmap = {}
  1468.             for (jnt_index, jnt) in enumerate(skel.joints):
  1469.             
  1470.                 # joint identifier must be unique
  1471.                 if jnt.id in jntmap:
  1472.                     raise Exception('SMC Import Error: Joint identifiers must be unique.')
  1473.  
  1474.                 # insert joint to map with empty child list
  1475.                 jntmap[jnt.id] = [jnt_index, []]
  1476.             
  1477.             # insert joints into their parent's list of children
  1478.             for jnt in skel.joints:
  1479.                 if jnt.parent != SMC.INVALID_JOINT:
  1480.                     if not(jnt.parent in jntmap): raise Exception('SMC Import Error: Invalid parent joint identifier.')
  1481.                     jntmap[jnt.parent][1].append(jnt.id)
  1482.                     
  1483.             # create blender armature
  1484.             armature = Blender.Armature.New(skel.name)
  1485.             armature.drawType = Blender.Armature.STICK
  1486.             armature.envelopes = False
  1487.             armature.vertexGroups = False
  1488.  
  1489.             # create blender armature object
  1490.             scene = Blender.Scene.GetCurrent()
  1491.             armatureObjectName = skel.name + '_object'
  1492.             armatureObject = scene.objects.new(armature, armatureObjectName)
  1493.  
  1494.             # set armature object to use vertex groups (not envelopes)
  1495.             for meshobj in self.meshlist:
  1496.                 mod = meshobj.modifiers.append(Modifier.Types.ARMATURE)
  1497.                 mod[Blender.Modifier.Settings.OBJECT] = armatureObject
  1498.                 mod[Blender.Modifier.Settings.ENVELOPES] = False
  1499.                 mod[Blender.Modifier.Settings.VGROUPS] = True
  1500.     
  1501.             # make armature editable before adding bones
  1502.             armature.makeEditable()
  1503.  
  1504.             # traverse joints to add bones
  1505.             jvisitor = SMCJointVisitor(jntmap, skel, armature)
  1506.             for root in root_nodes: jvisitor.visit(root, None)
  1507.  
  1508.             # update armature
  1509.             armature.update()
  1510.             
  1511.             # parent mesh objects to armature so it can modify the meshes
  1512.             armatureObject.makeParent(self.meshlist)
  1513.             
  1514.         return True
  1515.  
  1516.     # PUBLIC METHOD: IMPORT
  1517.     def run(self, filename):
  1518.  
  1519.         # open file
  1520.         self.ifile = InputFileStream()
  1521.         self.ifile.open(filename)
  1522.         
  1523.         # file processing
  1524.         if self.__processSMCHeader() == False: return False
  1525.         if self.__processFileList() == False: return False
  1526.         if self.__processVBuffers() == False: return False
  1527.         if self.__processIBuffers() == False: return False
  1528.         if self.__processSurfmats() == False: return False
  1529.         if self.__processSurfaces() == False: return False
  1530.         if self.__processSkeleton() == False: return False
  1531.         if self.__processJointMap() == False: return False
  1532.         if self.__processAnimList() == False: return False
  1533.  
  1534.         # model construction
  1535.         self.__buildMeshTextures()
  1536.         self.__buildMeshMaterials()
  1537.         self.__buildMeshObjects()
  1538.         self.__buildArmatureObjects()
  1539.         
  1540.         # success
  1541.         print "SMC import successful."
  1542.         Window.RedrawAll()
  1543.         return True
  1544.  
  1545. #
  1546. # IMPORT SMC
  1547. #
  1548.  
  1549. def importSMC(filename):
  1550.  
  1551.     obj = SMCImporter()
  1552.     obj.run(filename)
  1553.  
  1554. #
  1555. # CONTROL EXECUTION
  1556. # main() is called if and only if module is not imported
  1557. #
  1558.  
  1559. def main():
  1560.  
  1561.     Blender.Window.FileSelector(importSMC, "Import SMC", '*.smc')
  1562.  
  1563. if __name__ == '__main__':
  1564.     
  1565.     main()