Utility to generate geometry icons
This commit is contained in:
parent
10f0f4b06f
commit
c1b310c32b
|
@ -0,0 +1,207 @@
|
|||
# Apache License, Version 2.0
|
||||
|
||||
"""
|
||||
Example Usage
|
||||
=============
|
||||
|
||||
Command line::
|
||||
|
||||
./blender.bin \
|
||||
icon_file.blend --background --python ./release/datafiles/blender_icons_geom.py -- \
|
||||
--output-dir=./release/datafiles/blender_icons_geom
|
||||
|
||||
Icon Format
|
||||
===========
|
||||
|
||||
This is a simple binary format (all bytes, so no endian).
|
||||
|
||||
The header is 8 bytes:
|
||||
|
||||
:0..3: ``VCO``: identifier.
|
||||
:4: ``0``: icon file version.
|
||||
:5: icon size-x.
|
||||
:6: icon size-y.
|
||||
:7: icon start-x.
|
||||
:8: icon start-y.
|
||||
|
||||
Icon width and height are for icons that don't use the full byte range
|
||||
(so we don't get bad alignment for 48 pixel grid for eg).
|
||||
|
||||
Start values are currently unused.
|
||||
|
||||
After the header, the remaining length of the data defines the geometry size.
|
||||
|
||||
:6 bytes each: triangle (XY) locations.
|
||||
:12 bytes each: triangle (RGBA) locations.
|
||||
|
||||
All coordinates are written, then all colors.
|
||||
|
||||
Since this is a binary format which isn't intended for general use
|
||||
the ``.dat`` file extension should be used.
|
||||
"""
|
||||
|
||||
# This script writes out geometry-icons.
|
||||
import bpy
|
||||
|
||||
|
||||
class TriMesh:
|
||||
"""
|
||||
Triangulate, may apply other changes here too.
|
||||
"""
|
||||
__slots__ = ("object", "mesh")
|
||||
|
||||
def __init__(self, ob):
|
||||
self.object = ob
|
||||
self.mesh = None
|
||||
|
||||
def __enter__(self):
|
||||
self.mesh = self._tri_copy_from_object(self.object)
|
||||
return self.mesh
|
||||
|
||||
def __exit__(self, *args):
|
||||
bpy.data.meshes.remove(self.mesh)
|
||||
|
||||
@staticmethod
|
||||
def _tri_copy_from_object(ob):
|
||||
import bmesh
|
||||
assert(ob.type == 'MESH')
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(ob.data)
|
||||
bmesh.ops.triangulate(bm, faces=bm.faces)
|
||||
me = bpy.data.meshes.new(ob.name + ".copy")
|
||||
bm.to_mesh(me)
|
||||
bm.free()
|
||||
return me
|
||||
|
||||
|
||||
def write_mesh_data_lists(me):
|
||||
me_loops = me.loops[:]
|
||||
me_loops_color = me.vertex_colors.active.data[:]
|
||||
me_verts = me.vertices[:]
|
||||
me_polys = me.polygons[:]
|
||||
|
||||
# 100 layers of depth
|
||||
me_polys.sort(key=lambda p: int(p.center.z * 100))
|
||||
|
||||
tris_coords = []
|
||||
tris_colors = []
|
||||
|
||||
for p in me_polys:
|
||||
l_sta = p.loop_start
|
||||
l_len = p.loop_total
|
||||
loops_poly = me_loops[l_sta:l_sta + l_len]
|
||||
color_poly = me_loops_color[l_sta:l_sta + l_len]
|
||||
i0 = 0
|
||||
i1 = 1
|
||||
|
||||
# we only write tris now
|
||||
assert(len(loops_poly) == 3)
|
||||
|
||||
for i2 in range(2, l_len):
|
||||
l0 = loops_poly[i0]
|
||||
l1 = loops_poly[i1]
|
||||
l2 = loops_poly[i2]
|
||||
|
||||
c0 = color_poly[i0]
|
||||
c1 = color_poly[i1]
|
||||
c2 = color_poly[i2]
|
||||
|
||||
v0 = me_verts[l0.vertex_index]
|
||||
v1 = me_verts[l1.vertex_index]
|
||||
v2 = me_verts[l2.vertex_index]
|
||||
|
||||
tris_coords.append((
|
||||
v0.co.xy[:],
|
||||
v1.co.xy[:],
|
||||
v2.co.xy[:],
|
||||
))
|
||||
# Color as RGBA for each tri
|
||||
tris_colors.append(
|
||||
[[int(c * 255) for c in cn.color] for cn in (c0, c1, c2)]
|
||||
)
|
||||
i1 = i2
|
||||
return (tris_coords, tris_colors)
|
||||
|
||||
|
||||
def write_mesh_to_py(fh, me):
|
||||
|
||||
def float_as_byte(f):
|
||||
# -1..1 -> 0..255
|
||||
f = (f + 1.0) * 0.5
|
||||
f = int(round(f * 255))
|
||||
return min(max(f, 0), 255)
|
||||
|
||||
tris_coords, tris_colors = write_mesh_data_lists(me)
|
||||
|
||||
fw = fh.write
|
||||
|
||||
# Header (version 0).
|
||||
fw(b'VCO\x00')
|
||||
# Width, Height
|
||||
fw(bytes((255, 255)))
|
||||
# X, Y
|
||||
fw(bytes((0, 0)))
|
||||
|
||||
for tri_coords in tris_coords:
|
||||
for vert in tri_coords:
|
||||
fw(bytes([float_as_byte(c) for c in vert]))
|
||||
for tri_color in tris_colors:
|
||||
for color in tri_color:
|
||||
fw(bytes(color))
|
||||
|
||||
|
||||
def create_argparse():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--output-dir",
|
||||
dest="output_dir",
|
||||
default=".",
|
||||
type=str,
|
||||
metavar="DIR",
|
||||
required=False,
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
def main():
|
||||
import os
|
||||
import sys
|
||||
parser = create_argparse()
|
||||
if "--" in sys.argv:
|
||||
argv = sys.argv[sys.argv.index("--") + 1:]
|
||||
else:
|
||||
argv = []
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
objects = []
|
||||
|
||||
for ob in bpy.data.objects:
|
||||
|
||||
# Skip non-mesh objects
|
||||
if ob.type != 'MESH':
|
||||
continue
|
||||
name = ob.name
|
||||
|
||||
# Skip copies of objects
|
||||
if name.rpartition(".")[2].isdigit():
|
||||
continue
|
||||
|
||||
if not ob.data.vertex_colors:
|
||||
print("Skipping:", name, "(no vertex colors)")
|
||||
continue
|
||||
|
||||
objects.append((name, ob))
|
||||
|
||||
objects.sort(key=lambda a: a[0])
|
||||
|
||||
for name, ob in objects:
|
||||
filename = os.path.join(args.output_dir, name + ".dat")
|
||||
print("Writing:", filename)
|
||||
with open(filename, 'wb') as fh:
|
||||
with TriMesh(ob) as me:
|
||||
write_mesh_to_py(fh, me)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue