[QUESTION] ZMD File parse

This forum is for Graphics and 3D objects discussions.

Moderators: osRose dev team, ospRose dev team, osiRose dev team, Moderators

Forum rules
Client Editing is a delicate subject. osRose and osiRose will not support or use any Client Editing tool or results as a standard. So you are free to experiment, test, and develop there on Client Editing, but at your own risk

Re: [QUESTION] ZMD File parse

Postby cssvb94 on Tue Nov 11, 2008 5:57 pm

Thanks to Imame's work, now the the script imports ZMD files as it should.
I removed the euclid and math module dependency using only Blender's in-built functions.
Next step will be creating the bones instead 'Empty' objects.
Once more, thank you Imame. This work is a good example of team work in some form.
Here is the code itself:
place it into C:\Program Files\Blender Fondation\.blender\scripts\import_zmd_bin.py
When you start Blender new menu item should appear "RoseOnline ZMD binary File Format (.zmd)..."

  1.  
  2. #!BPY
  3. """
  4. Name: 'RoseOnline ZMD binary File Format (.zmd)...'
  5. Blender: 248
  6. Group: 'Import'
  7. Tooltip: 'Import RoseOnline binary ZMD file format (.zmd)'
  8. """
  9.  
  10. __author__= ['Spark', 'Imame']
  11. __url__ = ("http://forum.dev-osrose.com")
  12. __version__= '0.0.7'
  13. __bpydoc__= '''\
  14.  
  15. 0.0.7:
  16. Spark: 11/11/2008
  17. -> Works perfectly! =)
  18. -> Replaced euclid module with Blender.Mathutils, removed external modules dependency
  19. -> Removed math module
  20. -> Some cleanup of the code
  21.  
  22. 0.0.6:
  23. lmame:
  24. -> math attack time ^_^, seems to getting better now,
  25.  
  26. 0.0.5:
  27. lmame:
  28. -> added the i==0 from 0.0.3
  29. -> quaternion is calculated 'manually', same for mats multiplication and rot matrix (if needed),
  30. -> two formula for quaternion exist,
  31.  
  32. 0.0.4:
  33. Spark
  34. -> Cleanup
  35. -> Empty objects instead of cubes
  36.  
  37. 0.0.3:
  38. lmame:
  39. -> test of a new way, works not perfectly...
  40.  
  41. 0.0.2:
  42. lmame:
  43. -> added a "load file stuff",
  44. -> Just changed a stuff in the read vector (format was z,y,x instead of x,y,z),
  45.  
  46. 0.0.1
  47. -> Spark initial release,
  48. '''
  49.  
  50. import struct
  51. import Blender
  52. from Blender.Mesh.Primitives import *
  53. from Blender.Mathutils import *
  54. from Blender import Scene, Object
  55.  
  56. class zmdHeaderObject:
  57.  
  58.   def __init__(self):
  59.     self.binaryFormat = "<7ci"
  60.     self.format = ''
  61.     self.boneCount = 0
  62.  
  63.   def load(self, file):
  64.     tmpData = file.read(struct.calcsize(self.binaryFormat))
  65.     data = struct.unpack(self.binaryFormat, tmpData)
  66.     self.format = ''.join(data[0:7])
  67.     self.boneCount = data[7] #~ DWORD = 4 bytes
  68.     return self
  69.  
  70.   def __repr__(self):
  71.     return "Format:\t%s\tBones:\t%d" % (self.format, self.boneCount)
  72.  
  73. class zmdBoneObject:
  74.  
  75.     def __init__(self, ID):
  76.         self.binaryFormat = "<7f"
  77.         self.parentID = 0
  78.         self.quaternion = Quaternion()
  79.         self.matrix = Matrix()
  80.         self.ID = ID
  81.         self.name = ''
  82.         self.parentName = 'NONE'
  83.  
  84.     def readName(self, file):
  85.         #~ Reads byte by byte until \0x00, i.e cstr
  86.         bname = ''
  87.         while True:
  88.             tmpData = file.read(1)
  89.             if tmpData[0] == chr(0): break
  90.             bname = bname + tmpData
  91.         return bname
  92.  
  93.     def readParentID(self, file):
  94.         tmpData = file.read(struct.calcsize('i'))
  95.         return struct.unpack('i', tmpData)[0]
  96.  
  97.     def load(self, file):
  98.         self.parentID = self.readParentID(file)
  99.         self.name = self.readName(file)
  100.  
  101.         tmpData = file.read(struct.calcsize(self.binaryFormat))
  102.         data = struct.unpack(self.binaryFormat, tmpData)
  103.  
  104.         #~ Vector(x, z, y)
  105.         self.co = Vector(data[0], data[2], data[1]) / 100.0
  106.  
  107.         #~ Quaternion(w, x, z, y)
  108.         self.quaternion.w = data[3]
  109.         self.quaternion.x = data[4]
  110.         self.quaternion.z = data[5]
  111.         self.quaternion.y = data[6]
  112.  
  113.         #~ Blender way
  114.         self.matrix = self.quaternion.toMatrix()
  115.         return self
  116.  
  117.  
  118.     def __repr__(self):
  119.         return 'Bone %d name: "%s" \tparendBoneID: %d\tparentName: "%s"\n' % (self.ID, self.name, self.parentID, self.parentName) + \
  120.     'Coord:\t\t Vector(%.4f, %.4f, %.4f)\n' % tuple(self.co)  + \
  121.     'Rotation:\t Quaternion(%.4f, %.4f, %.4f, %.4f)\n' % (self.quaternion.w, self.quaternion.x, self.quaternion.y, self.quaternion.z)
  122.  
  123. #~ Loading file procedure.
  124. def load_zmd(filename):
  125.     Blender.Window.WaitCursor(1)
  126.  
  127.     #~ Loading file procedure.
  128.     binaryDummyFormat = "<i"
  129.  
  130.     #~ Open a binary file
  131.     file = open(filename,"rb")
  132.  
  133.     zmd = zmdHeaderObject()
  134.     zmd.load(file)
  135.  
  136.  
  137.     #~ Empty dictionary
  138.     bones = {}
  139.  
  140.     #~ Read and transform each bone position
  141.     print "\n\nReading %s ..." % filename
  142.     print zmd
  143.     for i in range(zmd.boneCount):
  144.         zbone = zmdBoneObject(i)
  145.         #~ Read bone
  146.         zbone.load(file)
  147.  
  148.         print "%s \t=\t Vector(%.6f, %.6f, %.6f)" % (zbone.name, zbone.co.x, zbone.co.y, zbone.co.z)
  149.  
  150.         #~ Apply the calculations only for bones after the root one, index > 0
  151.         if i > 0:
  152.             #~ Set parent's name
  153.             zbone.parentName = bones[zbone.parentID].name
  154.             #~ Calculate new absolute coordinates
  155.             v_result = bones[zbone.parentID].matrix * zbone.co + bones[zbone.parentID].co
  156.             #~ Update the matrix, local -> world
  157.             zbone.matrix = bones[zbone.parentID].matrix * zbone.matrix
  158.             #~ Quaternion is not used, but to preserve the conversion chain
  159.             zbone.quaternion = zbone.matrix.toQuat()
  160.             zbone.co = v_result
  161.         #~ Add bone to the dictionary
  162.         bones[i] = zbone
  163.  
  164.     #~ End of reading, close the file
  165.     file.close()
  166.     #~ Free some memory
  167.     del file, zbone, zmd
  168.  
  169.     print "\nCreating bones ..."
  170.     #~  Put some cubes instead bones
  171.     sc = Blender.Scene.GetCurrent()
  172.  
  173.     #~ Read bone dictionary and create dummy cubes instead of bones for a test purpose
  174.     #~ TODO: Create Bones objects instead Dummy objects
  175.     for i, bone in enumerate(bones.values()):
  176.         #~ Create dummy object
  177.         obj = Object.New("Empty", bone.name)
  178.         #~ Show name beside
  179.         obj.drawMode = obj.drawMode | 8
  180.         #~ Cube shape = 5
  181.         obj.emptyShape = 5
  182.         obj.size = (0.0125, 0.0125, 0.0125)
  183.  
  184.          #~ Put/link the object with the scene
  185.         sc.objects.link(obj)
  186.  
  187.         #~ All generated objects will appear already selected - much easier to zoom into them - use "." from NUM PAD to zoom on selected !
  188.         obj.sel = True
  189.         #~ Set the position
  190.         obj.LocX = bone.co[0]
  191.         obj.LocY = bone.co[1]
  192.         obj.LocZ = bone.co[2]
  193.  
  194.         #~ Next part creates parent <-> child connection, not necessary, but visual feedback =)
  195.         if i > 0:
  196.             parent_obj = Blender.Object.Get(bone.parentName)
  197.             parent_obj.makeParent([obj])
  198.  
  199.     #~  Refresh the views
  200.     Blender.Window.RedrawAll()
  201.  
  202.     #~ Clean up used memory
  203.     del sc, bones, parent_obj, bone, i
  204.  
  205.     Blender.Window.WaitCursor(0)
  206.     print "\nDone"
  207.  
  208. #~ Loading a ZMD file.
  209. if __name__=='__main__':
  210.     Blender.Window.FileSelector(load_zmd, 'Import RoseOnline ZMD', '*.zmd')
  211.  


Enjoy, test and report the bugs here.
aka Spark (ZMSViewer, Blender ZMS plug-in, RoseOnline ZMS/ZMD/ZMO to SMD and vice versa converter)
User avatar
cssvb94
Pomic
Pomic
 
Posts: 109
Joined: Thu May 01, 2008 7:22 am
Location: GMT +1

Re: [QUESTION] ZMD File parse

Postby lmame on Tue Nov 11, 2008 6:01 pm

Nice :D
It was a pleasure :lol: let's say it was the first experience in 3D import stuff :)
The world is full of love and peace ^_^
Image
User avatar
lmame
Admin
Admin
 
Posts: 8997
Joined: Mon Aug 06, 2007 4:42 pm
Location: July City

Re: [QUESTION] ZMD File parse

Postby cssvb94 on Thu Nov 13, 2008 12:28 pm

Update:
Version 0.0.8:
Script creates Armature/Bones instead just dummy objects.
Alligator_ArmatureObject.jpg
Alligator ZMD - Armature/Bones

filename: import_bin_zmd.py
  1. #!BPY
  2. """
  3. Name: 'RoseOnline ZMD binary File Format (.zmd)...'
  4. Blender: 248
  5. Group: 'Import'
  6. Tooltip: 'Import RoseOnline binary ZMD file format (.zmd)'
  7. """
  8.  
  9. __author__= ['Spark', 'lmame']
  10. __url__ = ("http://forum.dev-osrose.com")
  11. __version__= '0.0.8'
  12. __bpydoc__= '''\
  13.  
  14. 0.0.8:
  15. Spark @ 13/11/2008
  16. -> 'Empty' objects replaced with Armature/Bones
  17.  
  18. 0.0.7:
  19. Spark @ 11/11/2008
  20. -> Works perfectly! =)
  21. -> Replaced euclid module with Blender.Mathutils, removed external modules dependency
  22. -> Removed math module
  23. -> Some cleanup of the code
  24.  
  25. 0.0.6:
  26. lmame:
  27. -> math attack time ^_^, seems to getting better now
  28.  
  29. 0.0.5:
  30. lmame:
  31. -> added the i==0 from 0.0.3
  32. -> quaternion is calculated 'manually', same for mats multiplication and rot matrix (if needed)
  33. -> two formula for quaternion exist
  34.  
  35. 0.0.4:
  36. Spark
  37. -> Cleanup
  38. -> Empty objects instead of cubes
  39.  
  40. 0.0.3:
  41. lmame:
  42. -> test of a new way, works not perfectly...
  43.  
  44. 0.0.2:
  45. lmame:
  46. -> added a "load file stuff"
  47. -> Just changed a stuff in the read vector (format was z,y,x instead of x,y,z)
  48.  
  49. 0.0.1
  50. -> Spark initial release
  51. '''
  52.  
  53. import struct
  54. import Blender
  55. from Blender.Mesh.Primitives import *
  56. from Blender.Mathutils import *
  57. from Blender import Scene, Object, Armature
  58.  
  59. class zmdHeaderObject:
  60.  
  61.     def __init__(self):
  62.         self.binaryFormat = "<7ci"
  63.         self.format = ''
  64.         self.boneCount = 0
  65.  
  66.     def load(self, file):
  67.         tmpData = file.read(struct.calcsize(self.binaryFormat))
  68.         data = struct.unpack(self.binaryFormat, tmpData)
  69.         self.format = ''.join(data[0:7])
  70.         if self.format[0:3] != 'ZMD':
  71.             file.close()
  72.             raise ValueError('Not a ZMD file!\n')
  73.         else:
  74.             self.boneCount = data[7] #~ DWORD = 4 bytes
  75.             return self
  76.  
  77.     def __repr__(self):
  78.         return "Format:\t%s\tBones:\t%d" % (self.format, self.boneCount)
  79.  
  80. class zmdBoneObject:
  81.  
  82.     def __init__(self, ID):
  83.         self.binaryFormat = "<7f"
  84.         self.parentID = 0
  85.         self.quaternion = Quaternion()
  86.         self.matrix = Matrix()
  87.         self.ID = ID
  88.         self.name = ''
  89.         self.parentName = 'NONE'
  90.  
  91.     def readName(self, file):
  92.         #~ Reads byte by byte until \0x00, i.e cstr
  93.         bname = ''
  94.         while True:
  95.             tmpData = file.read(1)
  96.             if tmpData[0] == chr(0): break
  97.             bname = bname + tmpData
  98.         return bname
  99.  
  100.     def readParentID(self, file):
  101.         tmpData = file.read(struct.calcsize('i'))
  102.         return struct.unpack('i', tmpData)[0]
  103.  
  104.     def load(self, file):
  105.         self.parentID = self.readParentID(file)
  106.         self.name = self.readName(file)
  107.  
  108.         tmpData = file.read(struct.calcsize(self.binaryFormat))
  109.         data = struct.unpack(self.binaryFormat, tmpData)
  110.  
  111.         #~ Vector(x, z, y)
  112.         self.co = Vector(data[0], data[2], data[1]) / 100.0
  113.  
  114.         #~ Quaternion(w, x, z, y)
  115.         self.quaternion = Quaternion( data[3], data[4], data[6], data[5] )
  116.  
  117.         #~ Blender way
  118.         self.matrix = self.quaternion.toMatrix()
  119.         return self
  120.  
  121.  
  122.     def __repr__(self):
  123.         return 'Bone #%d "%s" \tParent: #%d "%s"\n' % (self.ID, self.name, self.parentID, self.parentName) + \
  124.     'Coord:\t\t Vector(%.4f, %.4f, %.4f)\n' % tuple(self.co)  + \
  125.     'Rotation:\t Quaternion(%.4f, %.4f, %.4f, %.4f)\n' % (self.quaternion.w, self.quaternion.x, self.quaternion.y, self.quaternion.z)
  126.  
  127. #~ Loading file procedure.
  128. def load_zmd(filename):
  129.     Blender.Window.WaitCursor(1)
  130.  
  131.     #~ Loading file procedure.
  132.     binaryDummyFormat = "<i"
  133.  
  134.     #~ Open a binary file
  135.     file = open(filename,"rb")
  136.  
  137.     zmd = zmdHeaderObject()
  138.     zmd.load(file)
  139.  
  140.  
  141.     #~ Empty dictionary
  142.     bones = {}
  143.  
  144.     #~ Read and transform each bone position
  145.     print "\n\nParsing '%s' ...\n" % filename
  146.     print zmd
  147.     for i in range(zmd.boneCount):
  148.         zbone = zmdBoneObject(i)
  149.         #~ Read bone
  150.         zbone.load(file)
  151.         #~ Apply the calculations only for bones after the root one, index > 0
  152.         if i > 0:
  153.             #~ Set parent's name
  154.             zbone.parentName = bones[zbone.parentID].name
  155.             #~ Calculate new absolute coordinates
  156.             v_result = bones[zbone.parentID].matrix * zbone.co + bones[zbone.parentID].co
  157.             #~ Update the matrix, local -> world
  158.             zbone.matrix = bones[zbone.parentID].matrix * zbone.matrix
  159.             #~ Quaternion is not used, but to preserve the conversion chain
  160.             zbone.quaternion = zbone.matrix.toQuat()
  161.             zbone.co = v_result
  162.         #~ Add bone to the dictionary
  163.         bones[i] = zbone
  164.         #~ print zbone
  165.  
  166.     #~ End of reading, close the file
  167.     file.close()
  168.     #~ Free some memory
  169.     del file, zbone, zmd
  170.  
  171.     sc = Blender.Scene.GetCurrent()
  172.  
  173.     #~ *************************** Armature ***************************
  174.  
  175.     #~ Armature name is generated from the file name
  176.     name = filename.split('/')[-1].split('\\')[-1].split('.')[0]
  177.     print "\n\nCreating armature '%s' ...\n" % name
  178.  
  179.     #~ Create Armature
  180.     arm_data = Armature.New(name)
  181.     #~ Set view options
  182.     arm_data.drawNames = True
  183.     arm_data.drawType = Armature.STICK
  184.     #~ IK is set to Auto for now!
  185.     arm_data.autoIK = True
  186.  
  187.     #~ Create scene armature object
  188.     arm_obj = sc.objects.new(arm_data)
  189.     arm_obj.drawMode = Object.DrawModes.NAME
  190.     arm_obj.sel = True
  191.     #~ Set edit mode to add bones
  192.     arm_data.makeEditable()
  193.  
  194.     for i, bone in enumerate(bones.values()):
  195.         #~ Create new bone
  196.         ebone = Armature.Editbone()
  197.         #~ Set bone name
  198.         ebone.name = bone.name
  199.         #~ Set coordinates
  200.         #~ Blender bone requires tail/head coordinates.
  201.         #~ Only tail coordinate should be used when export!
  202.         ebone.tail = bone.co
  203.         if i == 0 :
  204.             vcopy = bone.co.copy()
  205.             vcopy.y -= 0.05
  206.             ebone.head = vcopy
  207.             ebone.options = [Armature.HINGE, Armature.BONE_SELECTED]
  208.         else:
  209.             ebone.head = bones[bone.parentID].co
  210.             #~ Set the relationship
  211.             ebone.parent = arm_data.bones[bone.parentName]
  212.             ebone.options = [Armature.HINGE, Armature.CONNECTED, Armature.BONE_SELECTED]
  213.  
  214.         #~ Atach bone to the armature
  215.         arm_data.bones[ebone.name] = ebone
  216.     #~ Refresh
  217.     arm_data.update()
  218.  
  219.     #~ *************************** Armature ***************************
  220.  
  221.     #~  Refresh the views
  222.     Blender.Window.RedrawAll()
  223.  
  224.     #~ Be nice and clean up used memory
  225.     del sc, bones, bone, i
  226.  
  227.     Blender.Window.WaitCursor(0)
  228.     print "\nDone."
  229.  
  230. #~ Loading a ZMD file.
  231. if __name__=='__main__':
  232.     Blender.Window.FileSelector(load_zmd, 'Import RoseOnline ZMD', '*.zmd')
  233.  
aka Spark (ZMSViewer, Blender ZMS plug-in, RoseOnline ZMS/ZMD/ZMO to SMD and vice versa converter)
User avatar
cssvb94
Pomic
Pomic
 
Posts: 109
Joined: Thu May 01, 2008 7:22 am
Location: GMT +1

Re: [QUESTION] ZMD File parse

Postby lmame on Thu Nov 13, 2008 12:59 pm

Nice work :D
The world is full of love and peace ^_^
Image
User avatar
lmame
Admin
Admin
 
Posts: 8997
Joined: Mon Aug 06, 2007 4:42 pm
Location: July City

Re: [QUESTION] ZMD File parse

Postby blazerx on Wed Dec 31, 2008 10:01 pm

this really rocks guys but ive done everything as in putting it in the scripts and all that and changed the filename to what u listed (import_bin_zmd) but it still doesnt seem to show when i go to file>import so it just doesnt give me the option to import any zmd because of that, it might be a newby question but i was wondering if you could tell me how to fix that?
blazerx
Jelly Bean
Jelly Bean
 
Posts: 16
Joined: Wed Dec 03, 2008 10:23 pm

Re: [QUESTION] ZMD File parse

Postby lmame on Wed Dec 31, 2008 11:59 pm

import_bin_zmd.py don't forget the .py extension.
The world is full of love and peace ^_^
Image
User avatar
lmame
Admin
Admin
 
Posts: 8997
Joined: Mon Aug 06, 2007 4:42 pm
Location: July City

Re: [QUESTION] ZMD File parse

Postby blazerx on Fri Jan 02, 2009 4:05 am

ok thanks :D i fixed that problem but now that im at it i want to try to create a set in rose and i already have one made but (pretty obviously) bones are my problem because of the missing bones bug, but basicly i want to know if this would help me in the matter of getting the bone problem out of the way? and am i on the right track now that i have this? if i am, yay :D

(im sorry if this is sort of the wrong place to ask but if it is tell me so i dont make the same mistake again)
blazerx
Jelly Bean
Jelly Bean
 
Posts: 16
Joined: Wed Dec 03, 2008 10:23 pm

Re: [QUESTION] ZMD File parse

Postby lmame on Fri Jan 02, 2009 11:06 am

Yeah you should make another thread for that :)
The world is full of love and peace ^_^
Image
User avatar
lmame
Admin
Admin
 
Posts: 8997
Joined: Mon Aug 06, 2007 4:42 pm
Location: July City

Re: [QUESTION] ZMD File parse

Postby mini on Fri Jul 10, 2009 1:39 pm

EDIT:
Downloaded the ZIP and it worked :D
mini
Pomic
Pomic
 
Posts: 100
Joined: Mon Mar 23, 2009 9:18 am

Re: [QUESTION] ZMD File parse

Postby larsgevers on Wed Oct 21, 2009 10:31 pm

I have a question too, when i tried to export is to .3ds, and open it in 3ds max. Then it says that there is nothing in it. I don't see anything? :S
User avatar
larsgevers
Rackie
Rackie
 
Posts: 278
Joined: Fri Mar 20, 2009 2:10 pm

PreviousNext

Return to 3D discussions

Who is online

Users browsing this forum: No registered users and 3 guests