Multi-Objects: UV_OT_follow_active_quads
[blender.git] / doc / python_api / examples / gpu.offscreen.1.py
1 # Draws an off-screen buffer and display it in the corner of the view.
2 import bpy
3 from bgl import *
4
5
6 class OffScreenDraw(bpy.types.Operator):
7     bl_idname = "view3d.offscreen_draw"
8     bl_label = "View3D Offscreen Draw"
9
10     _handle_calc = None
11     _handle_draw = None
12     is_enabled = False
13
14     # manage draw handler
15     @staticmethod
16     def draw_callback_px(self, context):
17         scene = context.scene
18         aspect_ratio = scene.render.resolution_x / scene.render.resolution_y
19
20         self._update_offscreen(context, self._offscreen)
21         self._opengl_draw(context, self._texture, aspect_ratio, 0.2)
22
23     @staticmethod
24     def handle_add(self, context):
25         OffScreenDraw._handle_draw = bpy.types.SpaceView3D.draw_handler_add(
26             self.draw_callback_px, (self, context),
27             'WINDOW', 'POST_PIXEL',
28         )
29
30     @staticmethod
31     def handle_remove():
32         if OffScreenDraw._handle_draw is not None:
33             bpy.types.SpaceView3D.draw_handler_remove(OffScreenDraw._handle_draw, 'WINDOW')
34
35         OffScreenDraw._handle_draw = None
36
37     # off-screen buffer
38     @staticmethod
39     def _setup_offscreen(context):
40         import gpu
41         scene = context.scene
42         aspect_ratio = scene.render.resolution_x / scene.render.resolution_y
43
44         try:
45             offscreen = gpu.offscreen.new(512, int(512 / aspect_ratio))
46         except Exception as e:
47             print(e)
48             offscreen = None
49
50         return offscreen
51
52     @staticmethod
53     def _update_offscreen(context, offscreen):
54         scene = context.scene
55         render_layer = context.render_layer
56         render = scene.render
57         camera = scene.camera
58
59         modelview_matrix = camera.matrix_world.inverted()
60         projection_matrix = camera.calc_matrix_camera(
61             render.resolution_x,
62             render.resolution_y,
63             render.pixel_aspect_x,
64             render.pixel_aspect_y,
65         )
66
67         offscreen.draw_view3d(
68             scene,
69             render_layer,
70             context.space_data,
71             context.region,
72             projection_matrix,
73             modelview_matrix,
74         )
75
76     @staticmethod
77     def _opengl_draw(context, texture, aspect_ratio, scale):
78         """
79         OpenGL code to draw a rectangle in the viewport
80         """
81
82         glDisable(GL_DEPTH_TEST)
83
84         # view setup
85         glMatrixMode(GL_PROJECTION)
86         glPushMatrix()
87         glLoadIdentity()
88
89         glMatrixMode(GL_MODELVIEW)
90         glPushMatrix()
91         glLoadIdentity()
92
93         glOrtho(-1, 1, -1, 1, -15, 15)
94         gluLookAt(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
95
96         act_tex = Buffer(GL_INT, 1)
97         glGetIntegerv(GL_TEXTURE_2D, act_tex)
98
99         viewport = Buffer(GL_INT, 4)
100         glGetIntegerv(GL_VIEWPORT, viewport)
101
102         width = int(scale * viewport[2])
103         height = int(width / aspect_ratio)
104
105         glViewport(viewport[0], viewport[1], width, height)
106         glScissor(viewport[0], viewport[1], width, height)
107
108         # draw routine
109         glEnable(GL_TEXTURE_2D)
110         glActiveTexture(GL_TEXTURE0)
111
112         glBindTexture(GL_TEXTURE_2D, texture)
113
114         texco = [(1, 1), (0, 1), (0, 0), (1, 0)]
115         verco = [(1.0, 1.0), (-1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)]
116
117         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
118
119         glColor4f(1.0, 1.0, 1.0, 1.0)
120
121         glBegin(GL_QUADS)
122         for i in range(4):
123             glTexCoord3f(texco[i][0], texco[i][1], 0.0)
124             glVertex2f(verco[i][0], verco[i][1])
125         glEnd()
126
127         # restoring settings
128         glBindTexture(GL_TEXTURE_2D, act_tex[0])
129
130         glDisable(GL_TEXTURE_2D)
131
132         # reset view
133         glMatrixMode(GL_PROJECTION)
134         glPopMatrix()
135
136         glMatrixMode(GL_MODELVIEW)
137         glPopMatrix()
138
139         glViewport(viewport[0], viewport[1], viewport[2], viewport[3])
140         glScissor(viewport[0], viewport[1], viewport[2], viewport[3])
141
142     # operator functions
143     @classmethod
144     def poll(cls, context):
145         return context.area.type == 'VIEW_3D'
146
147     def modal(self, context, event):
148         if context.area:
149             context.area.tag_redraw()
150
151         return {'PASS_THROUGH'}
152
153     def invoke(self, context, event):
154         if OffScreenDraw.is_enabled:
155             self.cancel(context)
156
157             return {'FINISHED'}
158
159         else:
160             self._offscreen = OffScreenDraw._setup_offscreen(context)
161             if self._offscreen:
162                 self._texture = self._offscreen.color_texture
163             else:
164                 self.report({'ERROR'}, "Error initializing offscreen buffer. More details in the console")
165                 return {'CANCELLED'}
166
167             OffScreenDraw.handle_add(self, context)
168             OffScreenDraw.is_enabled = True
169
170             if context.area:
171                 context.area.tag_redraw()
172
173             context.window_manager.modal_handler_add(self)
174             return {'RUNNING_MODAL'}
175
176     def cancel(self, context):
177         OffScreenDraw.handle_remove()
178         OffScreenDraw.is_enabled = False
179
180         if context.area:
181             context.area.tag_redraw()
182
183
184 def register():
185     bpy.utils.register_class(OffScreenDraw)
186
187
188 def unregister():
189     bpy.utils.unregister_class(OffScreenDraw)
190
191
192 if __name__ == "__main__":
193     register()