On 11/14/2013 01:51 PM, Kevin Fishburne wrote:
On 11/14/2013 07:41 AM, Randall Morgan wrote:
Yes, I do think adding support for newer model types would be good. Perhaps
even add support for models done in solid works....
On Thu, Nov 14, 2013 at 4:34 AM, Fabien Bodard <gambas...@gmail.com> wrote:
Le 14 nov. 2013 06:14, "Kevin Fishburne" <kevinfishbu...@eightvirtues.com>
a écrit :
Using the example program as a reference I was able to successfully
render one of its included md2 models. If anyone needs a very spartan
starter tutorial, my basic code looks like this:
' Model array declared at beginning of Render module.
Public Model[32768] As Md2Object
' Model loading procedure test (index 500 is arbitrary).
Dim TempModel As Md2Model
TempModel = Md2Model.Load(BasePath & "/model/test/md2test.md2")
TempModel.Texture = LoadTexture(BasePath & "/model/test/md2test.jpg")
Model[500] = New Md2Object(TempModel)
' Render command after OpenGL matrix has been set.
Model[500].Draw
I've been having a hell of a time finding decent modeling software that
can export to the md2 format, as it is very old (though quite nice for
my needs). I created an untextured cube in Misfit Model 3D (1.3.7, stock
Kubuntu 13.10 repo) and exported it to md2, but my code raises sig 11
when it tries to execute the Draw method.
Does anyone have any insight into what modeling applications exist that
can export to md2 format? I'd love to learn Blender, but all the md2
export scripts I found failed. I think they were designed for older
versions. Maybe I should look for an old Blender version...or contact
the Nexuiz team. Any advice is appreciated, and to whoever wrote the sge
component, thank you.
--
Kevin Fishburne
Eight Virtues
www: http://sales.eightvirtues.com
e-mail: sa...@eightvirtues.com
phone: (770) 853-6271
Maybe the best will be to add another format more accurate with the current
technologies.
Thanks everyone. I'll give the mentioned programs a try and keep
investigating.
I looked up Blender's stock export formats on Wikipedia and the only one
that looks useful is X3D:
http://en.wikipedia.org/wiki/X3D
http://www.web3d.org/realtime-3d/x3d/what-x3d
Seems geared toward rendering in a web browser, although I don't know
why it couldn't be implemented outside of one. I searched the package
names for x3d and couldn't find anything. Maybe there's a lib out there
somewhere.
I finally got one of the md2 export scripts for Blender (2.66.1) working
(attached). I modified the Md2Model example project to use my exported
test md2 as a replacement for its "bauul.md2" data file so you could see
it crash. I'm guessing it is because the test md2 has no textures, so
I'll try that next. The modified project is here:
http://eightvirtues.com/sanctimonia/misc/Md2Model.tar.gz
It crashes when the Draw method is executed.
--
Kevin Fishburne
Eight Virtues
www: http://sales.eightvirtues.com
e-mail: sa...@eightvirtues.com
phone: (770) 853-6271
# ***** BEGIN GPL LICENSE BLOCK *****
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# ***** END GPL LICENCE BLOCK *****
bl_info = {
"name": "Export .md2",
"description": "Export to Quake2 file format, applies modifiers (.md2)",
"author": "Sebastian Lieberknecht, Dao Nguyen, Bernd Meyer and Marion Koelle metaio GmbH (based on Damien Thebault and Erwan Mathieu's Blender2.4x exporter)",
"version": (1, 7),
"blender": (2, 6, 3),
"api": 46461,
"location": "File > Export > md2",
"warning": '', # used for warning icon and text in addons panel
"wiki_url": "http://metaio.com",
"tracker_url": "http://metaio.com",
"category": "Import-Export"}
import bpy
from bpy.props import *
from bpy_extras.io_utils import ExportHelper
import math
import mathutils
import struct
import random
import os
import shutil
MD2_NORMALS=((-0.525731, 0.000000, 0.850651),
(-0.442863, 0.238856, 0.864188),
(-0.295242, 0.000000, 0.955423),
(-0.309017, 0.500000, 0.809017),
(-0.162460, 0.262866, 0.951056),
( 0.000000, 0.000000, 1.000000),
( 0.000000, 0.850651, 0.525731),
(-0.147621, 0.716567, 0.681718),
( 0.147621, 0.716567, 0.681718),
( 0.000000, 0.525731, 0.850651),
( 0.309017, 0.500000, 0.809017),
( 0.525731, 0.000000, 0.850651),
( 0.295242, 0.000000, 0.955423),
( 0.442863, 0.238856, 0.864188),
( 0.162460, 0.262866, 0.951056),
(-0.681718, 0.147621, 0.716567),
(-0.809017, 0.309017, 0.500000),
(-0.587785, 0.425325, 0.688191),
(-0.850651, 0.525731, 0.000000),
(-0.864188, 0.442863, 0.238856),
(-0.716567, 0.681718, 0.147621),
(-0.688191, 0.587785, 0.425325),
(-0.500000, 0.809017, 0.309017),
(-0.238856, 0.864188, 0.442863),
(-0.425325, 0.688191, 0.587785),
(-0.716567, 0.681718,-0.147621),
(-0.500000, 0.809017,-0.309017),
(-0.525731, 0.850651, 0.000000),
( 0.000000, 0.850651,-0.525731),
(-0.238856, 0.864188,-0.442863),
( 0.000000, 0.955423,-0.295242),
(-0.262866, 0.951056,-0.162460),
( 0.000000, 1.000000, 0.000000),
( 0.000000, 0.955423, 0.295242),
(-0.262866, 0.951056, 0.162460),
( 0.238856, 0.864188, 0.442863),
( 0.262866, 0.951056, 0.162460),
( 0.500000, 0.809017, 0.309017),
( 0.238856, 0.864188,-0.442863),
( 0.262866, 0.951056,-0.162460),
( 0.500000, 0.809017,-0.309017),
( 0.850651, 0.525731, 0.000000),
( 0.716567, 0.681718, 0.147621),
( 0.716567, 0.681718,-0.147621),
( 0.525731, 0.850651, 0.000000),
( 0.425325, 0.688191, 0.587785),
( 0.864188, 0.442863, 0.238856),
( 0.688191, 0.587785, 0.425325),
( 0.809017, 0.309017, 0.500000),
( 0.681718, 0.147621, 0.716567),
( 0.587785, 0.425325, 0.688191),
( 0.955423, 0.295242, 0.000000),
( 1.000000, 0.000000, 0.000000),
( 0.951056, 0.162460, 0.262866),
( 0.850651,-0.525731, 0.000000),
( 0.955423,-0.295242, 0.000000),
( 0.864188,-0.442863, 0.238856),
( 0.951056,-0.162460, 0.262866),
( 0.809017,-0.309017, 0.500000),
( 0.681718,-0.147621, 0.716567),
( 0.850651, 0.000000, 0.525731),
( 0.864188, 0.442863,-0.238856),
( 0.809017, 0.309017,-0.500000),
( 0.951056, 0.162460,-0.262866),
( 0.525731, 0.000000,-0.850651),
( 0.681718, 0.147621,-0.716567),
( 0.681718,-0.147621,-0.716567),
( 0.850651, 0.000000,-0.525731),
( 0.809017,-0.309017,-0.500000),
( 0.864188,-0.442863,-0.238856),
( 0.951056,-0.162460,-0.262866),
( 0.147621, 0.716567,-0.681718),
( 0.309017, 0.500000,-0.809017),
( 0.425325, 0.688191,-0.587785),
( 0.442863, 0.238856,-0.864188),
( 0.587785, 0.425325,-0.688191),
( 0.688191, 0.587785,-0.425325),
(-0.147621, 0.716567,-0.681718),
(-0.309017, 0.500000,-0.809017),
( 0.000000, 0.525731,-0.850651),
(-0.525731, 0.000000,-0.850651),
(-0.442863, 0.238856,-0.864188),
(-0.295242, 0.000000,-0.955423),
(-0.162460, 0.262866,-0.951056),
( 0.000000, 0.000000,-1.000000),
( 0.295242, 0.000000,-0.955423),
( 0.162460, 0.262866,-0.951056),
(-0.442863,-0.238856,-0.864188),
(-0.309017,-0.500000,-0.809017),
(-0.162460,-0.262866,-0.951056),
( 0.000000,-0.850651,-0.525731),
(-0.147621,-0.716567,-0.681718),
( 0.147621,-0.716567,-0.681718),
( 0.000000,-0.525731,-0.850651),
( 0.309017,-0.500000,-0.809017),
( 0.442863,-0.238856,-0.864188),
( 0.162460,-0.262866,-0.951056),
( 0.238856,-0.864188,-0.442863),
( 0.500000,-0.809017,-0.309017),
( 0.425325,-0.688191,-0.587785),
( 0.716567,-0.681718,-0.147621),
( 0.688191,-0.587785,-0.425325),
( 0.587785,-0.425325,-0.688191),
( 0.000000,-0.955423,-0.295242),
( 0.000000,-1.000000, 0.000000),
( 0.262866,-0.951056,-0.162460),
( 0.000000,-0.850651, 0.525731),
( 0.000000,-0.955423, 0.295242),
( 0.238856,-0.864188, 0.442863),
( 0.262866,-0.951056, 0.162460),
( 0.500000,-0.809017, 0.309017),
( 0.716567,-0.681718, 0.147621),
( 0.525731,-0.850651, 0.000000),
(-0.238856,-0.864188,-0.442863),
(-0.500000,-0.809017,-0.309017),
(-0.262866,-0.951056,-0.162460),
(-0.850651,-0.525731, 0.000000),
(-0.716567,-0.681718,-0.147621),
(-0.716567,-0.681718, 0.147621),
(-0.525731,-0.850651, 0.000000),
(-0.500000,-0.809017, 0.309017),
(-0.238856,-0.864188, 0.442863),
(-0.262866,-0.951056, 0.162460),
(-0.864188,-0.442863, 0.238856),
(-0.809017,-0.309017, 0.500000),
(-0.688191,-0.587785, 0.425325),
(-0.681718,-0.147621, 0.716567),
(-0.442863,-0.238856, 0.864188),
(-0.587785,-0.425325, 0.688191),
(-0.309017,-0.500000, 0.809017),
(-0.147621,-0.716567, 0.681718),
(-0.425325,-0.688191, 0.587785),
(-0.162460,-0.262866, 0.951056),
( 0.442863,-0.238856, 0.864188),
( 0.162460,-0.262866, 0.951056),
( 0.309017,-0.500000, 0.809017),
( 0.147621,-0.716567, 0.681718),
( 0.000000,-0.525731, 0.850651),
( 0.425325,-0.688191, 0.587785),
( 0.587785,-0.425325, 0.688191),
( 0.688191,-0.587785, 0.425325),
(-0.955423, 0.295242, 0.000000),
(-0.951056, 0.162460, 0.262866),
(-1.000000, 0.000000, 0.000000),
(-0.850651, 0.000000, 0.525731),
(-0.955423,-0.295242, 0.000000),
(-0.951056,-0.162460, 0.262866),
(-0.864188, 0.442863,-0.238856),
(-0.951056, 0.162460,-0.262866),
(-0.809017, 0.309017,-0.500000),
(-0.864188,-0.442863,-0.238856),
(-0.951056,-0.162460,-0.262866),
(-0.809017,-0.309017,-0.500000),
(-0.681718, 0.147621,-0.716567),
(-0.681718,-0.147621,-0.716567),
(-0.850651, 0.000000,-0.525731),
(-0.688191, 0.587785,-0.425325),
(-0.587785, 0.425325,-0.688191),
(-0.425325, 0.688191,-0.587785),
(-0.425325,-0.688191,-0.587785),
(-0.587785,-0.425325,-0.688191),
(-0.688191,-0.587785,-0.425325))
class MD2:
def __init__(self, options):
self.options = options
self.object = None
self.progressBarDisplayed = -10
return
def setObject(self, object, scale=1.0):
self.object = object
self.scale = scale
def write(self, filename):
self.version = 8
self.skinwidth = 2**10-1 #1023
self.skinheight = 2**10-1 #1023
# self.framesize : see below
mesh = self.object.data
skins = Util.getSkins(mesh)
self.num_skins = len(skins)
self.num_xyz = len(mesh.vertices)
self.num_st = len(mesh.tessfaces)*3
self.num_tris = len(mesh.tessfaces)
self.num_glcmds = self.num_tris * (1+3*3) + 1
self.num_frames = 1
if self.options.fExportAnimation:
self.num_frames = 1 + bpy.context.scene.frame_end - bpy.context.scene.frame_start
self.framesize = 40+4*self.num_xyz
self.ofs_skins = 68 # size of the header
self.ofs_st = self.ofs_skins + 64*self.num_skins
self.ofs_tris = self.ofs_st + 4*self.num_st
self.ofs_frames = self.ofs_tris + 12*self.num_tris
self.ofs_glcmds = self.ofs_frames + self.framesize*self.num_frames
self.ofs_end = self.ofs_glcmds + 4*self.num_glcmds
file = open(filename, 'wb')
try:
# write header
bin = struct.pack('<4B16i', #bin = struct.pack('<4s16i',
ord('I'),
ord('D'),
ord('P'),
ord('2'),
self.version,
self.skinwidth,
self.skinheight,
self.framesize,
self.num_skins,
self.num_xyz,
self.num_st, # number of texture coordinates
self.num_tris,
self.num_glcmds,
self.num_frames,
self.ofs_skins,
self.ofs_st,
self.ofs_tris,
self.ofs_frames,
self.ofs_glcmds,
self.ofs_end)
file.write(bin)
# write skin file names
for iSkin, skin in enumerate(skins):
fnImg = bpy.path.abspath(skin)
if self.options.fCopyTextureSxS:
fnSxS = os.path.join(os.path.dirname(filename), os.path.basename(fnImg))
if iSkin == 0 and self.options.fNameTextureToMD2Filename:
# rename first skin to basename
fnSxS = os.path.splitext(filename)[0] + os.path.splitext(fnImg)[1]
print("Copying texture %s to %s" % (fnImg, fnSxS))
try:
shutil.copy(fnImg, fnSxS)
except:
print("Copying texture %s to %s failed." % (fnImg, fnSxS))
fnImg = fnSxS # for proper referencing in the MD2 file
if len(fnImg) > 63 and not self.options.fExportOnlyTextureBasename:
print("WARNING: The texture path '"+fnImg+"' is too long. It is automatically truncated to the file basename.")
if len(fnImg) > 63 or self.options.fExportOnlyTextureBasename:
fnImg = os.path.basename(fnImg)
bin = struct.pack('<64s', bytes(fnImg[0:63], encoding='utf8'))
file.write(bin) # skin name
#define meshTextureFaces
if len(mesh.tessface_uv_textures) != 0:
meshTextureFaces = mesh.tessface_uv_textures[0].data
else:
meshTextureFaces = mesh.tessfaces # does this make sense?
for meshTextureFace in meshTextureFaces: # for face in mesh.faces:
try:
uvs = meshTextureFace.uv
except:
uvs = ([0,0],[0,0],[0,0])
# (u,v) in blender -> (u,1-v)
bin = struct.pack('<6h',
int(uvs[0][0]*self.skinwidth),
int((1-uvs[0][1])*self.skinheight),
int(uvs[1][0]*self.skinwidth),
int((1-uvs[1][1])*self.skinheight),
int(uvs[2][0]*self.skinwidth),
int((1-uvs[2][1])*self.skinheight),
)
file.write(bin) # uv
# (uv index is : face.index*3+i)
for face in mesh.tessfaces:
# 0,2,1 for good cw/ccw
bin = struct.pack('<3H',
face.vertices[0],
face.vertices[2],
face.vertices[1]
)
file.write(bin) # vert index
bin = struct.pack('<3H',
face.index*3 + 0,
face.index*3 + 2,
face.index*3 + 1,
)
file.write(bin) # uv index
if self.options.fExportAnimation:
min = None
max = None
timeLineMarkers =[]
for marker in bpy.context.scene.timeline_markers:
timeLineMarkers.append(marker)
# sort the markers. The marker with the frame number closest to 0 will be the first marker in the list.
# The marker with the biggest frame number will be the last marker in the list
timeLineMarkers.sort(key=lambda marker: marker.frame)
markerIdx = 0
# delete markers at same frame positions
if len(timeLineMarkers) > 1:
markerFrame = timeLineMarkers[len(timeLineMarkers)-1].frame
for i in range(len(timeLineMarkers)-2, -1, -1):
if timeLineMarkers[i].frame == markerFrame:
del timeLineMarkers[i]
else:
markerFrame = timeLineMarkers[i].frame
# BL: to fix: 1 is assumed to be the frame start (this is
# hardcoded sometimes...)
for frame in range(1, self.num_frames+1):
percent = (frame - bpy.context.scene.frame_start) / ( 1. + self.num_frames)
#Display the progress status of the export in the console
progressStatus = math.floor(percent*100)
if progressStatus - self.progressBarDisplayed >= 1:
# only show major updates (>=1%)
print("Export progress: %3i%%\r" % int(progressStatus), end=' ')
self.progressBarDisplayed = progressStatus
if frame == self.num_frames:
print("Export progress: %3i%% - Model exported." % 100)
bpy.context.scene.frame_set(frame)
if len(timeLineMarkers) != 0:
if markerIdx + 1 != len(timeLineMarkers):
if frame >= timeLineMarkers[markerIdx + 1].frame:
markerIdx += 1
name = timeLineMarkers[markerIdx].name
else:
name = 'frame'
self.outFrame(file, name + str(frame))
else:
self.outFrame(file)
# gl commands
for meshTextureFace in meshTextureFaces:
try:
uvs = meshTextureFace.uv
except:
uvs = ([0,0],[0,0],[0,0])
bin = struct.pack('<i', 3)
file.write(bin)
# 0,2,1 for good cw/ccw (also flips/inverts normal)
for vert in [0,2,1]:
# (u,v) in blender -> (u,1-v)
bin = struct.pack('<ffI',
uvs[vert][0],
(1.0 - uvs[vert][1]),
face.vertices[vert])
file.write(bin)
# NULL command
bin = struct.pack('<I', 0)
file.write(bin)
finally:
file.close()
def outFrame(self, file, frameName = 'frame'):
mesh = self.object.to_mesh(bpy.context.scene, True, 'PREVIEW')
mesh.transform(self.object.matrix_world)
if self.options.fmtExport == "Junaio":
mesh.transform(mathutils.Matrix.Rotation(math.pi/2, 4, 'X'))
mesh.transform(mathutils.Matrix.Rotation(math.pi, 4, 'Z'))
elif self.options.fmtExport == "Quake2":
mesh.transform(mathutils.Matrix.Rotation(math.pi/2, 4, 'X'))
mesh.transform(mathutils.Matrix.Scale(-1, 4, (0,1,0)))
###### compute the bounding box ###############
min = [mesh.vertices[0].co[0],
mesh.vertices[0].co[1],
mesh.vertices[0].co[2]]
max = [mesh.vertices[0].co[0],
mesh.vertices[0].co[1],
mesh.vertices[0].co[2]]
for vert in mesh.vertices:
for i in range(3):
if vert.co[i] < min[i]:
min[i] = vert.co[i]
if vert.co[i] > max[i]:
max[i] = vert.co[i]
########################################
# BL: some caching to speed it up:
# -> sd_ gets the vertices between [0 and 255]
# which is our important quantization.
sdx = (max[0]-min[0]) / 255.0
sdy = (max[1]-min[1]) / 255.0
sdz = (max[2]-min[2]) / 255.0
isdx = 255.0 / (max[0]-min[0])
isdy = 255.0 / (max[1]-min[1])
isdz = 255.0 / (max[2]-min[2])
# note about the scale: self.object.scale is already applied via matrix_world
bin = struct.pack('<6f16s',
# writing the scale of the model
self.scale * sdx,
self.scale * sdy,
self.scale * sdz,
## now the initial offset [= min of bounding box (correctly scaled)]
self.scale * min[0],
self.scale * min[1],
self.scale * min[2],
# and finally the name.
bytes(frameName, encoding='utf8'))
file.write(bin) # frame header
for vert in mesh.vertices:
# find the closest normal for every vertex
for iN in range(162):
# BL: what's the magic here??
dot = vert.normal[1]*MD2_NORMALS[iN][0] + \
-vert.normal[0]*MD2_NORMALS[iN][1] + \
vert.normal[2]*MD2_NORMALS[iN][2]
if iN==0 or dot > maxDot:
maxDot = dot
bestNormalIndex = iN
# and now write the normal.
bin = struct.pack('<4B',
int((vert.co[0]-min[0])*isdx),
int((vert.co[1]-min[1])*isdy),
int((vert.co[2]-min[2])*isdz),
bestNormalIndex)
file.write(bin) # write vertex and normal
class Util:
@staticmethod
def pickName():
name = '_MD2Obj_'+str(random.random())
return name[0:20]
# deletes an object from Blender (remove + unlink)
@staticmethod
def deleteObject(object):
bpy.context.scene.objects.unlink(object)
bpy.data.objects.remove(object)
# duplicates the given object and returns it
@staticmethod
def duplicateObject(object, name):
# backup the current object selection and current active object
selObjects = bpy.context.selected_objects[:]
actObject = bpy.context.active_object
# deselect all selected objects
bpy.ops.object.select_all(action='DESELECT')
# select the object which we want to duplicate
object.select = True
# duplicate the selected object
bpy.ops.object.duplicate()
# the duplicated object is automatically selected
copyObj = bpy.context.selected_objects[0]
# rename the object with the given name
copyObj.name = name
# select all objects which have been previously selected and make active the previous active object
bpy.context.scene.objects.active = actObject
for obj in selObjects:
obj.select = True
return copyObj
@staticmethod
def applyModifiers(object, possibleNewName):
# backup the current object selection and current active object
selObjects = bpy.context.selected_objects[:]
actObject = bpy.context.active_object
# deselect all selected objects
bpy.ops.object.select_all(action='DESELECT')
# select the object which we want to apply modifiers to
object.select = True
# duplicate the selected object
bpy.ops.object.duplicate()
# the duplicated object is automatically selected
modifiedObj = bpy.context.selected_objects[0]
# now apply all modifiers except the Armature modifier...
for modifier in modifiedObj.modifiers:
if modifier.type == "ARMATURE":
# these must stay for the animation
continue
# all others can be applied.
bpy.ops.object.modifier_apply(modifier=modifier.name)
# select all objects which have been previously selected and make active the previous active object
bpy.context.scene.objects.active = actObject
for obj in selObjects:
obj.select = True
if modifiedObj.name == object.name:
# no modifier applied.
return object
# modifiers were applied:
modifiedObj.name = possibleNewName
return modifiedObj
# returns the mesh of the object and return object.data (mesh)
@staticmethod
def triangulateMesh(object):
mesh = object.data
# make the object the active object!
bpy.context.scene.objects.active = object
bpy.ops.object.mode_set( mode="EDIT" , toggle = False )
bpy.ops.mesh.select_all(action="SELECT")
bpy.ops.mesh.quads_convert_to_tris()
bpy.ops.object.mode_set( mode="OBJECT" , toggle = False )
mesh.update(calc_tessface=True)
return mesh
@staticmethod
def getSkins(mesh):
skins = []
for material in mesh.materials:
for texSlot in material.texture_slots:
if not texSlot or texSlot.texture.type != "IMAGE":
continue
skins.append(texSlot.texture.image.filepath)
return skins
class ObjectInfo:
def __init__(self, object):
self.triang = True
self.vertices = -1
self.cTessfaces = 0
self.status = ('','')
self.ismesh = object and object.type == 'MESH'
if self.ismesh:
originalObject = object
mesh = object.data
self.skins = Util.getSkins(mesh)
tmpObjectName = Util.pickName()
try:
# apply the modifiers
object = Util.applyModifiers(object, tmpObjectName)
if object.name != tmpObjectName: # not yet copied: do it now.
object = Util.duplicateObject(object, tmpObjectName)
mesh = Util.triangulateMesh(object)
self.status = (str(len(mesh.vertices)) + ' vertices', str(len(mesh.tessfaces)) + ' faces')
self.cTessFaces = len(mesh.tessfaces)
self.vertices = len(mesh.vertices)
finally:
if object.name == tmpObjectName:
originalObject.select = True
bpy.context.scene.objects.active = originalObject
Util.deleteObject(object)
print(self.status)
class Export_MD2(bpy.types.Operator, ExportHelper):
"""Export selection to Quake2 file format (.md2)"""
bl_idname = "export_quake.md2"
bl_label = "Export selection to Quake2 file format (.md2)"
filename = StringProperty(name="File Path",
description="Filepath used for processing the script",
maxlen= 1024,default= "")
filename_ext = ".md2"
rScaleFactor = FloatProperty(name="Scale for blenderUnits -> [mm]",
description="Defaults to 1000 (blender unit -> [mm])",
default=1000.0)
fExportAnimation = BoolProperty(name="Export animation",
description="default: False",
default=False)
fExportOnlyTextureBasename = BoolProperty(name="Export only basenames (skin)",
description="default: True",
default=True)
fCopyTextureSxS = BoolProperty(name="Copy texture(s) next to .md2",
description="default: True",
default=True)
fNameTextureToMD2Filename = BoolProperty(name="Name first texture similar to .md2",
description="default: True",
default=True)
typesExportFormats = [
('Junaio', 'LH (Junaio)', 'Export for Junaio'),
('Quake2', 'RH (Quake2 default)', 'Export for Quake2'),
]
fmtExport = EnumProperty(name="Handedness",
description="Choose handedness of export",
items=typesExportFormats)
# id_export = 1
# id_cancel = 2
# id_anim = 3
# id_update = 4
# id_help = 5
# id_basename = 6
def __init__(self):
try:
self.object = bpy.context.selected_objects[0]
except:
self.object = None
# go into object mode before we start the actual export procedure
bpy.ops.object.mode_set( mode="OBJECT" , toggle = False )
self.info = ObjectInfo(self.object)
def execute(self, context):
props = self.properties
filepath = self.filepath
object = self.object
originalObject = object
# different name each time or we can't unlink it later
tmpObjectName = Util.pickName()
object = Util.applyModifiers(object, tmpObjectName)
mesh = object.data
if self.info.triang:
if object.name != tmpObjectName: # not yet copied: do it now.
object = Util.duplicateObject(object, tmpObjectName)
mesh = Util.triangulateMesh(object)
if object.type != 'MESH':
raise NameError('Selected object must be a mesh!')
# save the current frame to reset it after export
if self.fExportAnimation:
frame = bpy.context.scene.frame_current
try:
md2 = MD2(self)
md2.setObject(object, self.rScaleFactor)
md2.write(filepath)
finally:
if object.name == tmpObjectName:
originalObject.select = True
bpy.context.scene.objects.active = originalObject
Util.deleteObject(object)
if self.fExportAnimation:
bpy.context.scene.frame_set(frame)
self.report({'INFO'}, "Model '"+originalObject.name+"' exported")
return {'FINISHED'}
def invoke(self, context, event):
if not context.selected_objects:
self.report({'ERROR'}, "Please, select an object to export!")
return {'CANCELLED'}
if len(bpy.context.selected_objects) > 1:
self.report({'ERROR'}, "Please, select exactly one object to export!")
return {'CANCELLED'}
# check how many faces we have (there is a max..)
obj = bpy.context.selected_objects[0]
if obj.type != 'MESH':
self.report({'ERROR'}, "Only meshes can be exported (selected object is of type '%s')" % (obj.type))
return {'CANCELLED'}
info = ObjectInfo(obj)
cFinalTriangles = info.cTessFaces
if cFinalTriangles*3 > 2**16:
self.report({'ERROR'},
"Object has too many (triangulated) faces (%i), at most %i are supported in md2" % (cFinalTriangles, (2**16)/3))
return {'CANCELLED'}
wm = context.window_manager
wm.fileselect_add(self)
return {'RUNNING_MODAL'}
def menuCB(self, context):
self.layout.operator(Export_MD2.bl_idname, text="Quake II's MD2 (.md2)")
def register():
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_file_export.append(menuCB)
def unregister():
bpy.utils.unregister_module(__name__)
bpy.types.INFO_MT_file_export.remove(menuCB)
if __name__ == "__main__":
register()
------------------------------------------------------------------------------
DreamFactory - Open Source REST & JSON Services for HTML5 & Native Apps
OAuth, Users, Roles, SQL, NoSQL, BLOB Storage and External API Access
Free app hosting. Or install the open source package on any LAMP server.
Sign up and see examples for AngularJS, jQuery, Sencha Touch and Native!
http://pubads.g.doubleclick.net/gampad/clk?id=63469471&iu=/4140/ostg.clktrk
_______________________________________________
Gambas-user mailing list
Gambas-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/gambas-user