-
Notifications
You must be signed in to change notification settings - Fork 1
/
blender_picocad.py
388 lines (336 loc) · 25.7 KB
/
blender_picocad.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
bl_info = {
'name': 'Blender Picocad',
'description': 'Export to picocad.',
'blender': (2, 80, 0),
'category': 'Import-Export',
'location': 'File > Export > Picocad',
'wiki_url': 'https://github.com/davabase/blender_picocad',
'author': 'davabase',
}
import bpy
import os
from bpy_extras.io_utils import ExportHelper
from math import sqrt
from mathutils import Color, Vector, Euler
class PicocadExporter(bpy.types.Operator, ExportHelper):
"""Picocad Exporter"""
bl_idname = 'import_export.picocad'
bl_label = 'Export to Picocad'
bl_options = {'REGISTER'}
# From ExporterHelper.
filename_ext = '.txt'
def execute(self, context):
# Get the filename.
filename = os.path.splitext(bpy.path.basename(context.blend_data.filepath))[0]
if not filename:
filename = 'untitled'
# Get the scene background color.
back_color = color_to_picocad_index(context.scene.world.color)
# We use the image found in the material of the first mesh for the texture.
image = None
width = None
height = None
# Print the header.
# picocad, file name, zoom level, background color, alpha color.
output = 'picocad;{};16;{};0\n'.format(filename, back_color)
output += '{\n'
# We loop through objects instead of meshes since mesh data sticks around even after an object is deleted.
for name, object in bpy.data.objects.items():
if object.type != 'MESH':
continue
data = bpy.data.meshes[name]
location = object.location
double_sided = True
mesh_color = '6'
# Get information from the first assigned material.
if len(object.material_slots) > 0:
material = object.active_material
# Check if backface culling is enabled.
double_sided = not material.use_backface_culling
# Get the first image texture, no need to make this more complicated.
if material.use_nodes:
if not image:
for node in material.node_tree.nodes:
if node.type == 'TEX_IMAGE':
# Only use the texture if it is actually linked.
if len(node.outputs['Color'].links) > 0:
image = node.image
break
# If no image is provided to the material, attempt to get the base color of a principled BSDF shader.
if not image:
for node in material.node_tree.nodes:
if node.type == 'BSDF_PRINCIPLED':
# Only use this shader if it is actually linked.
if len(node.outputs['BSDF'].links) > 0:
base_color = node.inputs[0].default_value
mesh_color = color_to_picocad_index(Color((base_color[0], base_color[1], base_color[2])))
break
else:
self.report({'WARNING'}, 'Material must use nodes to find image texture or mesh color. Ignoring texture export and mesh color.')
# Get the texture size.
# Notice, this expects the texture assigned to the material to be the same one used in the UV map.
if not width or not height:
width = 128
height = 128
if image:
if image.size[0] <= 128 and image.size[1] <= 128:
width = image.size[0]
height = image.size[1]
else:
image = None
self.report({'WARNING'}, 'Image texture must be 128x128 or smaller. Ignoring texture export.')
# Print mesh header.
# name, location, rotation is unused.
output += '{\n'
output += ' name=\'{}\', pos={{{},{},{}}}, rot={{0,0,0}},\n'.format(name, location[0], location[1], location[2])
# Print the vertices.
output += ' v={\n'
object.rotation_mode = 'QUATERNION'
# TODO:
# The axes in picocad are a bit swapped from blender, compensation with a rotaion.
# This requires updating position too.
rotation = object.rotation_quaternion * Euler((0, 0, 0), 'XYZ').to_quaternion()
for v in data.vertices:
# Picocad does not support object rotation or scale so we bake them into the vertices.
vertex = Vector((v.co[0], v.co[1], v.co[2]))
vertex.rotate(rotation)
vertex *= object.scale
output += ' {{{:.1f},{:.1f},{:.1f}}},\n'.format(vertex[0], vertex[1], vertex[2])
# Remove the trailing comma from the last line.
output = output[:-2] + '\n'
output += ' },\n'
# Print the face header.
output += ' f={\n'
for f in data.polygons:
# Optional parameters are: dbl=1, noshade=1, notex=1, prio=1
output += ' {{{}, '.format(','.join(str(v + 1) for v in f.vertices))
if double_sided:
output += 'dbl=1, '
# Set the face color.
output += 'c={}, '.format(mesh_color)
if len(object.data.uv_layers) > 0:
output += 'uv={'
for loop_idx in f.loop_indices:
uv = object.data.uv_layers.active.data[loop_idx].uv
# Texture coordinates in picocad are in divisions of 8.
u = uv.x * width / 8
v = uv.y * height / 8
output += '{:.1f},{:.1f},'.format(u, v)
# Remove the trailing comma from the last line.
output = output[:-1]
output += '} },\n'
else:
# There's no uvmap, just use 0s for every point.
output += 'uv={{{}}} }},\n'.format(','.join('0,0' for v in f.vertices))
# Remove the trailing comma from the last line.
output = output[:-2] + '\n'
output += ' }\n'
output += '},\n'
# Remove the trailing comma from the last line.
output = output[:-2] + '\n'
output += '}%\n'
# Convert the image to a picocad texture.
if image:
texture = ''
column_count = 0
column = ''
for i in range(0, len(image.pixels), 4):
r = image.pixels[i]
g = image.pixels[i + 1]
b = image.pixels[i + 2]
# Ignore alpha.
color = color_to_picocad_color(Color((r, g, b)))
column += color
column_count += 1
if column_count == 128:
column_count = 0
texture += column[::-1] + '\n'
column = ''
# Remove the trailing new line from the last line.
texture = texture[:-1]
# Invert the texture, for some reason it's upsidedown.
output += texture[::-1]
else:
# If no texture image was supplied, use the default.
output += DEFAULT_TEXTURE
with open(self.filepath, 'w') as f:
f.write(output)
return {'FINISHED'}
# Create a mapping of picocad index, to picocad hex color and rgb color.
# Store the hex values as strings since they are going to saved in text anyway.
COLOR_MAP = [
('0', Color((0, 0, 0))), # Black
('1', Color((0.012286489829421043, 0.024157628417015076, 0.08650047332048416))), # Dark Blue
('2', Color((0.20863690972328186, 0.01850022003054619, 0.08650047332048416))), # Violet
('3', Color((0.0, 0.24228115379810333, 0.08228270709514618))), # Dark Green
('4', Color((0.40724021196365356, 0.08437623083591461, 0.0368894599378109))), # Brown
('5', Color((0.11443537473678589, 0.09530746936798096, 0.07818741351366043))), # Dark Gray
('6', Color((0.539479672908783, 0.5457245707511902, 0.5711249709129333))), # Light Gray
('7', Color((1.0, 0.8796226382255554, 0.8069523572921753))), # White
('8', Color((1.0, 0.0, 0.07421357929706573))), # Red
('9', Color((1.0, 0.3662526309490204, 0.0))), # Orange
('a', Color((1.0, 0.8387991189956665, 0.020288560539484024))), # Yellow
('b', Color((0.0, 0.7758224010467529, 0.0368894599378109))), # Light Green
('c', Color((0.022173885256052017, 0.4178851246833801, 1.0))), # Light Blue
('d', Color((0.22696588933467865, 0.18116429448127747, 0.33245155215263367))), # Gray Blue
('e', Color((1.0, 0.18447501957416534, 0.3915724754333496))), # Pink
('f', Color((1.0, 0.6038274168968201, 0.40197786688804626))) # Tan
]
# Cache to speed up lookups of the same color.
COLOR_CACHE = dict()
def color_distance(color1, color2):
# Return how different these colors are based on Euclidian distance.
return sqrt((color2.r - color1.r) ** 2 + (color2.g - color1.g) ** 2 + (color2.b - color1.b) ** 2)
def color_to_picocad(color):
# There are 16 colors in picocad.
# They are defined by either a single character, in the case of textures, or an index in the case of mesh color, background color, and transparency selection.
# Find the closest color to a picocad color and return it.
color_hash = (color.r, color.g, color.b)
if color_hash in COLOR_CACHE.keys():
return COLOR_CACHE[color_hash]
min_dist = float('inf')
closest_color_index = 0
closest_color = 0
for i, (pico, rgb) in enumerate(COLOR_MAP):
dist = color_distance(color, rgb)
if dist < min_dist:
min_dist = dist
closest_color_index = i
closest_color = pico
COLOR_CACHE[color_hash] = (closest_color_index, closest_color)
return (closest_color_index, closest_color)
def color_to_picocad_index(color):
return color_to_picocad(color)[0]
def color_to_picocad_color(color):
return color_to_picocad(color)[1]
# This is the default grid texture that picocad uses.
DEFAULT_TEXTURE = '''00000000eeee8888eeee8888aaaa9999aaaa9999bbbb3333bbbb3333ccccddddccccddddffffeeeeffffeeee7777666677776666555566665555666600000000
00000000eeee8888eeee8888aaaa9999aaaa9999bbbb3333bbbb3333ccccddddccccddddffffeeeeffffeeee7777666677776666555566665555666600000000
00000000eeee8888eeee8888aaaa9999aaaa9999bbbb3333bbbb3333ccccddddccccddddffffeeeeffffeeee7777666677776666555566665555666600000000
00000000eeee8888eeee8888aaaa9999aaaa9999bbbb3333bbbb3333ccccddddccccddddffffeeeeffffeeee7777666677776666555566665555666600000000
000000008888eeee8888eeee9999aaaa9999aaaa3333bbbb3333bbbbddddccccddddcccceeeeffffeeeeffff6666777766667777666655556666555500000000
000000008888eeee8888eeee9999aaaa9999aaaa3333bbbb3333bbbbddddccccddddcccceeeeffffeeeeffff6666777766667777666655556666555500000000
000000008888eeee8888eeee9999aaaa9999aaaa3333bbbb3333bbbbddddccccddddcccceeeeffffeeeeffff6666777766667777666655556666555500000000
000000008888eeee8888eeee9999aaaa9999aaaa3333bbbb3333bbbbddddccccddddcccceeeeffffeeeeffff6666777766667777666655556666555500000000
00000000eeee8888eeee8888aaaa9999aaaa9999bbbb3333bbbb3333ccccddddccccddddffffeeeeffffeeee7777666677776666555566665555666600000000
00000000eeee8888eeee8888aaaa9999aaaa9999bbbb3333bbbb3333ccccddddccccddddffffeeeeffffeeee7777666677776666555566665555666600000000
00000000eeee8888eeee8888aaaa9999aaaa9999bbbb3333bbbb3333ccccddddccccddddffffeeeeffffeeee7777666677776666555566665555666600000000
00000000eeee8888eeee8888aaaa9999aaaa9999bbbb3333bbbb3333ccccddddccccddddffffeeeeffffeeee7777666677776666555566665555666600000000
000000008888eeee8888eeee9999aaaa9999aaaa3333bbbb3333bbbbddddccccddddcccceeeeffffeeeeffff6666777766667777666655556666555500000000
000000008888eeee8888eeee9999aaaa9999aaaa3333bbbb3333bbbbddddccccddddcccceeeeffffeeeeffff6666777766667777666655556666555500000000
000000008888eeee8888eeee9999aaaa9999aaaa3333bbbb3333bbbbddddccccddddcccceeeeffffeeeeffff6666777766667777666655556666555500000000
000000008888eeee8888eeee9999aaaa9999aaaa3333bbbb3333bbbbddddccccddddcccceeeeffffeeeeffff6666777766667777666655556666555500000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'''
def menu_func_export(self, context):
self.layout.operator(PicocadExporter.bl_idname, text='Picocad')
def register():
bpy.utils.register_class(PicocadExporter)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
def unregister():
bpy.utils.unregister_class(PicocadExporter)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
if __name__ == '__main__':
register()