I'm currently working in another thread to find a better conversion method

here's my script:

#!BPY
""" 
Name: 'Brawl (.mdl0)...'
Blender: 248
Group: 'Import'
Tooltip: 'Import a Brawl model file (.mdl0)'
"""
__author__= ['Tcll']
__url__ = ("")
__version__= '0.015'
__bpydoc__= '''\
mdl0 Importer
'''
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Script copyright (C) Bob Holcomb 
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
# Importing modules

import struct as S
import Blender

def HexToDec(n):
	return float(S.unpack("<h", S.pack("<H", int((n.encode('hex')), 16)))[0])

def readvert(v):
	x, y, z = (HexToDec(mdl0.read(2))* 0.001), (HexToDec(mdl0.read(2))* 0.001), (HexToDec(mdl0.read(2))* 0.001)
	v = v - 1
	return x, y, z
	
			

def import_mdl0(path):
	Blender.Window.WaitCursor(1)
	name = path.split('\\')[-1].split('/')[-1]
	mesh = Blender.NMesh.New( name ) # create a new mesh
	# parse the file
	mdl0 = open(path, 'rb')
	
	if (mdl0.read(4).__str__() == "MDL0"):#MDL0 Magic
		print "mdl0 is vald"
		
		h02 = mdl0.read(4) #0x04(4)		MDL0 Size
		h03 = mdl0.read(4) #0x08(4)		Sections
		h04 = mdl0.read(4) #0x0C(4)		Model Nodes Offset
		h05 = mdl0.read(4) #0x10(4)		Definitions List
		h06 = mdl0.read(4) #0x14(4)		Bones List
		h07 = mdl0.read(4) #0x18(4)		Vertices List
		h08 = mdl0.read(4) #0x1C(4)		Normals List
		h09 = mdl0.read(4) #0x20(4)		Colors List
		h10 = mdl0.read(4) #0x24(4)		UV Points List
		h11 = mdl0.read(4) #0x28(4)		Materials 1 List
		h12 = mdl0.read(4) #0x2C(4)		Materials 2 List
		h13 = mdl0.read(4) #0x30(4)		Polygons List
		h14 = mdl0.read(4) #0x34(4)		Textures 1 List
		h15 = mdl0.read(4) #0x38(4)		Textures 2 List
		h16 = mdl0.read(4) #0x3C(4)		Model Name Offset
		h17 = mdl0.read(4) #0x40(4)		Header Length
		h18 = mdl0.read(4) #0x44(4)		Header Offset
		h19 = mdl0.read(4) #0x48(4)		Unknown 1
		h20 = mdl0.read(4) #0x4C(4)		Unknown 2
		h21 = mdl0.read(4) #0x50(4)		# of Vertices
		h22 = mdl0.read(4) #0x54(4)		# of Faces
		h23 = mdl0.read(4) #0x58(4)		Unknown 3
		h24 = mdl0.read(4) #0x5C(4)		# of Nodes
		h25 = mdl0.read(4) #0x60(4)		Version
		h26 = mdl0.read(2) #0x62(2)		Unknown 4
		h27 = mdl0.read(2) #0x64(2)		Unknown 5
		h28 = mdl0.read(4) #0x68(4)		Box Min. X
		h29 = mdl0.read(4) #0x6C(4)		Box Min. Y
		h30 = mdl0.read(4) #0x70(4)		Box Min. Z
		h31 = mdl0.read(4) #0x74(4)		Box Max. X
		h32 = mdl0.read(4) #0x78(4)		Box Max. Y
		h33 = mdl0.read(4) #0x7C(4)		Box Max. Z
		h34 = mdl0.read(4) #0x80(4)		# of Nodes (Copy?)
		
		a = 0
		while(a==0):
			x, y, z = (HexToDec(mdl0.read(2))* 0.001), (HexToDec(mdl0.read(2))* 0.001), (HexToDec(mdl0.read(2))* 0.001)
			v = "v "+(x).__str__()+" "+(y).__str__()+" "+(z).__str__()
			if (v == 'v 0.0 0.0 0.0'):
				a = 1
			mesh.verts.append(Blender.NMesh.Vert(x, y, z))

	else:
		print "file is not in mdl0 fomat"
		mdl0.close()
	

	# link the mesh to a new object
	ob = Blender.Object.New('Mesh', name) # Mesh must be spelled just this--it is a specific type
	ob.link(mesh) # tell the object to use the mesh we just made
	scn = Blender.Scene.GetCurrent()
	for o in scn.getChildren():
		o.sel = 0
	scn.link(ob) # link the object to the current scene
	ob.sel= 1
	ob.Layers = scn.Layers
	Blender.Window.WaitCursor(0)
	Blender.Window.RedrawAll()
Blender.Window.FileSelector(import_mdl0, 'Import')

I'm afraid this doesn't work correctly at the moment...

here's what I use to test the verts:

#!BPY
""" 
Name: 'Brawl (.mdl0)...'
Blender: 248
Group: 'Import'
Tooltip: 'Import a Brawl model file (.mdl0)'
"""
__author__= ['Tcll']
__url__ = ("")
__version__= '0.015'
__bpydoc__= '''\
mdl0 Importer
'''
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Script copyright (C) Bob Holcomb 
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
# Importing modules

import struct as S
import Blender

def HexToDec(n):
	h = float(S.unpack("<h", S.pack("<H", int((n.encode('hex')), 16)))[0])
#	while (h > 127): # uncomment this code for better results:
#		h = h*(1/256)
		
	return h


def import_mdl0(path):
	Blender.Window.WaitCursor(1)
	name = path.split('\\')[-1].split('/')[-1]
	mesh = Blender.NMesh.New( name ) # create a new mesh
	# parse the file
	mdl0 = open(path, 'rb')
	

	a = 0
	while(a==0):
		x, y, z = (HexToDec(mdl0.read(2))* 0.001), (HexToDec(mdl0.read(2))* 0.001), (HexToDec(mdl0.read(2))* 0.001)
		v = "v "+(x).__str__()+" "+(y).__str__()+" "+(z).__str__()
		if (v == 'v 0.0 0.0 0.0'):
			a = 1
		mesh.verts.append(Blender.NMesh.Vert(x, y, z))

	

	# link the mesh to a new object
	ob = Blender.Object.New('Mesh', name) # Mesh must be spelled just this--it is a specific type
	ob.link(mesh) # tell the object to use the mesh we just made
	scn = Blender.Scene.GetCurrent()
	for o in scn.getChildren():
		o.sel = 0
	scn.link(ob) # link the object to the current scene
	ob.sel= 1
	ob.Layers = scn.Layers
	Blender.Window.WaitCursor(0)
	Blender.Window.RedrawAll()
Blender.Window.FileSelector(import_mdl0, 'Import')

the commented code shows you all the verts (jumbled),
image:
while uncommenting it shows you about 10 verts (clean).
image:

export a vert selection from an mdl0 file with Brawlbox, and impoort that file...
(make sure to add about 2 lines of '00' to the end of the file in a hex editor before importing)

the attatchment below is not a pdf file
it's the vert export I used
import directly into blender
(zero's are already added)

Dani AI

Generated

Nice start, . The big issue behind your “jumbled vs clean” verts isn’t the math loop, it’s that MDL0 vertex streams carry their own format and scale. In Section 2 (Vertices), the header stores ComponentCount (XY vs. XYZ), Format (UInt8/Int8/UInt16/Int16/Float), Divisor, Stride, VertexCount, and DataOffset. For non-float data you must divide by 2^Divisor; hardcoding 1/256 will only be correct when Divisor==8. Also, use VertexCount instead of scanning until you hit a 0,0,0 sentinel. See the MDL0 spec notes for Section 2 fields and the Divisor rule. MDL0 file format.

Python tips that build on and ’s feedback:

  • In Blender 2.49 (compiled with Python 2.6.x), integer division of ints is truncating. Either import true division or divide by a float literal. PEP 238. Blender 2.49/Python 2.6 evidence.
  • Skip encode('hex'); unpack directly with struct and little-endian codes like '<h' (signed 16-bit). struct docs.

Minimal reader for one vertex stream (Python 2.6-friendly):

from __future__ import division
import struct as S

def read_vertices(f, vsec_off):
    f.seek(vsec_off)
    f.read(0x08)                    # skip len, MDL0 offset
    data_off = S.unpack('<i', f.read(4))[0]
    f.read(4)                       # name offset
    idx = S.unpack('<I', f.read(4))[0]
    comp = S.unpack('<I', f.read(4))[0]     # 0=XY, 1=XYZ
    fmt  = S.unpack('<I', f.read(4))[0]     # 0..4 per spec
    div, stride = S.unpack('<BB', f.read(2))
    count = S.unpack('<H', f.read(2))[0]

    code_size = {0:('<B',1), 1:('<b',1), 2:('<H',2), 3:('<h',2), 4:('<f',4)}[fmt]
    code, size = code_size
    scale = 1.0 if fmt == 4 else float(1 << div)

    f.seek(vsec_off + data_off)
    verts = []
    for _ in range(count):
        x = S.unpack(code, f.read(size))[0] / scale
        y = S.unpack(code, f.read(size))[0] / scale
        z = S.unpack(code, f.read(size))[0] / scale if comp == 1 else 0.0
        verts.append((x, y, z))
    return verts

Practical checks:

  • If your export only contains the vertices block, call read_vertices(f, 0).
  • Confirm byte order is little-endian and that offsets are file-relative for this section, as documented. MDL0 file format.

Recommended Answers

All 21 Replies

I have some comments on your code.

import struct as S
import Blender

def HexToDec(n):
	#return float(S.unpack("<h", S.pack("<H", int((n.encode('hex')), 16)))[0])
	#jcao219:  please keep lines short, so it is readable
	nhex = int(n.encode('hex'), 16)
	packed = S.pack("<H", nhex)
	unpacked = S.unpack("<h", packed)[0]
	return float(unpacked)

def readvert(v):  #jcao219:where do you use this function?
	#jcao219: ideally, you should have    def readvert(v, mdl0):
	x, y, z = HexToDec(mdl0.read(2))* 0.001, HexToDec(mdl0.read(2))* 0.001, HexToDec(mdl0.read(2))* 0.001
	v = v - 1  #jcao219: changing v here doesn't do anything... this is too C-like
	return x, y, z
	
	#jcao219: name mdl0 doesn't exist

def import_mdl0(path):
	Blender.Window.WaitCursor(1)
	name = path.split('\\')[-1].split('/')[-1]  #jcao219:i'm not sure what you are doing here
	mesh = Blender.NMesh.New( name ) # create a new mesh
	# parse the file
	mdl0 = open(path, 'rb')
	
	if (mdl0.read(4) == "MDL0"):#MDL0 Magic  jcao219: no need for str()
		print "mdl0 is valid"
		
		h02 = mdl0.read(4) #0x04(4)		MDL0 Size
		h03 = mdl0.read(4) #0x08(4)		Sections
		h04 = mdl0.read(4) #0x0C(4)		Model Nodes Offset
		h05 = mdl0.read(4) #0x10(4)		Definitions List
		h06 = mdl0.read(4) #0x14(4)		Bones List
		h07 = mdl0.read(4) #0x18(4)		Vertices List   jcao219: these are pointers?
		h08 = mdl0.read(4) #0x1C(4)		Normals List
		h09 = mdl0.read(4) #0x20(4)		Colors List
		h10 = mdl0.read(4) #0x24(4)		UV Points List
		h11 = mdl0.read(4) #0x28(4)		Materials 1 List
		h12 = mdl0.read(4) #0x2C(4)		Materials 2 List
		h13 = mdl0.read(4) #0x30(4)		Polygons List
		h14 = mdl0.read(4) #0x34(4)		Textures 1 List
		h15 = mdl0.read(4) #0x38(4)		Textures 2 List
		h16 = mdl0.read(4) #0x3C(4)		Model Name Offset
		h17 = mdl0.read(4) #0x40(4)		Header Length
		h18 = mdl0.read(4) #0x44(4)		Header Offset
		h19 = mdl0.read(4) #0x48(4)		Unknown 1
		h20 = mdl0.read(4) #0x4C(4)		Unknown 2
		h21 = mdl0.read(4) #0x50(4)		# of Vertices
		h22 = mdl0.read(4) #0x54(4)		# of Faces
		h23 = mdl0.read(4) #0x58(4)		Unknown 3
		h24 = mdl0.read(4) #0x5C(4)		# of Nodes
		h25 = mdl0.read(4) #0x60(4)		Version
		h26 = mdl0.read(2) #0x62(2)		Unknown 4
		h27 = mdl0.read(2) #0x64(2)		Unknown 5
		h28 = mdl0.read(4) #0x68(4)		Box Min. X
		h29 = mdl0.read(4) #0x6C(4)		Box Min. Y
		h30 = mdl0.read(4) #0x70(4)		Box Min. Z
		h31 = mdl0.read(4) #0x74(4)		Box Max. X
		h32 = mdl0.read(4) #0x78(4)		Box Max. Y
		h33 = mdl0.read(4) #0x7C(4)		Box Max. Z
		h34 = mdl0.read(4) #0x80(4)		# of Nodes (Copy?)
		
		a = 0
		while not a:  #jcao219: this is a better way to write the code
			x, y, z = HexToDec(mdl0.read(2))* 0.001, HexToDec(mdl0.read(2))* 0.001, HexToDec(mdl0.read(2))* 0.001
			v = "v "+str(x)+" "+str(y)+" "+str(z)  #never call magic methods directly! use str()
			if (v == 'v 0.0 0.0 0.0'):
				a = 1
			mesh.verts.append(Blender.NMesh.Vert(x, y, z))

	else:
		print "file is not in mdl0 fomat"
	mdl0.close()  #jcao219: always close!
	

	# link the mesh to a new object
	ob = Blender.Object.New('Mesh', name) # Mesh must be spelled just this--it is a specific type
	ob.link(mesh) # tell the object to use the mesh we just made
	scn = Blender.Scene.GetCurrent()
	for o in scn.getChildren():
		o.sel = 0
	scn.link(ob) # link the object to the current scene
	ob.sel= 1
	ob.Layers = scn.Layers
	Blender.Window.WaitCursor(0)
	Blender.Window.RedrawAll()
Blender.Window.FileSelector(import_mdl0, 'Import')

Also,

h = h * (1/256)

just zeros h.
Why do you want that?

the readvert function is not used yet...
it was an update to be used for later...

as for the h thing
try this:

def HexToDec(n):
	h = float(S.unpack("<h", S.pack("<H", int((n.encode('hex')), 16)))[0])
	while (h > 127): # uncomment this code for better results:
		h = h*(1/256)
 	return h

this takes vert offsets > 127 and multiplies them by (1/256)

sry my code is such a mess...
I'm not the best of programmers yet...

that was the code that works perfectly on Melee's dat files

the readvert function is not used yet...
it was an update to be used for later...

as for the h thing
try this:

def HexToDec(n):
	h = float(S.unpack("<h", S.pack("<H", int((n.encode('hex')), 16)))[0])
	while (h > 127): # uncomment this code for better results:
		h = h*(1/256)
 	return h

I assume you are using python 2 because str.encode('hex') only works for 2.
in that case, 1/256 = 0 and 0*h makes h 0.

sry...
was editing my comment when you posted...
have you even tried blender?
I'll try your script in blender and see how that works...

sry...
was editing my comment when you posted...
have you even tried blender?
I'll try your script in blender and see how that works...

okay, i'll assume that Blender uses Python 2.x but makes divisions convert to float.

You should probably do h /= 256 instead, which is the same but more concise.

okay, i'll assume that Blender uses Python 2.x but makes divisions convert to float.

You should probably do h /= 256 instead, which is the same but more concise.

blender 2.49b uses 2.6

and thanx :D
could never understand that until recently...

btw, your code works :D
but no differant from mine really :/

EDIT:
I deleted that readvert function, now realizing it won't work...

I'm just curious, what are you working on right now?

the title says it all :P

You should probably do h /= 256 instead, which is the same but more concise.

overlooked this last time...

you mean: h *= (1/256)

overlooked this last time...

you mean: h *= (1/256)

h = 0 would be more concise in Python 2. Or do you mean h /= 256.0 ?
Or are you making something, which should use divmod?

(1 / 256)*h = (0.00390625)*h

it doesn't convert correctly when I replace the (1/256) with float(0.00390625)
float(0.00390625) does nothing in the sence where (1/256) does

that being said...
IDK why float(0.00390625) doesn't work...

here:
these are the images I get with the differant methods:
note: h is not set as an int or float...

float(0.00390625)*h or (commenting out the entire loop):

(1/256)*h or float(1/256)*h:

If you have Python 2 you should get same result with 0 as with 1/256 and float(0)=0.0. I think you are not using

from __future__ import division

Maybe you should start to use that and use // when you need integer results.

Do

print 1/256*h

in code before assignment and

print h

after the assignment and see the results in console if you do not believe. 1/256 == 0 in Python 2 irrespective what type of h we have.

>>> h=123
>>> h=1/256*h
>>> h
0
>>> float(1/256)
0.0
>>> h=123
>>> h/=256.0
>>> h
0.48046875
>>>

-_-

blender 2.49b requires the use of Python 2.6 to run scripts
otherwise you can only use it's scripts

1/256 = 0.00390625 (!= 0)

every number counts

can someone please help me make progress??

I've got a bunch of impatient people on my end demending me to make progress...

enough with this nonsence...
int(1/256) = 0
(1/256) = 0.004 (using Wii to reply)

now let's just leave that alone KK
the h is the invalad vert offset getting multiplied by (1/256)

now I really need some help...
please.

just posting the links to all the forums I'm working with this on

forum links (to threads):

Smashboards: http://www.smashboards.com/showthread.php?t=280525
Emutalk: http://emutalk.net/showthread.php?t=51196
My forum: http://tcll5850.proboards.com/index.cgi?board=bpy&action=display&thread=25&page=1
KC-MM: http://forums.kc-mm.com/index.php?topic=11466.0
Daniweb: http://www.daniweb.com/forums/thread302929.html

(public post (every link is included))

SUCCESS :D

thanx jcao :D
got the verts for any file oto import

heres an image of the main file I was using:

Member Avatar for Member #929548

what do we do with the script?

what do we do with the script?

actually...

you've hit up on one of my old threads... :P

but to answer your Q, you put it in your blender scripts directory...
although it's only valid for 248a to 249b...
(25 and 26 use a different script system)

I do intend to pick up development on this again,
but right now, I'm a little overloaded... heh

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.