[Bf-blender-cvs] [0173116] master: New function to draw offscreen, and related API changes

Dalai Felinto noreply at git.blender.org
Tue Oct 20 05:15:34 CEST 2015


Commit: 0173116117858ae60fb33bf37707278f1721f980
Author: Dalai Felinto
Date:   Tue Oct 20 01:03:00 2015 -0200
Branches: master
https://developer.blender.org/rB0173116117858ae60fb33bf37707278f1721f980

New function to draw offscreen, and related API changes

This expose the capability of handling offscreen drawing. The initial
support lays the barebones for addons to work with framebuffer objects
and implement 3d viewport offscreen drawing. This can be used by script
writers to make fisheye lens preview, head mounted display support, ...

The complete documentation is here: http://www.blender.org/api/blender_python_api_2_76_1/gpu.offscreen.html

Review and many changes by Campbell Barton (thank you :)

https://developer.blender.org/D1533

===================================================================

A	doc/python_api/examples/gpu.offscreen.1.py
M	doc/python_api/sphinx_doc_gen.py
M	source/blender/gpu/GPU_extensions.h
M	source/blender/gpu/intern/gpu_extensions.c
M	source/blender/python/intern/CMakeLists.txt
M	source/blender/python/intern/gpu.c
M	source/blender/python/intern/gpu.h
A	source/blender/python/intern/gpu_offscreen.c

===================================================================

diff --git a/doc/python_api/examples/gpu.offscreen.1.py b/doc/python_api/examples/gpu.offscreen.1.py
new file mode 100644
index 0000000..06f0d91
--- /dev/null
+++ b/doc/python_api/examples/gpu.offscreen.1.py
@@ -0,0 +1,192 @@
+# 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()
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index f68d6bf..1788b4c 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -261,6 +261,7 @@ else:
         "bpy.utils.previews",
         "bpy_extras",
         "gpu",
+        "gpu.offscreen",
         "mathutils",
         "mathutils.geometry",
         "mathutils.bvhtree",
@@ -1659,7 +1660,9 @@ def write_rst_contents(basepath):
         # mathutils
         "mathutils", "mathutils.geometry", "mathutils.bvhtree", "mathutils.kdtree", "mathutils.noise",
         # misc
-        "freestyle", "bgl", "blf", "gpu", "aud", "bpy_extras",
+        "freestyle", "bgl", "blf",
+        "gpu", "gpu.offscreen",
+        "aud", "bpy_extras",
         # bmesh, submodules are in own page
         "bmesh",
         )
@@ -1799,6 +1802,7 @@ def write_rst_importable_modules(basepath):
         # C_modules
         "aud"                  : "Audio System",
         "blf"                  : "Font Drawing",
+        "gpu.offscreen"        : "GPU Off-Screen Buffer",
         "bmesh"                : "BMesh Module",
         "bmesh.types"          : "BMesh Types",
         "bmesh.utils"          : "BMesh Utilities",
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 2dadd38..685ae59 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -188,6 +188,7 @@ void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
 void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
 int GPU_offscreen_width(const GPUOffScreen *ofs);
 int GPU_offscreen_height(const GPUOffScreen *ofs);
+int GPU_offscreen_color_texture(const GPUOffScreen *ofs);
 
 /* Builtin/Non-generated shaders */
 typedef enum GPUProgramType {
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index ce82a67..02e57e4 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -1613,6 +1613,11 @@ int GPU_offscreen_height(const GPUOffScreen *ofs)
 	return ofs->color->h_orig;
 }
 
+int GPU_offscreen_color_texture(const GPUOffScreen *ofs)
+{
+	return ofs->color->bindcode;
+}
+
 /* GPUShader */
 
 struct GPUShader {
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index cd2a9fd..f04bca7 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -46,6 +46,7 @@ set(INC_SYS
 
 set(SRC
 	gpu.c
+	gpu_offscreen.c
 	bpy.c
 	bpy_app.c
 	bpy_app_build_options.c
diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c
index 65b2e97..aada3f6 100644
--- a/source/blender/python/intern/gpu.c
+++ b/source/blender/python/intern/gpu.c
@@ -55,7 +55,7 @@
 #define PY_MODULE_ADD_CONSTANT(module, name) PyModule_AddIntConstant(module, # name, name)
 
 PyDoc_STRVAR(M_gpu_doc,
-"This module provides access to the GLSL shader."
+"This module provides access to the GLSL shader and Offscreen rendering functionalities."
 );
 static struct PyModuleDef gpumodule = {
 	PyModuleDef_HEAD_INIT,
@@ -309,12 +309,25 @@ static PyMethodDef meth_export_shader[] = {
 	{"export_shader", (PyCFunction)GPU_export_shader, METH_VARARGS | METH_KEYWORDS, GPU_export_shader_doc}
 };
 
+/* -------------------------------------------------------------------- */
+/* Initialize Module */
+
 PyObject *GPU_initPython(void)
 {
-	PyObject *module = PyInit_gpu();
+	PyObject *module;
+	PyObject *submodule;
+	PyObject *sys_modules = PyThreadState_GET()->interp->modules;
+
+	module = PyInit_gpu();
+
 	PyModule_AddObject(module, "export_shader", (PyObject *)PyCFunction_New(meth_export_shader, NULL));
-	PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module);
 
+	/* gpu.offscreen */
+	PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen()));
+	PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+	Py_INCREF(submodule);
+
+	PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module);
 	return module;
 }
 
diff --git a/source/blender/python/intern/gpu.h b/source/blender/python/intern/gpu.h
index 8233886..0da44a4 100644
--- a/source/blender/python/intern/gpu.h
+++ b/source/blender/python/intern/gpu.h
@@ -36,4 +36,6 @@
 
 PyObject *GPU_initPython(void);
 
+PyObject *BPyInit_gpu_offscreen(void);
+
 #endif /* __GPU_H__ */
diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c
new file mod

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list