bone_widget/icon_utils.py

124 lines
3.5 KiB
Python
Raw Normal View History

2022-10-28 23:23:06 +02:00
import bpy
import bmesh
import numpy as np
import bgl
from mathutils import Vector, Matrix
import gpu
from gpu_extras.batch import batch_for_shader
def bounds_2d_co(coords, width, height):
from bpy_extras.view3d_utils import location_3d_to_region_2d as space_2d
region = bpy.context.region
rv3d = bpy.context.space_data.region_3d
co_2d = [space_2d(region, rv3d, co) for co in coords]
2023-01-18 16:02:42 +01:00
print("co_2d", co_2d)
2022-10-28 23:23:06 +02:00
x_value = sorted(co_2d, key=lambda x:x[0])
y_value = sorted(co_2d, key=lambda x:x[1])
min_x = x_value[0][0]
min_y = y_value[0][1]
box_width = x_value[-1][0] - min_x
box_height = y_value[-1][1] - min_y
x_margin = 1 / width # one pixel margin
y_margin = 1 / height
scale_fac = 2 / max(box_width, box_height)
if box_width < box_height :
center_offset = (box_height - box_width) /2
min_x -= center_offset
else :
center_offset = (box_width - box_height) /2
min_y -= center_offset
co_2d_bounds = []
for co in co_2d:
x = (co[0] - min_x) *scale_fac * (1 - 2*x_margin) -1 + x_margin#+ x_offset
y = (co[1] - min_y) *scale_fac * (1 - 2*y_margin) -1 + y_margin#-height/2 #* (1-y_offset) #+ y_offset
co_2d_bounds.append(Vector((x, y)))
return co_2d_bounds
def render_widget(shape, filepath, width=32, height=32) :
dg = bpy.context.evaluated_depsgraph_get()
bm = bmesh.new()
bm.from_object(shape, dg)
2023-01-18 16:02:42 +01:00
width *= 2
height *= 2
2022-10-28 23:23:06 +02:00
coords = [shape.matrix_world @ v.co for v in bm.verts]
coords = bounds_2d_co(coords, width, height)
indices = [(e.verts[0].index, e.verts[1].index) for e in bm.edges]
bm.free()
offscreen = gpu.types.GPUOffScreen(width, height)
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'LINES', {"pos": coords}, indices=indices)
with offscreen.bind():
2023-01-18 16:02:42 +01:00
fb = gpu.state.active_framebuffer_get()
fb.clear(color=(0.0, 0.0, 0.0, 0.0))
2022-10-28 23:23:06 +02:00
with gpu.matrix.push_pop():
# reset matrices -> use normalized device coordinates [-1, 1]
gpu.matrix.load_matrix(Matrix.Identity(4))
gpu.matrix.load_projection_matrix(Matrix.Identity(4))
shader.bind()
2023-01-18 16:02:42 +01:00
gpu.state.line_width_set(4*2)
#bgl.glEnable(bgl.GL_BLEND)
#bgl.glEnable( bgl.GL_LINE_SMOOTH )
shader.uniform_float("color", (0, 0, 0, 0.2))
2022-10-28 23:23:06 +02:00
batch.draw(shader)
2023-01-18 16:02:42 +01:00
gpu.state.line_width_set(2*2)
2022-10-28 23:23:06 +02:00
shader.uniform_float("color", (0.85, 0.85, 0.85, 1))
batch.draw(shader)
2023-01-18 16:02:42 +01:00
buffer = fb.read_color(0, 0, width, height, 4, 0, 'FLOAT')
buffer.dimensions = width * height * 4
#buffer = bgl.Buffer(bgl.GL_BYTE, width * height * 4)
#bgl.glReadBuffer(bgl.GL_BACK)
#bgl.glReadPixels(0, 0, width, height, bgl.GL_RGBA, bgl.GL_UNSIGNED_BYTE, buffer)
2022-10-28 23:23:06 +02:00
offscreen.free()
#icon_name = '.' + shape.name + '_icon.png'
2023-01-18 16:02:42 +01:00
icon_name = f'.{shape.name}_icon.png'
2022-10-28 23:23:06 +02:00
image = bpy.data.images.get(icon_name)
if image:
bpy.data.images.remove(image)
2023-01-18 16:02:42 +01:00
image = bpy.data.images.new(icon_name, width, height, alpha=True, float_buffer=True)
2022-10-28 23:23:06 +02:00
#image_data = np.asarray(buffer, dtype=np.uint8)
#image.pixels.foreach_set(image_data.flatten()/255)
#image_data = np.asarray(buffer, dtype=np.uint8)
2023-01-18 16:02:42 +01:00
image.pixels.foreach_set(buffer)
image.scale(int(width/2), int(height/2))
image.filepath_raw = str(filepath)
image.save()
2022-10-28 23:23:06 +02:00
2023-01-18 16:02:42 +01:00
bpy.data.images.remove(image)
2022-10-28 23:23:06 +02:00