gp_toolbox/handler_draw_cam.py

139 lines
4.2 KiB
Python

import bpy
import gpu
import bgl
# import blf
from gpu_extras.batch import batch_for_shader
from bpy_extras.view3d_utils import location_3d_to_region_2d
from bpy.app.handlers import persistent
def view3d_camera_border(context, cam):
## based on https://blender.stackexchange.com/questions/6377/coordinates-of-corners-of-camera-view-border
# cam = context.scene.camera
frame = cam.data.view_frame(scene=context.scene)
# to world-space
frame = [cam.matrix_world @ v for v in frame]
# to pixelspace
region, rv3d = context.region, context.space_data.region_3d
frame_px = [location_3d_to_region_2d(region, rv3d, v) for v in frame]
return frame_px
def draw_cam_frame_callback(self, context):
if context.region_data.view_perspective != 'CAMERA':
return
if context.scene.camera.name != 'draw_cam':
return
main_cam = context.scene.camera.parent
if not main_cam:
return
# if context.area != self._draw_area:
# return
# green -> (0.06, 0.4, 0.040, 0.6)
# orange -> (0.45, 0.18, 0.03, 1.0)
osd_color = (0.06, 0.4, 0.040, 0.4)
frame_point = view3d_camera_border(context, main_cam)
self.shader_2d = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
self.screen_framing = batch_for_shader(
self.shader_2d, 'LINE_LOOP', {"pos": frame_point})
bgl.glLineWidth(1)
self.shader_2d.bind()
self.shader_2d.uniform_float("color", osd_color)
self.screen_framing.draw(self.shader_2d)
# Reset
# bgl.glLineWidth(1)
# # Display Text
# if self.use_osd_text:
# font_id = 0
# dpi = context.preferences.system.dpi
# # Display current frame text
# blf.color(font_id, *osd_color) # unpack color in argument
# blf.position(font_id, context.region.width/3, 15, 0) # context.region.height-
# blf.size(font_id, 16, dpi)
# blf.draw(font_id, f'Draw cam')
## As a modal for tests
class GPTB_OT_cam_frame_draw(bpy.types.Operator):
bl_idname = "gp.draw_cam_frame"
bl_label = "Draw Cam Frame"
bl_description = "Draw the camera frame using a modal"
bl_options = {"REGISTER"} # , "INTERNAL"
# @classmethod
# def poll(cls, context):
# return True
def invoke(self, context, event):
## screen color frame
# r = bpy.context.region
# w = r.width
# h = r.height
# self.shader_2d = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
# self.screen_framing = batch_for_shader(
# self.shader_2d, 'LINE_LOOP', {"pos": [(0,0), (0,h), (w,h), (w,0)]})
## OpenGL handler
self._draw_area = context.area
args = (self, context)
self._handle = bpy.types.SpaceView3D.draw_handler_add(
draw_cam_frame_callback, args, "WINDOW", "POST_PIXEL")
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
def exit(self, context):
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
context.area.tag_redraw()
def modal(self, context, event):
if event.type in {'ESC'}:
self.exit(context)
return {"CANCELLED"}
return {'PASS_THROUGH'}
# return {'RUNNING_MODAL'}
class DrawClass:
def __init__(self, context):
# print("INIT")
self._handle = bpy.types.SpaceView3D.draw_handler_add(
draw_cam_frame_callback, args, "WINDOW", "POST_PIXEL")
def remove_handle(self):
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
### --- REGISTER ---
def register():
if not bpy.app.background:
bpy.utils.register_class(GPTB_OT_cam_frame_draw)
# ha = DrawClass()
# _handle = bpy.types.SpaceView3D.draw_handler_add(
# draw_cam_frame_callback, args, "WINDOW", "POST_PIXEL")
def unregister():
if not bpy.app.background:
bpy.utils.unregister_class(GPTB_OT_cam_frame_draw)
# ha.remove_handle()
# bpy.types.SpaceView3D.draw_handler_remove(_handle, 'WINDOW')
# if 'draw_cam_frame_callback' in [hand.__name__ for hand in bpy.app.handlers.save_pre]:
# bpy.app.handlers.save_pre.remove(remap_relative)
if __name__ == "__main__":
register()