"description": "Export Msp GL data",
"category": "Import-Export" }
-files = ("animation", "armature", "datafile", "export", "export_animation",
- "export_armature", "export_camera", "export_light", "export_material",
- "export_mesh", "export_object", "export_scene", "export_texture",
- "material", "mesh", "operators", "properties", "scene", "util")
+files = ("animation", "armature", "context", "datafile", "export",
+ "export_animation", "export_armature", "export_camera", "export_light",
+ "export_material", "export_mesh", "export_object", "export_scene",
+ "export_texture", "material", "mesh", "operators", "properties", "scene",
+ "util")
if "bpy" in locals():
import imp
--- /dev/null
+class ExportError(Exception):
+ def __init__(self, objs):
+ super().__init__(" -> ".join(o.name for o in objs))
+ self.objs = objs
+
+class ExportContext:
+ def __init__(self, ctx, *args, verbose=False):
+ self.obj = None
+
+ if type(ctx)==ExportContext:
+ self.level = ctx.level+1
+ self.parent = ctx
+ self.context = ctx.context
+ self.verbose = ctx.verbose
+ self.descr, self.start, self.delta = args
+ if type(self.descr)!=str:
+ self.obj = self.descr
+ self.descr = self.descr.name
+ else:
+ self.level = 0
+ self.parent = None
+ self.context = ctx
+ self.verbose = verbose
+ self.descr = None
+ self.start = 0.0
+ self.delta = 1.0
+ self.context.window_manager.progress_begin(self.start, self.delta)
+
+ if self.verbose and self.descr:
+ d = self.descr
+ if self.obj:
+ d += " ({})".format(type(self.obj).__name__)
+ print("{} {}".format("ยท"*self.level, d))
+
+ self.slice_delta = 0.0
+ self.progress = self.start
+ self.child = None
+ self.context.window_manager.progress_update(self.progress)
+ self.last_progress_update = self.progress
+
+ def export(self, func, *args, **kwargs):
+ try:
+ func(self, *args, **kwargs)
+ except Exception as e:
+ tasks = []
+ c = self
+ while c:
+ tasks.append(c)
+ c = c.child
+ objs = [t.obj for t in tasks if t.obj]
+ raise ExportError(objs) from e
+
+ def task(self, task, end):
+ self.child = ExportContext(self, task, self.progress, self.start+end*self.delta-self.progress)
+ self.progress += self.child.delta
+ return self.child
+
+ def set_progress(self, progr):
+ self.progress = self.start+progr*self.delta
+ self.child = None
+ if self.progress>self.last_progress_update+0.001:
+ self.context.window_manager.progress_update(self.progress)
+ self.last_progress_update = self.progress
+
+ def set_slices(self, count):
+ if count>0:
+ self.slice_delta = self.delta/count
+ else:
+ self.slice_delta = 0.0
+
+ def next_slice(self, task):
+ self.child = ExportContext(self, task, self.progress, self.slice_delta)
+ self.progress += self.slice_delta
+ return self.child
import itertools
class DataExporter:
- def export_to_file(self, context, out_fn, *, collection=False, shared_resources=False):
- from .util import Progress
- progress = Progress(context)
-
- objects = context.selected_objects
+ def export_to_file(self, ctx, out_fn, *, collection=False, shared_resources=False):
+ objects = context.context.selected_objects
resources = {}
material_atlases = {}
- dummy_res = self.export_resources(context, objects, resources, material_atlases, progress)
+ task = ctx.task("Exporting resources", 1.0)
+ dummy_res = self.export_resources(task, objects, resources, material_atlases)
path, base = os.path.split(out_fn)
base, ext = os.path.splitext(base)
+ task = ctx.task("Writing files", 1.0)
refs = dummy_res.collect_references()
if not shared_resources:
numbers = {}
for r in refs:
r.write_to_file(os.path.join(path, r.name))
- def export_resources(self, context, objects, resources, material_atlases, progress):
+ def export_resources(self, ctx, objects, resources, material_atlases):
if material_atlases is None:
material_atlases = {}
from .datafile import Resource
dummy_res = Resource("dummy", "dummy")
- for i, obj in enumerate(objects):
- progress.push_task_slice(obj.name, i, len(objects))
+ ctx.set_slices(len(objects))
+ for obj in objects:
+ task = ctx.next_slice(obj)
res_name = None
res = None
if obj.type=='MESH':
if not object_exporter:
from .export_object import ObjectExporter
object_exporter = ObjectExporter()
- object_exporter.export_object_resources(context, obj, resources, material_atlases, progress)
- res = object_exporter.export_object(obj, resources, progress)
+ object_exporter.export_object_resources(task, obj, resources, material_atlases)
+ res = object_exporter.export_object(obj, resources)
elif obj.type=='CAMERA':
res_name = obj.name+".camera"
if res_name not in resources:
if not armature_exporter:
from .export_armature import ArmatureExporter
armature_exporter = ArmatureExporter()
- res = armature_exporter.export_armature(context, obj)
+ res = armature_exporter.export_armature(obj)
elif obj.type=='LIGHT':
res_name = obj.name+".light"
if res_name not in resources:
resources[res_name] = res
dummy_res.create_reference_statement("ref", res)
- progress.pop_task()
-
return dummy_res
class ProjectExporter:
- def export_to_directory(self, context, out_dir):
- from .util import Progress
- progress = Progress(context)
-
+ def export_to_directory(self, ctx, out_dir):
from .scene import create_scene_chain
+ task = ctx.task("Preparing scenes", 0.0)
+ task.set_slices(len(ctx.context.blend_data.scenes))
+
scenes = {}
sequences = []
- for s in context.blend_data.scenes:
+ for s in ctx.context.blend_data.scenes:
+ subtask = task.next_slice(s)
if s.export_disposition=='IGNORE':
continue
if s.export_disposition=='SEQUENCE':
scene = create_scene_chain(s, scenes)
sequences.append(scene)
- elif s.name not in scenes:
+ elif s.export_disposition!='IGNORE' and s.name not in scenes:
scene = create_scene(s)
if s.export_disposition=='SCENE':
scenes[scene.name] = scene
scene_exporter = SceneExporter()
data_exporter = DataExporter()
+ task = ctx.task("Exporting resources", 1.0)
resources = {}
- dummy_res = data_exporter.export_resources(context, all_objects, resources, None, progress)
+ dummy_res = data_exporter.export_resources(task, all_objects, resources, None)
+
+ task = ctx.task("Exporting scenes", 1.0)
for s in ordered_scenes:
+ subtask = task.task(s, 0.5)
scene_name = s.name+".scene"
if scene_name not in resources:
scene_res = scene_exporter.export_scene(s, resources)
dummy_res.create_reference_statement("ref", scene_res)
for s in sequences:
+ subtask = task.task(s, 0.5)
seq_name = s.name+".seq"
if seq_name not in resources:
scene_exporter.export_sequence_resources(s, resources)
resources[seq_name] = seq_res
dummy_res.create_reference_statement("ref", seq_res)
+ task = ctx.task("Writing files", 1.0)
refs = dummy_res.collect_references()
for r in refs:
r.write_to_file(os.path.join(out_dir, r.name))
return tech_res
class MaterialExporter:
- def export_technique_resources(self, material, resources):
+ def export_technique_resources(self, ctx, material, resources):
from .export_texture import SamplerExporter, TextureExporter
texture_export = TextureExporter()
sampler_export = SamplerExporter()
if type(material)!=Material:
material = Material(material)
- for p in material.properties:
- if p.texture:
- tex_name = p.texture.image.name+".tex2d"
- if tex_name not in resources:
- resources[tex_name] = texture_export.export_texture(p.texture, p.tex_usage, invert_green=p.invert_green)
+ textured_props = [p for p in material.properties if p.texture]
+
+ ctx.set_slices(len(textured_props)+1)
+ for p in textured_props:
+ ctx.next_slice(p.texture.image)
+
+ tex_name = p.texture.image.name+".tex2d"
+ if tex_name not in resources:
+ resources[tex_name] = texture_export.export_texture(p.texture, p.tex_usage, invert_green=p.invert_green)
- samp_name = sampler_export.get_sampler_name(p.texture)
- if samp_name not in resources:
- resources[samp_name] = sampler_export.export_sampler(p.texture)
+ samp_name = sampler_export.get_sampler_name(p.texture)
+ if samp_name not in resources:
+ resources[samp_name] = sampler_export.export_sampler(p.texture)
+ ctx.next_slice(material)
mat_name = material.name+".mat"
if mat_name not in resources:
if material.type:
import mathutils
class MeshExporter:
- def export_mesh(self, context, mesh_or_obj, progress):
+ def export_mesh(self, ctx, mesh_or_obj):
from .mesh import Mesh, create_mesh_from_object
if type(mesh_or_obj)==Mesh:
mesh = mesh_or_obj
else:
- progress.push_task("", 0.0, 0.9)
- mesh = create_mesh_from_object(context, mesh_or_obj, progress)
- progress.pop_task()
+ task = ctx.task("Preparing mesh", 0.9)
+ mesh = create_mesh_from_object(task, mesh_or_obj)
from .datafile import Resource, Statement, Token
resource = Resource(mesh.name+".mesh", "mesh")
statements = resource.statements
+ task = ctx.task("Creating statements", 1.0)
+
st = Statement("vertices", Token("VERTEX3_FLOAT"))
stride = 12
if mesh.vertices[0].color:
if mesh.winding_test:
statements.append(Statement("winding", Token('COUNTERCLOCKWISE')))
- progress.set_progress(1.0)
+ task.set_progress(1.0)
return resource
return lods
- def export_object_resources(self, context, obj, resources, material_atlases, progress):
+ def export_object_resources(self, ctx, obj, resources, material_atlases):
if material_atlases is None:
material_atlases = {}
material_export = MaterialExporter()
material_atlas_export = MaterialAtlasExporter()
- for i, l in enumerate(lods):
+ ctx.set_slices(len(lods))
+ for l in lods:
lod_index = l.lod_index if l.lod_for_parent else 0
- progress.push_task_slice("LOD {}".format(lod_index), i, len(lods))
+ task = ctx.next_slice("LOD {}".format(lod_index))
material_atlas = None
atlas_flags = [m.render_mode!='EXTERNAL' and m.material_atlas for m in l.data.materials if m]
if material_atlas_key in material_atlases:
material_atlas = material_atlases[material_atlas_key]
else:
- material_atlas = create_material_atlas(context, l.data.materials[0])
+ material_atlas = create_material_atlas(task.context, l.data.materials[0])
material_atlases[material_atlas_key] = material_atlas
tech_name = "{}.tech".format(material_atlas.name)
resources[tech_name] = material_atlas_export.export_technique(material_atlas, resources)
elif l.material_slots and l.material_slots[0].material:
material = l.material_slots[0].material
+ subtask = task.task(material, 0.1)
if material.render_mode!='EXTERNAL':
tech_name = material.name+".tech"
if tech_name not in resources:
material = Material(material)
- material_export.export_technique_resources(material, resources)
+ material_export.export_technique_resources(subtask, material, resources)
resources[tech_name] = material_export.export_technique(material, resources)
elif "stub.tech" not in resources:
resources["stub.tech"] = self.export_stub_technique()
mesh_name = l.data.name+".mesh"
if mesh_name not in resources:
- mesh = create_mesh_from_object(context, l, material_atlas, progress)
- mesh_res = mesh_export.export_mesh(context, mesh, progress)
+ subtask = task.task(l, 1.0)
+ mesh = create_mesh_from_object(subtask, l, material_atlas)
+ mesh_res = mesh_export.export_mesh(subtask, mesh)
resources[mesh_name] = mesh_res
- progress.pop_task()
-
- def export_object(self, obj, resources, progress):
+ def export_object(self, obj, resources):
if obj.type!='MESH':
raise ValueError("Object {} is not a mesh".format(obj.name))
else:
statements += lod_st
- progress.set_progress(1.0)
-
return obj_res
def export_stub_technique(self):
import mathutils
class SceneExporter:
- def export_to_file(self, context, out_fn, *, selected_only=False, visible_only=True, collection=True, skip_existing=True):
- from .util import Progress
- progress = Progress(context)
-
+ def export_to_file(self, ctx, out_fn, *, selected_only=False, visible_only=True, collection=True, skip_existing=True):
from .scene import create_scene_from_current
- scene = create_scene_from_current(context, selected_only=selected_only, visible_only=visible_only)
+ task = ctx.task("Preparing scene", 0.1)
+ scene = create_scene_from_current(task, selected_only=selected_only, visible_only=visible_only)
resources = {}
- self.export_scene_resources(context, scene, resources, progress)
+ task = ctx.task("Exporting resources", 0.9)
+ self.export_scene_resources(task, scene, resources)
+ task = ctx.task(scene, 1.0)
scene_res = self.export_scene(scene, resources)
- progress.set_progress(1.0)
path, base = os.path.split(out_fn)
base, ext = os.path.splitext(base)
+ task = ctx.task("Writing files", 1.0)
if collection:
existing = None
if skip_existing:
for r in scene_res.collect_references():
r.write_to_file(os.path.join(path, r.name))
- def export_scene_resources(self, context, scene, resources, progress):
+ def export_scene_resources(self, ctx, scene, resources):
from .export import DataExporter
data_exporter = DataExporter()
- data_exporter.export_resources(context, scene.prototypes, resources, None, progress)
+ data_exporter.export_resources(ctx, scene.prototypes, resources, None)
def export_scene(self, scene, resources):
from .datafile import Resource, Statement, Token
self.lines += other.lines
- def prepare_triangles(self, progress):
+ def prepare_triangles(self, task):
face_count = len(self.faces)
for i in range(face_count):
f = self.faces[i]
f.normal = normals[1-cut_index]
nf.normal = normals[3-cut_index]
- progress.set_progress(i/face_count)
+ task.set_progress(i/face_count)
- def prepare_smoothing(self, progress):
+ def prepare_smoothing(self, task):
smooth_limit = -1
if self.smoothing=='NONE':
for f in self.faces:
for e in self.edges:
e.check_smooth(smooth_limit)
- progress.push_task("Sharp edges", 0.0, 0.7)
- self.split_vertices(self.find_smooth_group, progress)
+ subtask = task.task("Sharp edges", 0.7)
+ self.split_vertices(self.find_smooth_group, subtask)
if self.smoothing!='BLENDER':
- progress.set_task("Updating normals", 0.7, 1.0)
- self.compute_normals(progress)
-
- progress.pop_task()
+ subtask = task.task("Updating normals", 1.0)
+ self.compute_normals(subtask)
def prepare_vertex_groups(self, obj):
if not self.vertex_groups:
for i in f.loop_indices:
layer.uvs[i] = uv
- def prepare_uv(self, progress):
+ def prepare_uv(self, task):
# Form a list of UV layers referenced by materials with the array atlas
# property set
array_uv_layers = [] #[t.uv_layer for m in self.materials if m.array_atlas for t in m.texture_slots if t and t.texture_coords=='UV']
for i in f.loop_indices:
l.uvs[i] = mathutils.Vector((*l.uvs[i], layer))
- prog_count = len(self.uv_layers)
- prog_step = 0
-
# Split by the UV layer used for tangent vectors first so connectivity
# remains intact for tangent vector computation
tangent_layer_index = -1
elif self.uv_layers[0].unit==0:
tangent_layer_index = 0
- if tangent_layer_index>=0:
- prog_count += 1
- progress.push_task_slice("Computing tangents", 0, prog_count)
- self.split_vertices(self.find_uv_group, progress, tangent_layer_index)
- progress.set_task_slice(self.tangent_uvtex, 1, prog_count)
- self.compute_tangents(tangent_layer_index, progress)
- progress.pop_task()
- prog_step = 2
- else:
+ if tangent_layer_index<0:
raise Exception("Invalid configuration on mesh {}: No tangent UV layer".format(self.name))
+ prog_count = len(self.uv_layers)
+ if tangent_layer_index>=0:
+ prog_count += 1
+ task.set_slices(prog_count)
+
+ if tangent_layer_index>=0:
+ subtask = task.next_slice("Computing tangents")
+ self.split_vertices(self.find_uv_group, subtask, tangent_layer_index)
+ subtask = task.next_slice(self.tangent_uvtex)
+ self.compute_tangents(tangent_layer_index, subtask)
+
# Split by the remaining UV layers
for i, u in enumerate(self.uv_layers):
if i==tangent_layer_index:
continue
- progress.push_task_slice(u.name, prog_step, prog_count)
- self.split_vertices(self.find_uv_group, progress, i)
- progress.pop_task()
- prog_step += 1
+ subtask = task.next_slice(u.name)
+ self.split_vertices(self.find_uv_group, subtask, i)
# Copy UVs from layers to vertices
for v in self.vertices:
else:
v.uvs = [(0.0, 0.0)]*len(self.uv_layers)
- def prepare_colors(self, progress):
+ def prepare_colors(self, task):
if not self.colors:
return
- self.split_vertices(self.find_color_group, progress)
+ self.split_vertices(self.find_color_group, task)
for v in self.vertices:
if v.faces:
else:
v.color = (1.0, 1.0, 1.0, 1.0)
- def split_vertices(self, find_group_func, progress, *args):
+ def split_vertices(self, find_group_func, task, *args):
vertex_count = len(self.vertices)
for i in range(vertex_count):
v = self.vertices[i]
f.vertices[f.vertices.index(v)] = nv
nv.faces.append(f)
- progress.set_progress(i/vertex_count)
+ task.set_progress(i/vertex_count)
def find_smooth_group(self, vertex, face):
face.flag = True
return group
- def compute_normals(self, progress):
+ def compute_normals(self, task):
for i, v in enumerate(self.vertices):
v.normal = mathutils.Vector()
for f in v.faces:
else:
v.normal = mathutils.Vector((0, 0, 1))
- progress.set_progress(i/len(self.vertices))
+ task.set_progress(i/len(self.vertices))
- def compute_tangents(self, index, progress):
+ def compute_tangents(self, index, task):
layer_uvs = self.uv_layers[index].uvs
for i, v in enumerate(self.vertices):
if v.tan.length:
v.tan.normalize()
- progress.set_progress(i/len(self.vertices))
+ task.set_progress(i/len(self.vertices))
- def prepare_sequence(self, progress):
- progress.push_task("Reordering faces", 0.0, 0.5)
- self.reorder_faces(progress)
+ def prepare_sequence(self, task):
+ subtask = task.task("Reordering faces", 0.5)
+ self.reorder_faces(subtask)
- progress.set_task("Building sequence", 0.5, 1.0)
+ subtask = task.task("Building sequence", 1.0)
sequence = None
for i, f in enumerate(self.faces):
if sequence:
sequence = f.vertices[:]
self.vertex_sequence.append(sequence)
- progress.set_progress(i/len(self.faces))
-
- progress.pop_task()
+ subtask.set_progress(i/len(self.faces))
self.reorder_vertices()
- def reorder_faces(self, progress):
+ def reorder_faces(self, task):
# Tom Forsyth's vertex cache optimization algorithm
# http://eelpi.gotdns.org/papers/fast_vert_cache_opt.html
del cached_vertices[max_cache_size:]
n_processed += 1
- progress.set_progress(n_processed/len(self.faces))
+ task.set_progress(n_processed/len(self.faces))
self.faces = reordered_faces
for i, f in enumerate(self.faces):
e.key = make_edge_key(e.vertices[0].index, e.vertices[1].index)
-def create_mesh_from_object(context, obj, material_atlas, progress):
+def create_mesh_from_object(ctx, obj, material_atlas):
if obj.type!="MESH":
raise Exception("Object {} is not a mesh".format(obj.name))
- progress.push_task("Preparing mesh", 0.0, 0.2)
+ task = ctx.task("Collecting mesh data", 0.2)
objs = [(obj, mathutils.Matrix())]
i = 0
if c.type=="MESH" and c.compound:
objs.append((c, m*c.matrix_local))
- dg = context.evaluated_depsgraph_get()
+ dg = ctx.context.evaluated_depsgraph_get()
mesh = None
for o, m in objs:
if material_atlas:
mesh.apply_material_atlas(material_atlas)
- progress.set_task("Triangulating", 0.2, 0.3)
- mesh.prepare_triangles(progress)
- progress.set_task("Smoothing", 0.3, 0.5)
- mesh.prepare_smoothing(progress)
- progress.set_task("Vertex groups", 0.5, 0.6)
+ task = ctx.task("Triangulating", 0.3)
+ mesh.prepare_triangles(task)
+ task = ctx.task("Smoothing", 0.5)
+ mesh.prepare_smoothing(task)
+ task = ctx.task("Vertex groups", 0.6)
mesh.prepare_vertex_groups(obj)
- progress.set_task("Preparing UVs", 0.6, 0.75)
- mesh.prepare_uv(progress)
- progress.set_task("Preparing vertex colors", 0.75, 0.85)
- mesh.prepare_colors(progress)
- progress.set_task("Render sequence", 0.85, 1.0)
- mesh.prepare_sequence(progress)
-
- progress.pop_task()
+ task = ctx.task("Preparing UVs", 0.75)
+ mesh.prepare_uv(task)
+ task = ctx.task("Preparing vertex colors", 0.85)
+ mesh.prepare_colors(task)
+ task = ctx.task("Render sequence", 1.0)
+ mesh.prepare_sequence(task)
return mesh
filepath: bpy.props.StringProperty(name="File path", description="File path for exporting the data", subtype='FILE_PATH')
collection: bpy.props.BoolProperty(name="As a collection", description="Export all data as a single collection file", default=False)
shared_resources: bpy.props.BoolProperty(name="Shared resources", description="Use global names for resource files to enable sharing", default=True)
+ debug_mode: bpy.props.BoolProperty(name="Debug mode", description="Enable debugging output to console")
@classmethod
def poll(cls, context):
return {'RUNNING_MODAL'}
def execute(self, context):
+ from .context import ExportContext
from .export import DataExporter
+
+ ex_ctx = ExportContext(context, verbose=self.debug_mode)
exporter = DataExporter()
- exporter.export_to_file(context, self.filepath,
+ ex_ctx.export(exporter.export_to_file, self.filepath,
collection=self.collection,
shared_resources=self.shared_resources)
return {'FINISHED'}
col.prop(self, "collection")
col.prop(self, "shared_resources")
+ self.layout.separator()
+
+ col = self.layout.column()
+ col.prop(self, "debug_mode")
+
class ExportMspGLAnimation(bpy.types.Operator, ExportHelper):
bl_idname = "export.mspgl_animation"
bl_label = "Export Msp GL animation"
export_all: bpy.props.BoolProperty(name="Export all animations", description="Export all animations present on the selected objects' NLA tracks")
collection: bpy.props.BoolProperty(name="As a collection", description="Export the animations as a single collection file", default=True)
looping_threshold: bpy.props.FloatProperty(name="Looping threshold", description="Tolerance for curve beginning and end values for looping", min=0.0, soft_max=1.0, precision=4, default=0.001)
+ debug_mode: bpy.props.BoolProperty(name="Debug mode", description="Enable debugging output to console")
def check(self, context):
ext_changed = self.set_extension(".mdc" if self.export_all and self.collection else ".anim")
return ext_changed or super_result
def execute(self, context):
+ from .context import ExportContext
from .export_animation import AnimationExporter
+
+ ex_ctx = ExportContext(context, verbose=self.debug_mode)
exporter = AnimationExporter()
- exporter.export_to_file(context, self.filepath,
+ ex_ctx.export(exporter.export_to_file, self.filepath,
export_all=self.export_all,
collection=self.collection,
looping_threshold=looping_threshold)
col.prop(self, "collection")
col.prop(self, "looping_threshold")
+ self.layout.separator()
+
+ col = self.layout.column()
+ col.prop(self, "debug_mode")
+
class ExportMspGLScene(bpy.types.Operator, ExportHelper):
bl_idname = "export_scene.mspgl_scene"
bl_label = "Export Msp GL scene"
visible_only: bpy.props.BoolProperty(name="Visible only", description="Only export objects in visible collections", default=True)
collection: bpy.props.BoolProperty(name="As a collection", description="Export the scene and all resources as a single collection file", default=False)
skip_existing: bpy.props.BoolProperty(name="Skip existing files", description="Skip resources that already exist as files", default=True)
+ debug_mode: bpy.props.BoolProperty(name="Debug mode", description="Enable debugging output to console")
def invoke(self, context, event):
self.filepath = context.scene.name+".scene"
return ext_changed or super_result
def execute(self, context):
+ from .context import ExportContext
from .export_scene import SceneExporter
+
+ ex_ctx = ExportContext(context, verbose=self.debug_mode)
exporter = SceneExporter()
- exporter.export_to_file(context, self.filepath,
+ ex_ctx.export(exporter.export_to_file, self.filepath,
selected_only=self.selected_only,
visible_only=self.visible_only,
collection=self.collection,
if self.collection:
col.prop(self, "skip_existing")
+ self.layout.separator()
+
+ col = self.layout.column()
+ col.prop(self, "debug_mode")
+
class ExportMspGLProject(bpy.types.Operator):
bl_idname = "export.mspgl_project"
bl_label = "Export Msp GL project"
bl_description = "Export the entire project in Msp GL format"
directory: bpy.props.StringProperty(name="Directory", description="Directory for exporting the data", subtype='FILE_PATH')
+ debug_mode: bpy.props.BoolProperty(name="Debug mode", description="Enable debugging output to console")
def invoke(self, context, event):
blend_filepath = context.blend_data.filepath
return {'RUNNING_MODAL'}
def execute(self, context):
+ from .context import ExportContext
from .export import ProjectExporter
+
+ ex_ctx = ExportContext(context, verbose=self.debug_mode)
exporter = ProjectExporter()
- exporter.export_to_directory(context, self.directory)
+ ex_ctx.export(exporter.export_to_directory, self.directory)
return {'FINISHED'}
+ def draw(self, context):
+ col = self.layout.column()
+ col.prop(self, "debug_mode")
+
class AddRenderMethod(bpy.types.Operator):
bl_idname = "material.add_render_method"
bl_label = "Add Render Method"
result += get_all_collections(c)
return result
-def create_scene_from_current(context, *, selected_only=False, visible_only=True):
+def create_scene_from_current(ctx, *, selected_only=False, visible_only=True):
obj_filters = []
if selected_only:
if visible_only:
visible_names = set()
- for c in get_all_collections(context.view_layer.layer_collection):
+ for c in get_all_collections(ctx.context.view_layer.layer_collection):
if not c.hide_viewport and not c.collection.hide_viewport:
visible_names.update(o.name for o in c.collection.objects)
obj_filters.append(lambda o: o.name in visible_names)
if obj_filters:
obj_filter = lambda o: all(f(o) for f in obj_filters)
- return Scene(context.scene, obj_filter)
+ return Scene(ctx.context.scene, obj_filter)
def create_scene(scene, *, visible_only=True):
obj_filter = None
import os
-class Progress:
- def __init__(self, context):
- self.task = ""
- self.start = 0.0
- self.delta = 1.0
- self.last = 0.0
- self.stack = []
- if context:
- self.window_manager = context.window_manager
- self.window_manager.progress_begin(0.0, 1.0)
- else:
- self.window_manager = None
-
- def push_task(self, task, low, high):
- self.stack.append((self.task, self.start, self.delta))
- self.set_task(task, low, high)
-
- def push_task_slice(self, task, index, count):
- self.push_task(task, index/count, (index+1)/count)
-
- def pop_task(self):
- if not self.stack:
- return
-
- self.set_progress(1.0)
- self.task, self.start, self.delta = self.stack.pop()
-
- def set_task(self, task, low, high):
- if self.stack:
- outer = self.stack[-1]
- if outer[0]:
- task = "{}: {}".format(outer[0], task)
- low = outer[1]+low*outer[2]
- high = outer[1]+high*outer[2]
-
- self.task = task
- self.start = low
- self.delta = high-low
-
- self.set_progress(0.0)
-
- def set_task_slice(self, task, index, count):
- self.set_task(task, index/count, (index+1)/count)
-
- def set_progress(self, value):
- value = self.start+self.delta*value
- if value>self.last+0.001:
- if self.window_manager:
- self.window_manager.progress_update(value)
- self.last = value
-
-
def linear_to_srgb(l):
if l<0.0031308:
return 12.92*l