]> git.tdb.fi Git - libs/gl.git/blob - blender/io_mspgl/export_texture.py
Make texture channel handling in the Blender exporter more flexible
[libs/gl.git] / blender / io_mspgl / export_texture.py
1 import os
2 import base64
3 import codecs
4
5 def pixels_to_rgba(pixels):
6         return (int(p*255) for p in pixels)
7
8 def pixels_to_rgb(pixels):
9         for i in range(0, len(pixels), 4):
10                 yield int(pixels[i]*255)
11                 yield int(pixels[i+1]*255)
12                 yield int(pixels[i+2]*255)
13
14 def pixels_to_rgb_invert(pixels, mask):
15         for i in range(0, len(pixels), 4):
16                 r = int(pixels[i]*255)
17                 yield 255-r if mask&1 else r
18                 g = int(pixels[i+1]*255)
19                 yield 255-g if mask&2 else g
20                 b = int(pixels[i+2]*255)
21                 yield 255-b if mask&4 else b
22
23 def pixels_to_gray(pixels):
24         for i in range(0, len(pixels), 4):
25                 yield int((pixels[i]+pixels[i+1]+pixels[i+2])*255/3)
26
27 class TextureExporter:
28         def export_texture(self, tex_node, channels=['R', 'G', 'B']):
29                 image = tex_node.image
30                 from .datafile import RawData, Resource, Statement, Token
31                 tex_res = Resource(image.name+".tex", "texture")
32
33                 tex_res.statements.append(Statement("type", Token("\\2d")))
34
35                 if tex_node.use_mipmap:
36                         tex_res.statements.append(Statement("generate_mipmap", True))
37
38                 colorspace = image.colorspace_settings.name
39                 if len(channels)==1 and colorspace=='sRGB':
40                         raise Exception("Unsupported configuration on texture {}: Grayscale with sRGB".format(image.name))
41
42                 invert_mask = sum(1<<i for i, c in enumerate(channels) if c[0]=='~')
43
44                 from .util import basename
45                 fn = basename(image.filepath)
46                 if not invert_mask and fn:
47                         if not tex_node.use_mipmap:
48                                 tex_res.statements.append(Statement("mipmap_levels", 1))
49                         srgb = "_srgb" if colorspace=='sRGB' else ""
50                         tex_res.statements.append(Statement("external_image"+srgb, fn))
51                 else:
52                         if len(channels)==4:
53                                 fmt = 'SRGB8_ALPHA8' if colorspace=='sRGB' else 'RGBA8'
54                         elif len(channels)==1:
55                                 fmt = 'LUMINANCE8'
56                         else:
57                                 fmt = 'SRGB8' if colorspace=='sRGB' else 'RGB8'
58
59                         tex_res.statements.append(Statement("storage", Token(fmt), image.size[0], image.size[1]))
60
61                         pixels = tuple(image.pixels)
62                         texdata = ""
63                         if len(channels)==4:
64                                 texdata = pixels_to_rgba(pixels)
65                         elif len(channels)==1:
66                                 texdata = pixels_to_gray(pixels)
67                         elif invert_mask:
68                                 texdata = pixels_to_rgb_invert(pixels, invert_mask)
69                         else:
70                                 texdata = pixels_to_rgb(pixels)
71
72                         data = RawData(image.name+".mdr", bytes(texdata))
73                         tex_res.statements.append(tex_res.create_reference_statement("external_data", data))
74
75                 return tex_res
76
77 class SamplerExporter:
78         def export_sampler(self, tex_node):
79                 from .datafile import Resource, Statement, Token
80                 samp_res = Resource(self.get_sampler_name(tex_node), "sampler")
81
82                 use_interpolation = tex_node.interpolation!='Closest'
83                 if use_interpolation:
84                         if tex_node.use_mipmap:
85                                 samp_res.statements.append(Statement("filter", Token('LINEAR_MIPMAP_LINEAR')))
86                         else:
87                                 samp_res.statements.append(Statement("filter", Token('LINEAR')))
88                         samp_res.statements.append(Statement("max_anisotropy", tex_node.max_anisotropy))
89                 else:
90                         if tex_node.use_mipmap:
91                                 samp_res.statements.append(Statement("filter", Token('NEAREST_MIPMAP_NEAREST')))
92                         else:
93                                 samp_res.statements.append(Statement("filter", Token('NEAREST')))
94
95                 if tex_node.extension=="REPEAT":
96                         samp_res.statements.append(Statement("wrap", Token('REPEAT')))
97                 elif tex_node.extension=="EXTEND":
98                         samp_res.statements.append(Statement("wrap", Token('CLAMP_TO_EDGE')))
99                 elif tex_node.extension=="CLIP":
100                         samp_res.statements.append(Statement("wrap", Token('CLAMP_TO_BORDER')))
101                         samp_res.statements.append(Statement("border_color", 0.0, 0.0, 0.0, 0.0))
102
103                 return samp_res
104
105         def get_sampler_name(self, tex_node):
106                 name_parts = []
107
108                 use_interpolation = tex_node.interpolation!='Closest'
109                 name_parts.append("linear" if use_interpolation else "nearest")
110                 if tex_node.use_mipmap:
111                         name_parts.append("mip")
112                 if use_interpolation and tex_node.max_anisotropy>1:
113                         name_parts.append("aniso{:g}x".format(tex_node.max_anisotropy))
114                 if tex_node.extension!="REPEAT":
115                         name_parts.append("clip" if tex_node.extension=="CLIP" else "clamp")
116
117                 return "_".join(name_parts)+".samp"