Files
blender-portable-repo/scripts/addons/blender_kitsu/render_review/draw.py
T
2026-03-17 14:58:51 -06:00

208 lines
5.3 KiB
Python

# SPDX-FileCopyrightText: 2021 Blender Studio Tools Authors
#
# SPDX-License-Identifier: GPL-3.0-or-later
import typing
import bpy
import gpu
from gpu_extras.batch import batch_for_shader
APPROVED_COLOR = (0.24, 1, 0.139, 0.7)
PUSHED_TO_EDIT_COLOR = (0.8, .8, 0.1, 0.5)
Float2 = typing.Tuple[float, float]
Float3 = typing.Tuple[float, float, float]
Float4 = typing.Tuple[float, float, float, float]
LINE_WIDTH = 6
class LineDrawer:
def draw(self, coords: typing.List[Float2], colors: typing.List[Float4]):
line_shader = gpu.shader.from_builtin('FLAT_COLOR')
global LINE_WIDTH
if not coords:
return
gpu.state.blend_set("ALPHA")
gpu.state.line_width_set(LINE_WIDTH)
batch = batch_for_shader(
line_shader, 'LINES',
{"pos": coords, "color": colors}
)
batch.draw(line_shader)
def get_strip_rectf(strip) -> Float4:
# Get x and y in terms of the grid's frames and channels.
x1 = strip.frame_final_start
x2 = strip.frame_final_end
# Seems to be a 5 % offset from channel top start of strip.
y1 = strip.channel + 0.05
y2 = strip.channel - 0.05 + 1
return x1, y1, x2, y2
def line_in_strip(
strip_coords: Float4,
pixel_size_x: float,
color: Float4,
line_height_factor: float,
out_coords: typing.List[Float2],
out_colors: typing.List[Float4],
):
# Strip coords.
s_x1, s_y1, s_x2, s_y2 = strip_coords
# Calculate line height with factor.
line_y = (1 - line_height_factor) * s_y1 + line_height_factor * s_y2
# if strip is shorter than line_width use stips s_x2
# line_x2 = s_x1 + line_width if (s_x2 - s_x1 > line_width) else s_x2
line_x2 = s_x2
# Be careful not to draw over the current frame line.
cf_x = bpy.context.scene.frame_current_final
# TODO(Sybren): figure out how to pass one colour per line,
# instead of one colour per vertex.
out_coords.append((s_x1, line_y))
out_colors.append(color)
if s_x1 < cf_x < line_x2:
# Bad luck, the line passes our strip, so draw two lines.
out_coords.append((cf_x - pixel_size_x, line_y))
out_colors.append(color)
out_coords.append((cf_x + pixel_size_x, line_y))
out_colors.append(color)
out_coords.append((line_x2, line_y))
out_colors.append(color)
def draw_callback_px(line_drawer: LineDrawer):
global LINE_WIDTH
context = bpy.context
if not context.scene.sequence_editor:
return
# From . import shown_strips.
region = context.region
xwin1, ywin1 = region.view2d.region_to_view(0, 0)
xwin2, ywin2 = region.view2d.region_to_view(region.width, region.height)
one_pixel_further_x, one_pixel_further_y = region.view2d.region_to_view(1, 1)
pixel_size_x = one_pixel_further_x - xwin1
# Strips = shown_strips(context).
strips = context.scene.sequence_editor.sequences_all
coords = [] # type: typing.List[Float2]
colors = [] # type: typing.List[Float4]
# Collect all the lines (vertex coords + vertex colours) to draw.
for strip in strips:
# Get corners (x1, y1), (x2, y2) of the strip rectangle in px region coords.
strip_coords = get_strip_rectf(strip)
# Check if any of the coordinates are out of bounds.
if (
strip_coords[0] > xwin2
or strip_coords[2] < xwin1
or strip_coords[1] > ywin2
or strip_coords[3] < ywin1
):
continue
if strip.rr.is_approved:
line_in_strip(
strip_coords,
pixel_size_x,
APPROVED_COLOR,
0.05,
coords,
colors,
)
elif strip.rr.is_pushed_to_edit:
line_in_strip(
strip_coords,
pixel_size_x,
PUSHED_TO_EDIT_COLOR,
0.05,
coords,
colors,
)
line_drawer.draw(coords, colors)
def tag_redraw_all_sequencer_editors():
context = bpy.context
# Py cant access notifiers.
for window in context.window_manager.windows:
for area in window.screen.areas:
if area.type == "SEQUENCE_EDITOR":
for region in area.regions:
if region.type == "WINDOW":
region.tag_redraw()
# This is a list so it can be changed instead of set
# if it is only changed, it does not have to be declared as a global everywhere
cb_handle = []
def callback_enable():
global cb_handle
if cb_handle:
return
# Doing GPU stuff in the background crashes Blender, so let's not.
if bpy.app.background:
return
line_drawer = LineDrawer()
cb_handle[:] = (
bpy.types.SpaceSequenceEditor.draw_handler_add(
draw_callback_px, (line_drawer,), "WINDOW", "POST_VIEW"
),
)
tag_redraw_all_sequencer_editors()
def callback_disable():
global cb_handle
if not cb_handle:
return
try:
bpy.types.SpaceSequenceEditor.draw_handler_remove(cb_handle[0], "WINDOW")
except ValueError:
# Thrown when already removed.
pass
cb_handle.clear()
tag_redraw_all_sequencer_editors()
# ---------REGISTER ----------.
def register():
callback_enable()
def unregister():
callback_disable()