Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release/datafiles/blender_icons_geom.py')
-rw-r--r--release/datafiles/blender_icons_geom.py330
1 files changed, 330 insertions, 0 deletions
diff --git a/release/datafiles/blender_icons_geom.py b/release/datafiles/blender_icons_geom.py
new file mode 100644
index 00000000000..bb7a6568767
--- /dev/null
+++ b/release/datafiles/blender_icons_geom.py
@@ -0,0 +1,330 @@
+# 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 object_material_colors(ob):
+ material_colors = []
+ color_default = (1.0, 1.0, 1.0, 1.0)
+ for slot in ob.material_slots:
+ material = slot.material
+ color = color_default
+ if material is not None and material.use_nodes:
+ node_tree = material.node_tree
+ if node_tree is not None:
+ color = next((
+ node.outputs[0].default_value[:]
+ for node in node_tree.nodes
+ if node.type == 'RGB'
+ ), color_default)
+ material_colors.append(color)
+ return material_colors
+
+
+def object_child_map(objects):
+ objects_children = {}
+ for ob in objects:
+ ob_parent = ob.parent
+ # Get the root.
+ if ob_parent is not None:
+ while ob_parent and ob_parent.parent:
+ ob_parent = ob_parent.parent
+ if ob_parent is not None:
+ objects_children.setdefault(ob_parent, []).append(ob)
+ for ob_all in objects_children.values():
+ ob_all.sort(key=lambda ob: ob.name)
+ return objects_children
+
+
+def mesh_data_lists_from_mesh(me, material_colors):
+ me_loops = me.loops[:]
+ me_loops_color = me.vertex_colors.active.data[:]
+ me_verts = me.vertices[:]
+ me_polys = me.polygons[:]
+
+ tris_data = []
+
+ for p in me_polys:
+ # Backface culling (allows using spheres without tedious manual deleting).
+ if p.normal.z <= 0.0:
+ continue
+
+ material_index = p.material_index
+ if material_index < len(material_colors):
+ base_color = material_colors[p.material_index]
+ else:
+ base_color = (1.0, 1.0, 1.0, 1.0)
+
+ 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_data.append((
+ # float depth
+ p.center.z,
+ # XY coords.
+ (
+ v0.co.xy[:],
+ v1.co.xy[:],
+ v2.co.xy[:],
+ ),
+ # RGBA color.
+ tuple((
+ [int(c * b * 255) for c, b in zip(cn.color, base_color)]
+ for cn in (c0, c1, c2)
+ )),
+ ))
+ i1 = i2
+ return tris_data
+
+
+def mesh_data_lists_from_objects(ob_parent, ob_children):
+ tris_data = []
+
+ has_parent = False
+ if ob_children:
+ parent_matrix = ob_parent.matrix_world.copy()
+ parent_matrix_inverted = parent_matrix.inverted()
+
+ for ob in (ob_parent, *ob_children):
+ with TriMesh(ob) as me:
+ if has_parent:
+ me.transform(parent_matrix_inverted * ob.matrix_world)
+
+ tris_data.extend(
+ mesh_data_lists_from_mesh(
+ me,
+ object_material_colors(ob),
+ )
+ )
+ has_parent = True
+ return tris_data
+
+
+def write_mesh_to_py(fh, ob, ob_children):
+
+ def float_as_byte(f, axis_range):
+ assert(axis_range <= 255)
+ # -1..1 -> 0..255
+ f = (f + 1.0) * 0.5
+ f = int(round(f * axis_range))
+ return min(max(f, 0), axis_range)
+
+ def vert_as_byte_pair(v):
+ return (
+ float_as_byte(v[0], coords_range_align[0]),
+ float_as_byte(v[1], coords_range_align[1]),
+ )
+
+ tris_data = mesh_data_lists_from_objects(ob, ob_children)
+
+ # 100 levels of Z depth, round to avoid differences from precision error
+ # causing different computers to write triangles in more or less random order.
+ tris_data.sort(key=lambda data: int(data[0] * 100))
+
+ if 0:
+ # make as large as we can, keeping alignment
+ def size_scale_up(size):
+ assert(size != 0)
+ while size * 2 <= 255:
+ size *= 2
+ return size
+
+ coords_range = (
+ size_scale_up(ob.get("size_x")) or 255,
+ size_scale_up(ob.get("size_y")) or 255,
+ )
+ else:
+ # disable for now
+ coords_range = 255, 255
+
+ # Pixel size needs to be increased since a pixel needs one extra geom coordinate,
+ # if we're writing 32 pixel, align verts to 33.
+ coords_range_align = tuple(min(c + 1, 255) for c in coords_range)
+
+ print("Writing:", fh.name, coords_range)
+
+ fw = fh.write
+
+ # Header (version 0).
+ fw(b'VCO\x00')
+ # Width, Height
+ fw(bytes(coords_range))
+ # X, Y
+ fw(bytes((0, 0)))
+
+ for (_, tri_coords, _) in tris_data:
+ for vert in tri_coords:
+ fw(bytes(vert_as_byte_pair(vert)))
+ for (_, _, tri_color) in tris_data:
+ 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,
+ help="Directory to write icons to.",
+ )
+ parser.add_argument(
+ "--group",
+ dest="group",
+ default="",
+ type=str,
+ metavar="GROUP",
+ required=False,
+ help="Group name to export from (otherwise export all objects).",
+ )
+ 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 = []
+
+ if args.group:
+ group = bpy.data.collections.get(args.group)
+ if group is None:
+ print(f"Group {args.group!r} not found!")
+ return
+ objects_source = group.objects
+ del group
+ else:
+ objects_source = bpy.data.objects
+
+ for ob in objects_source:
+
+ # 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])
+
+ objects_children = object_child_map(bpy.data.objects)
+
+ for name, ob in objects:
+ if ob.parent:
+ continue
+ filename = os.path.join(args.output_dir, name + ".dat")
+ with open(filename, 'wb') as fh:
+ write_mesh_to_py(fh, ob, objects_children.get(ob, []))
+
+
+if __name__ == "__main__":
+ main()