4 def pixels_to_rgba(pixels):
5 return (int(p*255) for p in pixels)
7 def pixels_to_rgb(pixels):
8 for i in range(0, len(pixels), 4):
9 yield int(pixels[i]*255)
10 yield int(pixels[i+1]*255)
11 yield int(pixels[i+2]*255)
13 def pixels_to_rgb_invert(pixels, mask):
14 for i in range(0, len(pixels), 4):
15 r = int(pixels[i]*255)
16 yield 255-r if mask&1 else r
17 g = int(pixels[i+1]*255)
18 yield 255-g if mask&2 else g
19 b = int(pixels[i+2]*255)
20 yield 255-b if mask&4 else b
22 def pixels_to_gray(pixels):
23 for i in range(0, len(pixels), 4):
24 yield int((pixels[i]+pixels[i+1]+pixels[i+2])*255/3)
26 def pixels_to_single_channel(pixels, channel):
27 for i in range(0, len(pixels), 4):
28 yield int(pixels[i+channel]*255)
30 class TextureExporter:
31 def export_texture(self, tex_node, channels=['R', 'G', 'B']):
32 image = tex_node.image
33 from .datafile import RawData, Resource, Statement, Token
34 tex_res = Resource(self.get_texture_name(tex_node, channels), "texture")
36 tex_res.statements.append(Statement("type", Token("\\2d")))
38 if tex_node.use_mipmap:
39 tex_res.statements.append(Statement("generate_mipmap", True))
41 colorspace = image.colorspace_settings.name
42 if len(channels)==1 and colorspace=='sRGB':
43 raise Exception("Unsupported configuration on texture {}: Grayscale with sRGB".format(image.name))
45 invert_mask = sum(1<<i for i, c in enumerate(channels) if c[0]=='~')
47 fn = bpy.path.basename(image.filepath)
48 native_channels = None
50 abs_path = bpy.path.abspath(image.filepath)
51 if os.path.exists(abs_path):
53 native_bpp = imbuf.load(bpy.path.abspath(image.filepath)).planes
55 native_channels = ['R', 'G', 'B', 'A']
57 native_channels = ['R', 'G', 'B']
59 native_channels = ['Y']
61 if not invert_mask and channels==native_channels:
62 if not tex_node.use_mipmap:
63 tex_res.statements.append(Statement("mipmap_levels", 1))
64 srgb = "_srgb" if colorspace=='sRGB' else ""
65 tex_res.statements.append(Statement("external_image"+srgb, fn))
68 fmt = 'SRGB8_ALPHA8' if colorspace=='sRGB' else 'RGBA8'
69 elif len(channels)==1:
72 fmt = 'SRGB8' if colorspace=='sRGB' else 'RGB8'
74 tex_res.statements.append(Statement("storage", Token(fmt), image.size[0], image.size[1]))
76 pixels = tuple(image.pixels)
79 texdata = pixels_to_rgba(pixels)
80 elif len(channels)==1:
82 texdata = pixels_to_gray(pixels)
84 texdata = pixels_to_single_channel(pixels, "RGBA".index(channels[0]))
86 texdata = pixels_to_rgb_invert(pixels, invert_mask)
88 texdata = pixels_to_rgb(pixels)
90 data = RawData(os.path.splitext(tex_res.name)[0]+".mdr", bytes(texdata))
91 tex_res.statements.append(tex_res.create_reference_statement("external_data", data))
95 def get_texture_name(self, tex_node, channels):
96 image_name = tex_node.image.name
97 if len(channels)==1 and channels[0]!='Y':
98 image_name += "_"+channels[0]
99 return image_name+".tex"
101 class SamplerExporter:
102 def export_sampler(self, tex_node):
103 from .datafile import Resource, Statement, Token
104 samp_res = Resource(self.get_sampler_name(tex_node), "sampler")
106 use_interpolation = tex_node.interpolation!='Closest'
107 if use_interpolation:
108 if tex_node.use_mipmap:
109 samp_res.statements.append(Statement("filter", Token('LINEAR_MIPMAP_LINEAR')))
111 samp_res.statements.append(Statement("filter", Token('LINEAR')))
112 samp_res.statements.append(Statement("max_anisotropy", tex_node.max_anisotropy))
114 if tex_node.use_mipmap:
115 samp_res.statements.append(Statement("filter", Token('NEAREST_MIPMAP_NEAREST')))
117 samp_res.statements.append(Statement("filter", Token('NEAREST')))
119 if tex_node.extension=="REPEAT":
120 samp_res.statements.append(Statement("wrap", Token('REPEAT')))
121 elif tex_node.extension=="EXTEND":
122 samp_res.statements.append(Statement("wrap", Token('CLAMP_TO_EDGE')))
123 elif tex_node.extension=="CLIP":
124 samp_res.statements.append(Statement("wrap", Token('CLAMP_TO_BORDER')))
125 samp_res.statements.append(Statement("border_color", 0.0, 0.0, 0.0, 0.0))
129 def get_sampler_name(self, tex_node):
132 use_interpolation = tex_node.interpolation!='Closest'
133 name_parts.append("linear" if use_interpolation else "nearest")
134 if tex_node.use_mipmap:
135 name_parts.append("mip")
136 if use_interpolation and tex_node.max_anisotropy>1:
137 name_parts.append("aniso{:g}x".format(tex_node.max_anisotropy))
138 if tex_node.extension!="REPEAT":
139 name_parts.append("clip" if tex_node.extension=="CLIP" else "clamp")
141 return "_".join(name_parts)+".samp"