]> git.tdb.fi Git - libs/gl.git/blob - blender/io_mspgl/export_object.py
4bc6f450b330a3ca17159ddea6fa9a2ba1ab836e
[libs/gl.git] / blender / io_mspgl / export_object.py
1 import os
2 import mathutils
3
4 def linear_to_srgb(l):
5         if l<0.0031308:
6                 return 12.92*l
7         else:
8                 return 1.055*(l**(1/2.4))-0.055
9
10 def get_colormap(srgb):
11         if srgb:
12                 return linear_to_srgb
13         else:
14                 return lambda x: x
15
16 def image_name(i):
17         fp = i.filepath
18         if fp:
19                 return os.path.split(fp)[1]
20         else:
21                 return i.name
22
23
24 class ObjectExporter:
25         def __init__(self):
26                 self.show_progress = True
27                 self.use_strips = True
28                 self.use_degen_tris = False
29                 self.textures = "REF"
30                 self.separate_mesh = False
31                 self.separate_tech = False
32                 self.shared_resources = True
33                 self.export_lods = True
34
35         def compute_bounding_sphere(self, obj):
36                 p1 = max(((v.co, v.co.length) for v in obj.data.vertices), key=lambda x:x[1])[0]
37                 p2 = max(((v.co, (v.co-p1).length) for v in obj.data.vertices), key=lambda x:x[1])[0]
38                 center = (p1+p2)/2
39                 radius = (p1-p2).length/2
40                 for v in obj.data.vertices:
41                         d = v.co-center
42                         if d.length>radius:
43                                 center += d*(1-radius/d.length)/2
44                                 radius = (radius+d.length)/2
45
46                 return center, radius
47
48         def make_external_name(self, base_name, resource_name, ext, index):
49                 if self.shared_resources:
50                         return resource_name+ext
51                 elif lod_index>0:
52                         return "{}_lod{}{}".format(base_name, lod_index, ext)
53                 else:
54                         return base_name+ext
55
56         def create_mesh_exporter(self):
57                 from .export_mesh import MeshExporter
58                 mesh_export = MeshExporter()
59                 mesh_export.use_strips = self.use_strips
60                 mesh_export.use_degen_tris = self.use_degen_tris
61                 return mesh_export
62
63         def export_to_file(self, context, out_fn):
64                 obj = context.active_object
65
66                 from .util import Progress
67                 progress = Progress(self.show_progress and context)
68
69                 path, base = os.path.split(out_fn)
70                 base = os.path.splitext(base)[0]
71
72                 meshes = self.export_object_meshes(context, obj, progress, base_name=base)
73                 if self.separate_mesh:
74                         for name, st in meshes.items():
75                                 with open(os.path.join(path, name), "w") as out_file:
76                                         for s in st:
77                                                 s.write_to_file(out_file)
78
79                 if self.separate_tech:
80                         lods = [obj]
81                         if self.export_lods:
82                                 lods += [c for c in obj.children if c.lod_for_parent]
83
84                         for l in lods:
85                                 lod_index = l.lod_index if l.lod_for_parent else 0
86
87                                 material = None
88                                 if obj.material_slots:
89                                         material = obj.material_slots[0].material
90
91                                 if not l.technique:
92                                         tech_name = self.make_external_name(base, material.name, ".tech", lod_index)
93                                         st = self.export_object_technique(l, base_name=base)
94                                         with open(os.path.join(path, tech_name), "w") as out_file:
95                                                 for s in st:
96                                                         s.write_to_file(out_file)
97                                 elif material and l.override_material:
98                                         mat_name = self.make_external_name(base, material.name, ".mat", lod_index)
99                                         st = self.export_material(material)
100                                         with open(os.path.join(path, mat_name), "w") as out_file:
101                                                 for s in st:
102                                                         s.write_to_file(out_file)
103
104                 statements = self.export_object(context, obj, progress, meshes=meshes, base_name=base)
105
106                 with open(out_fn, "w") as out_file:
107                         for s in statements:
108                                 s.write_to_file(out_file)
109
110         def export_object_meshes(self, context, obj, progress, *, base_name=None):
111                 if base_name is None:
112                         base_name = obj.name
113
114                 lods = [obj]
115                 if self.export_lods:
116                         lods += [c for c in obj.children if c.lod_for_parent]
117
118                 from .mesh import create_mesh_from_object
119                 mesh_export = self.create_mesh_exporter()
120                 meshes = {}
121
122                 for i, l in enumerate(lods):
123                         lod_index = l.lod_index if l.lod_for_parent else 0
124                         progress.push_task_slice("LOD {}".format(lod_index), i, len(lods))
125
126                         mesh_name = self.make_external_name(base_name, l.data.name, ".mesh", lod_index)
127                         if mesh_name not in meshes:
128                                 mesh = create_mesh_from_object(context, l, progress)
129                                 meshes[mesh_name] = mesh_export.export_mesh(context, mesh, progress)
130
131                         progress.pop_task()
132
133                 return meshes
134
135         def export_object(self, context, obj, progress, *, meshes=None, base_name=None):
136                 if base_name is None:
137                         base_name = obj.name
138
139                 if meshes is None:
140                         meshes = self.export_object_meshes(context, obj, progress, base_name=base_name)
141
142                 lods = [obj]
143                 for c in obj.children:
144                         if c.lod_for_parent:
145                                 if c.lod_index>=len(lods):
146                                         lods += [None]*(c.lod_index+1-len(lods))
147                                 lods[c.lod_index] = c
148
149                 from .datafile import Statement
150                 statements = []
151
152                 center, radius = self.compute_bounding_sphere(obj)
153                 statements.append(Statement("bounding_sphere_hint", *center, radius))
154
155                 prev_mesh = None
156                 prev_tech = (None, None)
157                 for i, l in enumerate(lods):
158                         lod_st = []
159
160                         if l.data.name!=prev_mesh:
161                                 mesh_name = self.make_external_name(base_name, l.data.name, ".mesh", i)
162                                 if self.separate_mesh:
163                                         lod_st.append(Statement("mesh", mesh_name))
164                                 else:
165                                         st = Statement("mesh")
166                                         st.sub = meshes[mesh_name]
167                                         lod_st.append(st)
168
169                                 prev_mesh = l.data.name
170
171                         mat_name = None
172                         if l.material_slots and l.material_slots[0].material:
173                                 mat_name = l.material_slots[0].material.name
174
175                         tech = (l.technique, mat_name)
176                         if tech!=prev_tech:
177                                 tech_name = self.make_external_name(base_name, mat_name or l.name, ".tech", i)
178                                 if l.technique:
179                                         if l.inherit_tech:
180                                                 st = Statement("technique")
181                                                 st.sub = self.export_object_technique(l, base_name=base_name)
182                                                 lod_st.append(st)
183                                         else:
184                                                 lod_st.append(Statement("technique", l.technique))
185                                 elif self.separate_tech:
186                                         lod_st.append(Statement("technique", tech_name))
187                                 else:
188                                         st = Statement("technique")
189                                         st.sub = self.export_object_technique(l, base_name=base_name)
190                                         lod_st.append(st)
191
192                                 prev_tech = tech
193
194                         if i>0:
195                                 st = Statement("level_of_detail", i)
196                                 st.sub = lod_st
197                                 statements.append(st)
198                         else:
199                                 statements += lod_st
200
201                 progress.set_progress(1.0)
202
203                 return statements
204
205         def export_object_technique(self, obj, *, base_name=None):
206                 if base_name is None:
207                         base_name = obj.name
208
209                 material = None
210                 if obj.material_slots:
211                         material = obj.material_slots[0].material
212
213                 from .datafile import Statement, Token
214                 statements = []
215
216                 if obj.technique:
217                         if not obj.inherit_tech:
218                                 return []
219
220                         st = Statement("inherit", obj.technique)
221                         if material:
222                                 for slot in material.texture_slots:
223                                         if slot and slot.texture.type=="IMAGE":
224                                                 name = image_name(slot.texture.image)
225                                                 if slot.use_map_color_diffuse:
226                                                         st.sub.append(Statement("texture", "diffuse_map", name))
227                                                 elif slot.use_map_normal:
228                                                         st.sub.append(Statement("texture", "normal_map", name))
229                                 if obj.override_material:
230                                         mat_name = self.make_external_name(base_name, material.name, ".mat", obj.lod_index)
231                                         st.sub.append(Statement("material", "surface", mat_name))
232                         statements.append(st)
233
234                         return statements
235
236                 pass_st = Statement("pass", "")
237                 if material:
238                         st = Statement("material")
239                         st.sub = self.export_material(material)
240                         pass_st.sub.append(st)
241
242                         if self.textures!="NONE":
243                                 diffuse_tex = None
244                                 for slot in material.texture_slots:
245                                         if slot and slot.texture.type=="IMAGE" and slot.use_map_color_diffuse:
246                                                 diffuse_tex = slot.texture
247                                                 break
248
249                                 if diffuse_tex:
250                                         st = Statement("texunit", 0)
251                                         if self.textures=="INLINE":
252                                                 ss = Statement("texture2d")
253                                                 ss.sub.append(Statement("min_filter", Token("LINEAR")))
254                                                 ss.sub.append(Statement("storage", Token("RGBA"), tex.image.size[0], tex.image.size[1]))
255                                                 texdata = ""
256                                                 for p in tex.image.pixels:
257                                                         texdata += "\\x%02X"%int(p*255)
258                                                 ss.sub.append(Statement("raw_data", texdata))
259                                                 st.sub.append(ss)
260                                         elif tex.image:
261                                                 st.sub.append(Statement("texture", image_name(tex.image)))
262                                         pass_st.sub.append(st)
263                 statements.append(pass_st)
264
265                 return statements
266
267         def export_material(self, material):
268                 from .datafile import Statement
269                 statements = []
270
271                 cm = get_colormap(material.srgb_colors)
272                 if any(s.use_map_color_diffuse for s in material.texture_slots if s):
273                         statements.append(Statement("diffuse", 1.0, 1.0, 1.0, 1.0))
274                         amb = cm(material.ambient)
275                         statements.append(Statement("ambient", amb, amb, amb, 1.0))
276                 else:
277                         diff = material.diffuse_color*material.diffuse_intensity
278                         statements.append(Statement("diffuse", cm(diff.r), cm(diff.g), cm(diff.b), 1.0))
279                         amb = diff*material.ambient
280                         statements.append(Statement("ambient", cm(amb.r), cm(amb.g), cm(amb.b), 1.0))
281                 spec = material.specular_color*material.specular_intensity
282                 statements.append(Statement("specular", cm(spec.r), cm(spec.g), cm(spec.g), 1.0))
283                 statements.append(Statement("shininess", material.specular_hardness))
284
285                 return statements