mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
Add very preliminary support for map exporting.
There is no error checking, texture alignment or support for non-point lights, but it's a start. Also, it's assumed all brushes are convex and manifold.
This commit is contained in:
parent
6b8df7f42a
commit
4fc9316320
2 changed files with 168 additions and 3 deletions
|
@ -54,7 +54,7 @@ from bpy.app.handlers import persistent
|
|||
from .entityclass import EntityClassDict, EntityClassError
|
||||
from . import entity
|
||||
from . import import_map
|
||||
#from . import export_map
|
||||
from . import export_map
|
||||
|
||||
def ecm_draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -267,8 +267,7 @@ class ExportMap(bpy.types.Operator, ExportHelper):
|
|||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.active_object != None
|
||||
and type(context.active_object.data) == bpy.types.Mesh)
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
keywords = self.as_keywords (ignore=("check_existing", "filter_glob"))
|
||||
|
|
166
tools/io_qfmap/export_map.py
Normal file
166
tools/io_qfmap/export_map.py
Normal file
|
@ -0,0 +1,166 @@
|
|||
# vim:ts=4:et
|
||||
# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import bpy
|
||||
import bmesh
|
||||
from mathutils import Vector,Matrix
|
||||
from math import pi
|
||||
|
||||
def active_uv(mesh):
|
||||
for uvt in mesh.uv_textures:
|
||||
if uvt.active:
|
||||
return uvt
|
||||
return None
|
||||
|
||||
def make_face(bmface, mesh):
|
||||
uvtex = active_uv(mesh)
|
||||
uvfaces = mesh.uv_layers[uvtex.name].data
|
||||
face = mesh.polygons[bmface.index]
|
||||
mat = mesh.materials[face.material_index]
|
||||
uvs = uvfaces[face.loop_start:face.loop_start + face.loop_total]
|
||||
uvs = list(map(lambda a: a.uv, uvs))
|
||||
v = list(face.vertices[-3:])
|
||||
v.reverse()
|
||||
return (mesh.vertices[v[0]].co, mesh.vertices[v[1]].co,
|
||||
mesh.vertices[v[2]].co, mat.name, 0, 0, 0, 1, 1)
|
||||
|
||||
def make_brushes(obj):
|
||||
act = bpy.context.scene.objects.active
|
||||
bpy.context.scene.objects.active = obj
|
||||
bpy.ops.object.editmode_toggle()
|
||||
brushmesh = bmesh.from_edit_mesh(obj.data).copy()
|
||||
bpy.ops.object.editmode_toggle()
|
||||
bpy.context.scene.objects.active = act
|
||||
brushes = []
|
||||
face_set = set(brushmesh.faces)
|
||||
while face_set:
|
||||
face_queue = [face_set.pop()]
|
||||
brush = []
|
||||
while face_queue:
|
||||
face = face_queue.pop()
|
||||
brush.append(face)
|
||||
for edge in face.edges:
|
||||
for link_face in edge.link_faces:
|
||||
if link_face in face_set:
|
||||
face_set.remove(link_face)
|
||||
face_queue.append(link_face)
|
||||
brushes.append(brush)
|
||||
mesh = obj.to_mesh(bpy.context.scene, True, 'PREVIEW')
|
||||
mesh.transform(obj.matrix_world)
|
||||
for b in brushes:
|
||||
for i in range(len(b)):
|
||||
b[i] = make_face(b[i], mesh)
|
||||
return brushes
|
||||
|
||||
def export_mesh(obj):
|
||||
qfe = obj.qfentity
|
||||
edict = entity_dict(qfe)
|
||||
if qfe.classname:
|
||||
edict["classname"] = qfe.classname
|
||||
ec = bpy.context.scene.qfmap.entity_classes.get(edict["classname"])
|
||||
if not ec or ec.size:
|
||||
edict["origin"] = "{l.x:.0f} {l.y:.0f} {l.z:.0f}".format(l=obj.location)
|
||||
return edict, []
|
||||
return edict, make_brushes(obj)
|
||||
|
||||
def export_lamp(obj):
|
||||
qfe = obj.qfentity
|
||||
edict = entity_dict(qfe)
|
||||
if qfe.classname:
|
||||
edict["classname"] = qfe.classname
|
||||
if not edict.get("classname"):
|
||||
edict["classname"] = "light"
|
||||
edict["origin"] = "{l.x:.0f} {l.y:.0f} {l.z:.0f}".format(l=obj.location)
|
||||
light = obj.data
|
||||
edict["light"] = light.distance
|
||||
return edict
|
||||
|
||||
def vector_str(vect):
|
||||
return "{v.x:.0f} {v.y:.0f} {v.z:.0f}".format(v=vect)
|
||||
|
||||
def export_empty(obj):
|
||||
qfe = obj.qfentity
|
||||
edict = entity_dict(qfe)
|
||||
if qfe.classname:
|
||||
edict["classname"] = qfe.classname
|
||||
edict["origin"] = vector_str(obj.location)
|
||||
return edict
|
||||
|
||||
def write_brush(outfile, brush):
|
||||
outfile.write("{\n")
|
||||
for f in brush:
|
||||
outfile.write("( {} ) ( {} ) ( {} ) {} {} {} {} {} {}\n".format(
|
||||
vector_str(f[0]), vector_str(f[1]), vector_str(f[2]),
|
||||
f[3], f[4], f[5], f[6], f[7], f[8]))
|
||||
outfile.write("}\n")
|
||||
|
||||
def write_entity(outfile, edict, brushes):
|
||||
outfile.write("{\n")
|
||||
for item in edict.items():
|
||||
outfile.write("\"{item[0]}\" \"{item[1]}\"\n".format(item=item))
|
||||
for brush in brushes:
|
||||
write_brush(outfile, brush)
|
||||
outfile.write("}\n")
|
||||
|
||||
def entity_dict(ent):
|
||||
edict = {}
|
||||
for field in ent.fields:
|
||||
edict[field.name] = field.value
|
||||
return edict
|
||||
|
||||
def export_map(operator, context, filepath):
|
||||
bpy.context.user_preferences.edit.use_global_undo = False
|
||||
|
||||
world_objects = []
|
||||
entities = []
|
||||
for obj in bpy.context.scene.objects:
|
||||
qfe = obj.qfentity
|
||||
edict = entity_dict(qfe)
|
||||
if (obj.type == 'MESH'
|
||||
and (qfe.classname == 'worldspawn'
|
||||
or (not qfe.classname and "classname" not in edict))):
|
||||
world_objects.append(obj)
|
||||
elif (obj.type in {'MESH', 'LAMP', 'EMPTY'}
|
||||
and (qfe.classname or ("classname" in edict))):
|
||||
entities.append(obj)
|
||||
world_brushes = []
|
||||
world_dict = {"classname":"worldspawn"}
|
||||
for obj in world_objects:
|
||||
world_dict.update(entity_dict(obj.qfentity))
|
||||
world_brushes.extend(make_brushes(obj))
|
||||
outfile = open(filepath, "wt")
|
||||
write_entity(outfile, world_dict, world_brushes)
|
||||
for obj in entities:
|
||||
if obj.type == 'MESH':
|
||||
edict, brushes = export_mesh(obj)
|
||||
elif obj.type == 'LAMP':
|
||||
brushes = []
|
||||
edict = export_lamp(obj)
|
||||
elif obj.type == 'EMPTY':
|
||||
brushes = []
|
||||
edict = export_empty(obj)
|
||||
write_entity(outfile, edict, brushes)
|
||||
outfile.close()
|
||||
bpy.context.user_preferences.edit.use_global_undo = True
|
||||
return {'FINISHED'}
|
Loading…
Reference in a new issue