Utility to generate geometry icons
authorCampbell Barton <ideasman42@gmail.com>
Tue, 24 Apr 2018 05:34:33 +0000 (07:34 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 24 Apr 2018 05:52:57 +0000 (07:52 +0200)
release/datafiles/blender_icons_geom.py [new file with mode: 0644]

diff --git a/release/datafiles/blender_icons_geom.py b/release/datafiles/blender_icons_geom.py
new file mode 100644 (file)
index 0000000..b98f5a5
--- /dev/null
@@ -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()