]> git.tdb.fi Git - libs/gl.git/blob - blender/io_mspgl/export_object.py
Revise export function parameter orders
[libs/gl.git] / blender / io_mspgl / export_object.py
1 import os
2 import mathutils
3
4 class ObjectExporter:
5         def __init__(self):
6                 self.show_progress = True
7                 self.export_all = False
8                 self.collection = False
9                 self.shared_resources = True
10
11         def compute_bounding_sphere(self, obj):
12                 p1 = max(((v.co, v.co.length) for v in obj.data.vertices), key=lambda x:x[1])[0]
13                 p2 = max(((v.co, (v.co-p1).length) for v in obj.data.vertices), key=lambda x:x[1])[0]
14                 center = (p1+p2)/2
15                 radius = (p1-p2).length/2
16                 for v in obj.data.vertices:
17                         d = v.co-center
18                         if d.length>radius:
19                                 center += d*(1-radius/d.length)/2
20                                 radius = (radius+d.length)/2
21
22                 return center, radius
23
24         def collect_object_lods(self, obj):
25                 lods = [obj]
26                 lods += sorted([c for c in obj.children if c.lod_for_parent], key=(lambda l: l.lod_index))
27                 for i, l in enumerate(lods):
28                         if i>0 and l.lod_index!=i:
29                                 raise Exception("Inconsistent LOD indices")
30
31                 return lods
32
33         def create_mesh_exporter(self):
34                 from .export_mesh import MeshExporter
35                 mesh_export = MeshExporter()
36                 return mesh_export
37
38         def create_material_exporter(self):
39                 from .export_material import MaterialExporter
40                 material_export = MaterialExporter()
41                 return material_export
42
43         def create_material_atlas_exporter(self):
44                 from .export_material import MaterialAtlasExporter
45                 material_atlas_export = MaterialAtlasExporter()
46                 return material_atlas_export
47
48         def export_to_file(self, context, out_fn):
49                 if self.export_all:
50                         objs = [o for o in context.selected_objects if o.type=="MESH"]
51                 else:
52                         objs = [context.active_object]
53
54                 from .util import Progress
55                 progress = Progress(self.show_progress and context)
56
57                 path, base = os.path.split(out_fn)
58                 base, ext = os.path.splitext(base)
59
60                 resources = {}
61                 for i, obj in enumerate(objs):
62                         if self.export_all:
63                                 out_fn = os.path.join(path, obj.name+ext)
64
65                         progress.push_task_slice(obj.name, i, len(objs))
66                         self.export_object_resources(context, obj, resources, None, progress)
67
68                         obj_res = self.export_object(context, obj, resources, progress)
69                         refs = obj_res.collect_references()
70                         if not self.shared_resources:
71                                 numbers = {}
72                                 for r in refs:
73                                         res_ext = os.path.splitext(r.name)[1]
74                                         n = numbers.get(res_ext, 0)
75                                         if n>0:
76                                                 r.name = "{}_{}{}".format(base, n, res_ext)
77                                         else:
78                                                 r.name = base+res_ext
79                                         numbers[res_ext] = n+1
80
81                         if self.collection:
82                                 obj_res.write_collection(out_fn)
83                         else:
84                                 for r in refs:
85                                         r.write_to_file(os.path.join(path, r.name))
86                                 obj_res.write_to_file(out_fn)
87
88                         progress.pop_task()
89
90         def export_object_resources(self, context, obj, resources, material_atlases, progress):
91                 if material_atlases is None:
92                         material_atlases = {}
93
94                 lods = self.collect_object_lods(obj)
95
96                 from .mesh import create_mesh_from_object
97                 from .material import create_material_atlas
98                 mesh_export = self.create_mesh_exporter()
99                 material_export = self.create_material_exporter()
100                 material_atlas_export = self.create_material_atlas_exporter()
101
102                 for i, l in enumerate(lods):
103                         lod_index = l.lod_index if l.lod_for_parent else 0
104                         progress.push_task_slice("LOD {}".format(lod_index), i, len(lods))
105
106                         material_atlas = None
107                         atlas_flags = [m.render_mode!='EXTERNAL' and m.material_atlas for m in l.data.materials if m]
108                         if any(atlas_flags):
109                                 mmk = lambda m: m.shader if m.render_mode=='CUSTOM' else ""
110                                 material_atlas_key = mmk(l.data.materials[0])
111                                 key_mismatch = any(mmk(m)!=material_atlas_key for m in l.data.materials)
112                                 if not all(atlas_flags) or key_mismatch:
113                                         raise Exception("Conflicting settings in object materials")
114
115                                 if material_atlas_key in material_atlases:
116                                         material_atlas = material_atlases[material_atlas_key]
117                                 else:
118                                         material_atlas = create_material_atlas(context, l.data.materials[0])
119                                         material_atlases[material_atlas_key] = material_atlas
120
121                                 tech_name = "{}.tech".format(material_atlas.name)
122                                 if tech_name not in resources:
123                                         material_atlas_export.export_technique_resources(material_atlas, resources)
124                                         resources[tech_name] = material_atlas_export.export_technique(material_atlas, resources)
125                         elif l.material_slots and l.material_slots[0].material:
126                                 material = l.material_slots[0].material
127                                 if material.render_mode!='EXTERNAL':
128                                         tech_name = material.name+".tech"
129                                         if tech_name not in resources:
130                                                 material_export.export_technique_resources(material, resources)
131                                                 resources[tech_name] = material_export.export_technique(material, resources)
132                         elif "stub.tech" not in resources:
133                                 resources["stub.tech"] = self.export_stub_technique()
134
135                         mesh_name = l.data.name+".mesh"
136                         if mesh_name not in resources:
137                                 mesh = create_mesh_from_object(context, l, material_atlas, progress)
138                                 mesh_res = mesh_export.export_mesh(context, mesh, progress)
139                                 resources[mesh_name] = mesh_res
140
141                         progress.pop_task()
142
143         def export_object(self, context, obj, resources, progress):
144                 if resources is None:
145                         resources = {}
146                         self.export_object_resources(context, obj, resources, None, progress)
147
148                 lods = self.collect_object_lods(obj)
149
150                 from .datafile import Resource, Statement
151                 obj_res = Resource(obj.name+".object", "object")
152                 statements = obj_res.statements
153
154                 center, radius = self.compute_bounding_sphere(obj)
155                 statements.append(Statement("bounding_sphere_hint", *center, radius))
156
157                 prev_mesh = None
158                 prev_tech = None
159                 for i, l in enumerate(lods):
160                         lod_st = []
161
162                         if l.data.name!=prev_mesh:
163                                 mesh_res = resources[l.data.name+".mesh"]
164                                 lod_st.append(obj_res.create_reference_statement("mesh", mesh_res))
165
166                                 prev_mesh = l.data.name
167
168                         material = None
169                         if l.material_slots:
170                                 material = l.material_slots[0].material
171                         if material:
172                                 if material.render_mode=='EXTERNAL':
173                                         tech_name = material.technique
174                                 elif material.material_atlas:
175                                         tech_name = "material_atlas_{}.tech".format(os.path.splitext(material.technique)[0])
176                                 else:
177                                         tech_name = material.name+".tech"
178                         else:
179                                 tech_name = "stub.tech"
180
181                         if tech_name!=prev_tech:
182                                 if material and material.render_mode=='EXTERNAL':
183                                         lod_st.append(Statement("technique", material.technique))
184                                 else:
185                                         lod_st.append(obj_res.create_reference_statement("technique", resources[tech_name]))
186                                 prev_tech = tech_name
187
188                         if i>0:
189                                 st = Statement("level_of_detail", i)
190                                 st.sub = lod_st
191                                 statements.append(st)
192                         else:
193                                 statements += lod_st
194
195                 progress.set_progress(1.0)
196
197                 return obj_res
198
199         def export_stub_technique(self):
200                 from .datafile import Resource, Statement
201                 tech_res = Resource("stub.tech", "technique")
202                 pass_st = Statement("pass", "")
203                 tech_res.statements.append(pass_st)
204                 mat_st = Statement("material")
205                 pass_st.sub.append(mat_st)
206                 mat_st.sub.append(Statement("basic"))
207                 return tech_res