forked from bartvdbraak/blender
192 lines
5.1 KiB
Python
192 lines
5.1 KiB
Python
# Draws an off-screen buffer and display it in the corner of the view.
|
|
import bpy
|
|
from bgl import *
|
|
|
|
|
|
class OffScreenDraw(bpy.types.Operator):
|
|
bl_idname = "view3d.offscreen_draw"
|
|
bl_label = "View3D Offscreen Draw"
|
|
|
|
_handle_calc = None
|
|
_handle_draw = None
|
|
is_enabled = False
|
|
|
|
# manage draw handler
|
|
@staticmethod
|
|
def draw_callback_px(self, context):
|
|
scene = context.scene
|
|
aspect_ratio = scene.render.resolution_x / scene.render.resolution_y
|
|
|
|
self._update_offscreen(context, self._offscreen)
|
|
self._opengl_draw(context, self._texture, aspect_ratio, 0.2)
|
|
|
|
@staticmethod
|
|
def handle_add(self, context):
|
|
OffScreenDraw._handle_draw = bpy.types.SpaceView3D.draw_handler_add(
|
|
self.draw_callback_px, (self, context),
|
|
'WINDOW', 'POST_PIXEL',
|
|
)
|
|
|
|
@staticmethod
|
|
def handle_remove():
|
|
if OffScreenDraw._handle_draw is not None:
|
|
bpy.types.SpaceView3D.draw_handler_remove(OffScreenDraw._handle_draw, 'WINDOW')
|
|
|
|
OffScreenDraw._handle_draw = None
|
|
|
|
# off-screen buffer
|
|
@staticmethod
|
|
def _setup_offscreen(context):
|
|
import gpu
|
|
scene = context.scene
|
|
aspect_ratio = scene.render.resolution_x / scene.render.resolution_y
|
|
|
|
try:
|
|
offscreen = gpu.offscreen.new(512, int(512 / aspect_ratio))
|
|
except Exception as e:
|
|
print(e)
|
|
offscreen = None
|
|
|
|
return offscreen
|
|
|
|
@staticmethod
|
|
def _update_offscreen(context, offscreen):
|
|
scene = context.scene
|
|
render = scene.render
|
|
camera = scene.camera
|
|
|
|
modelview_matrix = camera.matrix_world.inverted()
|
|
projection_matrix = camera.calc_matrix_camera(
|
|
render.resolution_x,
|
|
render.resolution_y,
|
|
render.pixel_aspect_x,
|
|
render.pixel_aspect_y,
|
|
)
|
|
|
|
offscreen.draw_view3d(
|
|
scene,
|
|
context.space_data,
|
|
context.region,
|
|
projection_matrix,
|
|
modelview_matrix,
|
|
)
|
|
|
|
@staticmethod
|
|
def _opengl_draw(context, texture, aspect_ratio, scale):
|
|
"""
|
|
OpenGL code to draw a rectangle in the viewport
|
|
"""
|
|
|
|
glDisable(GL_DEPTH_TEST)
|
|
|
|
# view setup
|
|
glMatrixMode(GL_PROJECTION)
|
|
glPushMatrix()
|
|
glLoadIdentity()
|
|
|
|
glMatrixMode(GL_MODELVIEW)
|
|
glPushMatrix()
|
|
glLoadIdentity()
|
|
|
|
glOrtho(-1, 1, -1, 1, -15, 15)
|
|
gluLookAt(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
|
|
|
|
act_tex = Buffer(GL_INT, 1)
|
|
glGetIntegerv(GL_TEXTURE_2D, act_tex)
|
|
|
|
viewport = Buffer(GL_INT, 4)
|
|
glGetIntegerv(GL_VIEWPORT, viewport)
|
|
|
|
width = int(scale * viewport[2])
|
|
height = int(width / aspect_ratio)
|
|
|
|
glViewport(viewport[0], viewport[1], width, height)
|
|
glScissor(viewport[0], viewport[1], width, height)
|
|
|
|
# draw routine
|
|
glEnable(GL_TEXTURE_2D)
|
|
glActiveTexture(GL_TEXTURE0)
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture)
|
|
|
|
texco = [(1, 1), (0, 1), (0, 0), (1, 0)]
|
|
verco = [(1.0, 1.0), (-1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)]
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
|
|
|
|
glColor4f(1.0, 1.0, 1.0, 1.0)
|
|
|
|
glBegin(GL_QUADS)
|
|
for i in range(4):
|
|
glTexCoord3f(texco[i][0], texco[i][1], 0.0)
|
|
glVertex2f(verco[i][0], verco[i][1])
|
|
glEnd()
|
|
|
|
# restoring settings
|
|
glBindTexture(GL_TEXTURE_2D, act_tex[0])
|
|
|
|
glDisable(GL_TEXTURE_2D)
|
|
|
|
# reset view
|
|
glMatrixMode(GL_PROJECTION)
|
|
glPopMatrix()
|
|
|
|
glMatrixMode(GL_MODELVIEW)
|
|
glPopMatrix()
|
|
|
|
glViewport(viewport[0], viewport[1], viewport[2], viewport[3])
|
|
glScissor(viewport[0], viewport[1], viewport[2], viewport[3])
|
|
|
|
# operator functions
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.area.type == 'VIEW_3D'
|
|
|
|
def modal(self, context, event):
|
|
if context.area:
|
|
context.area.tag_redraw()
|
|
|
|
return {'PASS_THROUGH'}
|
|
|
|
def invoke(self, context, event):
|
|
if OffScreenDraw.is_enabled:
|
|
self.cancel(context)
|
|
|
|
return {'FINISHED'}
|
|
|
|
else:
|
|
self._offscreen = OffScreenDraw._setup_offscreen(context)
|
|
if self._offscreen:
|
|
self._texture = self._offscreen.color_texture
|
|
else:
|
|
self.report({'ERROR'}, "Error initializing offscreen buffer. More details in the console")
|
|
return {'CANCELLED'}
|
|
|
|
OffScreenDraw.handle_add(self, context)
|
|
OffScreenDraw.is_enabled = True
|
|
|
|
if context.area:
|
|
context.area.tag_redraw()
|
|
|
|
context.window_manager.modal_handler_add(self)
|
|
return {'RUNNING_MODAL'}
|
|
|
|
def cancel(self, context):
|
|
OffScreenDraw.handle_remove()
|
|
OffScreenDraw.is_enabled = False
|
|
|
|
if context.area:
|
|
context.area.tag_redraw()
|
|
|
|
|
|
def register():
|
|
bpy.utils.register_class(OffScreenDraw)
|
|
|
|
|
|
def unregister():
|
|
bpy.utils.unregister_class(OffScreenDraw)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
register()
|