added a function to convert any non faces not a part of a cube, to export as brushes, 1 per face.
this means you can have suzanne, and some cubes in 1 mesh, and the cubes will export as brushes and suzanne will export 1 brush per face.
intersections should not be a problem, all sides of the cube are invisible except the one that is the face.
twosided faces are supported also, they will give some minor error if seen from behind because the brush must have some width, in most cases single sided brushes will be used.
Triangles are exported as brushes with 5 entrys, as opposed to 6, this seems to work.
Maybe I could export primitives of this shape also. (extruded triangle shape)
from Blender import *
def write_cube2brush(file, faces, PREF_SCALE):
# comment only
# file.write('// brush "%s", "%s"
' % (ob.name, ob.getData(name_only=1)))
file.write('// brush from cube
{
')
for f in faces:
# from 4 verts this gets them in reversed order and only 3 of them
# 0,1,2,3 -> 2,1,0
for v in f.v[2::-1]:
file.write('( %.8f %.8f %.8f ) ' % tuple(v.co*PREF_SCALE) )
try: mode= f.mode
except: mode= 0
if mode & Mesh.FaceModes.INVISIBLE:
file.write('common/caulk')
else:
try: image= f.image
except: image= None
if image: file.write(sys.splitext(sys.basepath(image.filename))[0])
else: file.write('NULL')
# Texture stuff ignored for now
file.write(' 0 0 0 0.5 0.5 1 1 1
')
file.write('}
')
def write_face2brush(file, face, PREF_SCALE):
image_text= 'NULL'
try: mode= face.mode
except: mode= 0
if mode & Mesh.FaceModes.INVISIBLE:
image_text= 'common/caulk'
else:
try: image= face.image
except: image= None
if image: image_text = sys.splitext(sys.basepath(image.filename))[0]
f_v= face.v
file.write('// brush from face
{
')
# front
for v in f_v[2::-1]:
file.write('( %.8f %.8f %.8f ) ' % tuple(v.co*PREF_SCALE) )
file.write(image_text)
# Texture stuff ignored for now
file.write(' 0 0 0 0.5 0.5 1 1 1
')
# back
no= face.no * 0.01
for v in f_v[:3]:
file.write('( %.8f %.8f %.8f ) ' % tuple((v.co-no)*PREF_SCALE) )
if mode & Mesh.FaceModes.TWOSIDE:
file.write(image_text)
else:
file.write('common/caulk')
# Texture stuff ignored for now
file.write(' 0 0 0 0.5 0.5 1 1 1
')
# sides.
for v in ((tuple((f_v[0].co)*PREF_SCALE), tuple((f_v[1].co)*PREF_SCALE), tuple((f_v[1].co-no)*PREF_SCALE))):
file.write( '( %.8f %.8f %.8f ) ' % v )
file.write('common/caulk')
file.write(' 0 0 0 0.5 0.5 1 1 1
')
for v in ((tuple((f_v[1].co)*PREF_SCALE), tuple((f_v[2].co)*PREF_SCALE), tuple((f_v[2].co-no)*PREF_SCALE))):
file.write( '( %.8f %.8f %.8f ) ' % v )
file.write('common/caulk')
file.write(' 0 0 0 0.5 0.5 1 1 1
')
if len(f_v)==3: # Tri, it seemms tri brushes are supported.
for v in ((tuple((f_v[2].co)*PREF_SCALE), tuple((f_v[0].co)*PREF_SCALE), tuple((f_v[0].co-no)*PREF_SCALE))):
file.write( '( %.8f %.8f %.8f ) ' % v )
file.write('common/caulk')
file.write(' 0 0 0 0.5 0.5 1 1 1
')
else: # Quad
for v in ((tuple((f_v[2].co)*PREF_SCALE), tuple((f_v[3].co)*PREF_SCALE), tuple((f_v[3].co-no)*PREF_SCALE))):
file.write( '( %.8f %.8f %.8f ) ' % v )
file.write('common/caulk')
file.write(' 0 0 0 0.5 0.5 1 1 1
')
for v in ((tuple((f_v[3].co)*PREF_SCALE), tuple((f_v[0].co)*PREF_SCALE), tuple((f_v[0].co-no)*PREF_SCALE))):
file.write( '( %.8f %.8f %.8f ) ' % v )
file.write('common/caulk')
file.write(' 0 0 0 0.5 0.5 1 1 1
')
file.write('}
')
def mesh2cubes(me):
Mesh.Mode(Mesh.SelectModes.VERTEX) # se we can rely on face selection
me.sel= False # use selection to flag used verts.
# Count the quad users to work out the cubes are in the mesh.
vert_quad_users= [[] for i in xrange(len(me.verts))]
for f in me.faces:
if len(f) == 4:
for v in f:
vert_quad_users[v.index].append(f)
face_cube_groups= []
for vidx, vqusers in enumerate(vert_quad_users):
v= me.verts[vidx]
# Dont look at again.
if len(vqusers) == 3 and not v.sel:
BAD= False
v.sel= True
unique_faces= set() # should be a set, py2.3 compat grrr :/
# We have 3 users so we could be a part of a cube.
for f in vqusers:
if len(f) != 4:
BAD= True
break
# Add as a key of unique faces
unique_faces.add(f.index)
for nxt_face_v in f:
if not nxt_face_v.sel: # Not from the original faces
nxt_face_v.sel= True
for other_face in vert_quad_users[nxt_face_v.index]:
if len(other_face)!=4:
BAD= True
break
unique_faces.add(other_face.index)
if BAD or len(unique_faces) > 6:
break
nxt_face_v_qusers = vert_quad_users[nxt_face_v.index]
if len(nxt_face_v_qusers)==3:
for nxt_face in nxt_face_v_qusers:
if len(nxt_face)!=4:
BAD= True
break
unique_faces.add(nxt_face.index)
if len(unique_faces) > 6:
break
else:
BAD= True
break
if BAD or len(unique_faces) > 6:
break
if not BAD and len(unique_faces) == 6:
faces = [me.faces[i] for i in unique_faces]
if len(set([v.index for f in faces for v in f]))==8:
face_cube_groups.append( faces )
Mesh.Mode(Mesh.SelectModes.FACE) # se we can rely on face selection
return face_cube_groups
def write_node_map(file, ob):
'''
Writes the properties of an object (empty in this case)
as a MAP node as long as it has the property name - classname
returns True/False based on weather a node was written
'''
props= [(p.name, p.data) for p in ob.properties]
IS_MAP_NODE= False
for name, value in props:
if name=='classname':
IS_MAP_NODE= True
break
if not IS_MAP_NODE:
return False
# Write a node
file.write('{
')
for name_value in props:
file.write('"%s" "%s"
' % name_value)
file.write('}
')
return True
def export_map(filepath):
print 'Map Exporter 0.0'
file= open(filepath, 'w')
# header
file.write('
// entity 0
')
file.write('{
')
file.write('"classname" "worldspawn"
')
PREF_SCALE= 10
obs_mesh= []
obs_lamp= []
obs_surf= []
obs_empty= []
dummy_mesh= Mesh.New()
for ob in Object.GetSelected():
type= ob.getType()
if type == 'Mesh': obs_mesh.append(ob)
elif type == 'Lamp': obs_lamp.append(ob)
elif type == 'Surf': obs_surf.append(ob)
elif type == 'Empty': obs_empty.append(ob)
print ' writing cubes from meshes'
for ob in obs_mesh:
dummy_mesh.getFromObject(ob.name)
# Is the object 1 cube? - object-is-a-brush
if len(dummy_mesh.verts) == 8 and len(dummy_mesh.faces) == 6:
# This is a box
dummy_mesh.transform(ob.matrixWorld)
write_cube2brush(file, dummy_mesh.faces, PREF_SCALE)
else:
face_groups= mesh2cubes(dummy_mesh)
if face_groups:
dummy_mesh.transform(ob.matrixWorld)
for face_cube_group in face_groups:
write_cube2brush(file, face_cube_group, PREF_SCALE)
dummy_mesh.sel= 0 # desel all
for fg in face_groups:
for f in fg:
f.sel= True
else:
print ' found no cubes in mesh object:', ob.name
for f in dummy_mesh.faces:
if not f.sel:
write_face2brush(file, f, PREF_SCALE)
#print 'warning, not exporting "%s" it is not a cube' % ob.name
file.write('}
')
dummy_mesh.verts= None
print ' writing lamps'
for ob in obs_lamp:
print ' %s' % ob.name
lamp= ob.data
file.write('{
')
file.write('"classname" "light"
')
file.write('"light" "%.6f"
' % (lamp.dist* PREF_SCALE))
file.write('"origin" "%.6f %.6f %.6f"
' % tuple(ob.getLocation('worldspace')))
file.write('"_color" "%.6f %.6f %.6f"
' % tuple(lamp.col))
file.write('"style" "0"
')
file.write('}
')
for ob in obs_surf:
print ob
print ' writing empty objects as nodes'
for ob in obs_empty:
if write_node_map(file, ob):
print ' %s' % ob.name
else:
print ' ignoring %s' % ob.name
def main():
Window.FileSelector(export_map, 'EXPORT MAP', '*.map')
if __name__ == '__main__': main()