diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/doxygen/Doxyfile | 6 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.1.py | 20 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.10.py | 76 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.11.py | 65 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.2.py | 38 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.3.py | 44 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.4.py | 39 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.5.py | 37 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.6.py | 31 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.7.py | 77 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.8.py | 92 | ||||
-rw-r--r-- | doc/python_api/examples/gpu.9.py | 61 | ||||
-rw-r--r-- | doc/python_api/requirements.txt | 4 | ||||
-rw-r--r-- | doc/python_api/rst/info_overview.rst | 8 | ||||
-rw-r--r-- | doc/python_api/sphinx_doc_gen.py | 72 | ||||
-rwxr-xr-x | doc/python_api/sphinx_doc_gen.sh | 8 | ||||
-rwxr-xr-x | doc/python_api/sphinx_doc_update.py | 7 |
17 files changed, 344 insertions, 341 deletions
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index ecd60957f2b..1e430823b10 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = Blender # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "V2.83" +PROJECT_NUMBER = "V2.90" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -51,7 +51,7 @@ PROJECT_BRIEF = # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = ../../release/freedesktop/icons/48x48/apps/blender.png +PROJECT_LOGO = ../../release/freedesktop/icons/scalable/apps/blender.svg # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is @@ -1720,7 +1720,7 @@ COMPACT_LATEX = NO # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -PAPER_TYPE = a4wide +PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # that should be included in the LaTeX output. The package can be specified just diff --git a/doc/python_api/examples/gpu.1.py b/doc/python_api/examples/gpu.1.py index 831349e5430..a014e69c2d2 100644 --- a/doc/python_api/examples/gpu.1.py +++ b/doc/python_api/examples/gpu.1.py @@ -119,4 +119,24 @@ Examples To try these examples, just copy them into Blenders text editor and execute them. To keep the examples relatively small, they just register a draw function that can't easily be removed anymore. Blender has to be restarted in order to delete the draw handlers. + +3D Lines with Single Color +-------------------------- """ + +import bpy +import gpu +from gpu_extras.batch import batch_for_shader + +coords = [(1, 1, 1), (-2, 0, 0), (-2, -1, 3), (0, 1, 1)] +shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') +batch = batch_for_shader(shader, 'LINES', {"pos": coords}) + + +def draw(): + shader.bind() + shader.uniform_float("color", (1, 1, 0, 1)) + batch.draw(shader) + + +bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW') diff --git a/doc/python_api/examples/gpu.10.py b/doc/python_api/examples/gpu.10.py index a4db576ecc0..2f255b7127d 100644 --- a/doc/python_api/examples/gpu.10.py +++ b/doc/python_api/examples/gpu.10.py @@ -1,41 +1,65 @@ """ -Rendering the 3D View into a Texture ------------------------------------- +Custom Shader for dotted 3D Line +-------------------------------- -The scene has to have a camera for this example to work. -You could also make this independent of a specific camera, -but Blender does not expose good functions to create view and projection matrices yet. +In this example the arc length (distance to the first point on the line) is calculated in every vertex. +Between the vertex and fragment shader that value is automatically interpolated +for all points that will be visible on the screen. +In the fragment shader the ``sin`` of the arc length is calculated. +Based on the result a decision is made on whether the fragment should be drawn or not. """ import bpy -import bgl import gpu -from gpu_extras.presets import draw_texture_2d +from random import random +from mathutils import Vector +from gpu_extras.batch import batch_for_shader -WIDTH = 512 -HEIGHT = 256 +vertex_shader = ''' + uniform mat4 u_ViewProjectionMatrix; -offscreen = gpu.types.GPUOffScreen(WIDTH, HEIGHT) + in vec3 position; + in float arcLength; + out float v_ArcLength; -def draw(): - context = bpy.context - scene = context.scene + void main() + { + v_ArcLength = arcLength; + gl_Position = u_ViewProjectionMatrix * vec4(position, 1.0f); + } +''' + +fragment_shader = ''' + uniform float u_Scale; + + in float v_ArcLength; - view_matrix = scene.camera.matrix_world.inverted() + void main() + { + if (step(sin(v_ArcLength * u_Scale), 0.5) == 1) discard; + gl_FragColor = vec4(1.0); + } +''' - projection_matrix = scene.camera.calc_matrix_camera( - context.evaluated_depsgraph_get(), x=WIDTH, y=HEIGHT) +coords = [Vector((random(), random(), random())) * 5 for _ in range(5)] - offscreen.draw_view3d( - scene, - context.view_layer, - context.space_data, - context.region, - view_matrix, - projection_matrix) +arc_lengths = [0] +for a, b in zip(coords[:-1], coords[1:]): + arc_lengths.append(arc_lengths[-1] + (a - b).length) - bgl.glDisable(bgl.GL_DEPTH_TEST) - draw_texture_2d(offscreen.color_texture, (10, 10), WIDTH, HEIGHT) +shader = gpu.types.GPUShader(vertex_shader, fragment_shader) +batch = batch_for_shader( + shader, 'LINE_STRIP', + {"position": coords, "arcLength": arc_lengths}, +) + + +def draw(): + shader.bind() + matrix = bpy.context.region_data.perspective_matrix + shader.uniform_float("u_ViewProjectionMatrix", matrix) + shader.uniform_float("u_Scale", 10) + batch.draw(shader) -bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL') +bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW') diff --git a/doc/python_api/examples/gpu.11.py b/doc/python_api/examples/gpu.11.py deleted file mode 100644 index 2f255b7127d..00000000000 --- a/doc/python_api/examples/gpu.11.py +++ /dev/null @@ -1,65 +0,0 @@ -""" -Custom Shader for dotted 3D Line --------------------------------- - -In this example the arc length (distance to the first point on the line) is calculated in every vertex. -Between the vertex and fragment shader that value is automatically interpolated -for all points that will be visible on the screen. -In the fragment shader the ``sin`` of the arc length is calculated. -Based on the result a decision is made on whether the fragment should be drawn or not. -""" -import bpy -import gpu -from random import random -from mathutils import Vector -from gpu_extras.batch import batch_for_shader - -vertex_shader = ''' - uniform mat4 u_ViewProjectionMatrix; - - in vec3 position; - in float arcLength; - - out float v_ArcLength; - - void main() - { - v_ArcLength = arcLength; - gl_Position = u_ViewProjectionMatrix * vec4(position, 1.0f); - } -''' - -fragment_shader = ''' - uniform float u_Scale; - - in float v_ArcLength; - - void main() - { - if (step(sin(v_ArcLength * u_Scale), 0.5) == 1) discard; - gl_FragColor = vec4(1.0); - } -''' - -coords = [Vector((random(), random(), random())) * 5 for _ in range(5)] - -arc_lengths = [0] -for a, b in zip(coords[:-1], coords[1:]): - arc_lengths.append(arc_lengths[-1] + (a - b).length) - -shader = gpu.types.GPUShader(vertex_shader, fragment_shader) -batch = batch_for_shader( - shader, 'LINE_STRIP', - {"position": coords, "arcLength": arc_lengths}, -) - - -def draw(): - shader.bind() - matrix = bpy.context.region_data.perspective_matrix - shader.uniform_float("u_ViewProjectionMatrix", matrix) - shader.uniform_float("u_Scale", 10) - batch.draw(shader) - - -bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW') diff --git a/doc/python_api/examples/gpu.2.py b/doc/python_api/examples/gpu.2.py index d1e8ac32589..4bee9acebe3 100644 --- a/doc/python_api/examples/gpu.2.py +++ b/doc/python_api/examples/gpu.2.py @@ -1,19 +1,45 @@ """ -3D Lines with Single Color --------------------------- +Triangle with Custom Shader +--------------------------- """ import bpy import gpu from gpu_extras.batch import batch_for_shader -coords = [(1, 1, 1), (-2, 0, 0), (-2, -1, 3), (0, 1, 1)] -shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') -batch = batch_for_shader(shader, 'LINES', {"pos": coords}) +vertex_shader = ''' + uniform mat4 viewProjectionMatrix; + + in vec3 position; + out vec3 pos; + + void main() + { + pos = position; + gl_Position = viewProjectionMatrix * vec4(position, 1.0f); + } +''' + +fragment_shader = ''' + uniform float brightness; + + in vec3 pos; + + void main() + { + gl_FragColor = vec4(pos * brightness, 1.0); + } +''' + +coords = [(1, 1, 1), (2, 0, 0), (-2, -1, 3)] +shader = gpu.types.GPUShader(vertex_shader, fragment_shader) +batch = batch_for_shader(shader, 'TRIS', {"position": coords}) def draw(): shader.bind() - shader.uniform_float("color", (1, 1, 0, 1)) + matrix = bpy.context.region_data.perspective_matrix + shader.uniform_float("viewProjectionMatrix", matrix) + shader.uniform_float("brightness", 0.5) batch.draw(shader) diff --git a/doc/python_api/examples/gpu.3.py b/doc/python_api/examples/gpu.3.py index 4bee9acebe3..0c86b52bcf5 100644 --- a/doc/python_api/examples/gpu.3.py +++ b/doc/python_api/examples/gpu.3.py @@ -1,45 +1,29 @@ """ -Triangle with Custom Shader ---------------------------- +Wireframe Cube using Index Buffer +--------------------------------- """ import bpy import gpu from gpu_extras.batch import batch_for_shader -vertex_shader = ''' - uniform mat4 viewProjectionMatrix; +coords = ( + (-1, -1, -1), (+1, -1, -1), + (-1, +1, -1), (+1, +1, -1), + (-1, -1, +1), (+1, -1, +1), + (-1, +1, +1), (+1, +1, +1)) - in vec3 position; - out vec3 pos; +indices = ( + (0, 1), (0, 2), (1, 3), (2, 3), + (4, 5), (4, 6), (5, 7), (6, 7), + (0, 4), (1, 5), (2, 6), (3, 7)) - void main() - { - pos = position; - gl_Position = viewProjectionMatrix * vec4(position, 1.0f); - } -''' - -fragment_shader = ''' - uniform float brightness; - - in vec3 pos; - - void main() - { - gl_FragColor = vec4(pos * brightness, 1.0); - } -''' - -coords = [(1, 1, 1), (2, 0, 0), (-2, -1, 3)] -shader = gpu.types.GPUShader(vertex_shader, fragment_shader) -batch = batch_for_shader(shader, 'TRIS', {"position": coords}) +shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') +batch = batch_for_shader(shader, 'LINES', {"pos": coords}, indices=indices) def draw(): shader.bind() - matrix = bpy.context.region_data.perspective_matrix - shader.uniform_float("viewProjectionMatrix", matrix) - shader.uniform_float("brightness", 0.5) + shader.uniform_float("color", (1, 0, 0, 1)) batch.draw(shader) diff --git a/doc/python_api/examples/gpu.4.py b/doc/python_api/examples/gpu.4.py index 0c86b52bcf5..e05290a9442 100644 --- a/doc/python_api/examples/gpu.4.py +++ b/doc/python_api/examples/gpu.4.py @@ -1,30 +1,39 @@ """ -Wireframe Cube using Index Buffer ---------------------------------- +Mesh with Random Vertex Colors +------------------------------ """ import bpy import gpu +import bgl +import numpy as np +from random import random from gpu_extras.batch import batch_for_shader -coords = ( - (-1, -1, -1), (+1, -1, -1), - (-1, +1, -1), (+1, +1, -1), - (-1, -1, +1), (+1, -1, +1), - (-1, +1, +1), (+1, +1, +1)) +mesh = bpy.context.active_object.data +mesh.calc_loop_triangles() -indices = ( - (0, 1), (0, 2), (1, 3), (2, 3), - (4, 5), (4, 6), (5, 7), (6, 7), - (0, 4), (1, 5), (2, 6), (3, 7)) +vertices = np.empty((len(mesh.vertices), 3), 'f') +indices = np.empty((len(mesh.loop_triangles), 3), 'i') -shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') -batch = batch_for_shader(shader, 'LINES', {"pos": coords}, indices=indices) +mesh.vertices.foreach_get( + "co", np.reshape(vertices, len(mesh.vertices) * 3)) +mesh.loop_triangles.foreach_get( + "vertices", np.reshape(indices, len(mesh.loop_triangles) * 3)) + +vertex_colors = [(random(), random(), random(), 1) for _ in range(len(mesh.vertices))] + +shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR') +batch = batch_for_shader( + shader, 'TRIS', + {"pos": vertices, "color": vertex_colors}, + indices=indices, +) def draw(): - shader.bind() - shader.uniform_float("color", (1, 0, 0, 1)) + bgl.glEnable(bgl.GL_DEPTH_TEST) batch.draw(shader) + bgl.glDisable(bgl.GL_DEPTH_TEST) bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW') diff --git a/doc/python_api/examples/gpu.5.py b/doc/python_api/examples/gpu.5.py index e05290a9442..2edde46a364 100644 --- a/doc/python_api/examples/gpu.5.py +++ b/doc/python_api/examples/gpu.5.py @@ -1,39 +1,26 @@ """ -Mesh with Random Vertex Colors ------------------------------- +2D Rectangle +------------ """ import bpy import gpu -import bgl -import numpy as np -from random import random from gpu_extras.batch import batch_for_shader -mesh = bpy.context.active_object.data -mesh.calc_loop_triangles() +vertices = ( + (100, 100), (300, 100), + (100, 200), (300, 200)) -vertices = np.empty((len(mesh.vertices), 3), 'f') -indices = np.empty((len(mesh.loop_triangles), 3), 'i') +indices = ( + (0, 1, 2), (2, 1, 3)) -mesh.vertices.foreach_get( - "co", np.reshape(vertices, len(mesh.vertices) * 3)) -mesh.loop_triangles.foreach_get( - "vertices", np.reshape(indices, len(mesh.loop_triangles) * 3)) - -vertex_colors = [(random(), random(), random(), 1) for _ in range(len(mesh.vertices))] - -shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR') -batch = batch_for_shader( - shader, 'TRIS', - {"pos": vertices, "color": vertex_colors}, - indices=indices, -) +shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR') +batch = batch_for_shader(shader, 'TRIS', {"pos": vertices}, indices=indices) def draw(): - bgl.glEnable(bgl.GL_DEPTH_TEST) + shader.bind() + shader.uniform_float("color", (0, 0.5, 0.5, 1.0)) batch.draw(shader) - bgl.glDisable(bgl.GL_DEPTH_TEST) -bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW') +bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL') diff --git a/doc/python_api/examples/gpu.6.py b/doc/python_api/examples/gpu.6.py index 2edde46a364..69af65e163e 100644 --- a/doc/python_api/examples/gpu.6.py +++ b/doc/python_api/examples/gpu.6.py @@ -1,25 +1,36 @@ """ -2D Rectangle ------------- +2D Image +-------- + +To use this example you have to provide an image that should be displayed. """ import bpy import gpu +import bgl from gpu_extras.batch import batch_for_shader -vertices = ( - (100, 100), (300, 100), - (100, 200), (300, 200)) +IMAGE_NAME = "Untitled" +image = bpy.data.images[IMAGE_NAME] -indices = ( - (0, 1, 2), (2, 1, 3)) +shader = gpu.shader.from_builtin('2D_IMAGE') +batch = batch_for_shader( + shader, 'TRI_FAN', + { + "pos": ((100, 100), (200, 100), (200, 200), (100, 200)), + "texCoord": ((0, 0), (1, 0), (1, 1), (0, 1)), + }, +) -shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR') -batch = batch_for_shader(shader, 'TRIS', {"pos": vertices}, indices=indices) +if image.gl_load(): + raise Exception() def draw(): + bgl.glActiveTexture(bgl.GL_TEXTURE0) + bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode) + shader.bind() - shader.uniform_float("color", (0, 0.5, 0.5, 1.0)) + shader.uniform_int("image", 0) batch.draw(shader) diff --git a/doc/python_api/examples/gpu.7.py b/doc/python_api/examples/gpu.7.py index 69af65e163e..56cbb93c61a 100644 --- a/doc/python_api/examples/gpu.7.py +++ b/doc/python_api/examples/gpu.7.py @@ -1,37 +1,86 @@ """ -2D Image --------- +Generate a texture using Offscreen Rendering +-------------------------------------------- -To use this example you have to provide an image that should be displayed. +#. Create an :class:`gpu.types.GPUOffScreen` object. +#. Draw some circles into it. +#. Make a new shader for drawing a planar texture in 3D. +#. Draw the generated texture using the new shader. """ import bpy import gpu import bgl +from mathutils import Matrix from gpu_extras.batch import batch_for_shader +from gpu_extras.presets import draw_circle_2d -IMAGE_NAME = "Untitled" -image = bpy.data.images[IMAGE_NAME] +# Create and fill offscreen +########################################## -shader = gpu.shader.from_builtin('2D_IMAGE') +offscreen = gpu.types.GPUOffScreen(512, 512) + +with offscreen.bind(): + bgl.glClear(bgl.GL_COLOR_BUFFER_BIT) + with gpu.matrix.push_pop(): + # reset matrices -> use normalized device coordinates [-1, 1] + gpu.matrix.load_matrix(Matrix.Identity(4)) + gpu.matrix.load_projection_matrix(Matrix.Identity(4)) + + amount = 10 + for i in range(-amount, amount + 1): + x_pos = i / amount + draw_circle_2d((x_pos, 0.0), (1, 1, 1, 1), 0.5, 200) + + +# Drawing the generated texture in 3D space +############################################# + +vertex_shader = ''' + uniform mat4 modelMatrix; + uniform mat4 viewProjectionMatrix; + + in vec2 position; + in vec2 uv; + + out vec2 uvInterp; + + void main() + { + uvInterp = uv; + gl_Position = viewProjectionMatrix * modelMatrix * vec4(position, 0.0, 1.0); + } +''' + +fragment_shader = ''' + uniform sampler2D image; + + in vec2 uvInterp; + + void main() + { + gl_FragColor = texture(image, uvInterp); + } +''' + +shader = gpu.types.GPUShader(vertex_shader, fragment_shader) batch = batch_for_shader( shader, 'TRI_FAN', { - "pos": ((100, 100), (200, 100), (200, 200), (100, 200)), - "texCoord": ((0, 0), (1, 0), (1, 1), (0, 1)), + "position": ((-1, -1), (1, -1), (1, 1), (-1, 1)), + "uv": ((0, 0), (1, 0), (1, 1), (0, 1)), }, ) -if image.gl_load(): - raise Exception() - def draw(): bgl.glActiveTexture(bgl.GL_TEXTURE0) - bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode) + bgl.glBindTexture(bgl.GL_TEXTURE_2D, offscreen.color_texture) shader.bind() - shader.uniform_int("image", 0) + shader.uniform_float("modelMatrix", Matrix.Translation((1, 2, 3)) @ Matrix.Scale(3, 4)) + shader.uniform_float("viewProjectionMatrix", bpy.context.region_data.perspective_matrix) + shader.uniform_float("image", 0) batch.draw(shader) -bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL') +bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW') diff --git a/doc/python_api/examples/gpu.8.py b/doc/python_api/examples/gpu.8.py index 56cbb93c61a..470bd8a2dad 100644 --- a/doc/python_api/examples/gpu.8.py +++ b/doc/python_api/examples/gpu.8.py @@ -1,23 +1,28 @@ """ -Generate a texture using Offscreen Rendering --------------------------------------------- +Copy Offscreen Rendering result back to RAM +------------------------------------------- -#. Create an :class:`gpu.types.GPUOffScreen` object. -#. Draw some circles into it. -#. Make a new shader for drawing a planar texture in 3D. -#. Draw the generated texture using the new shader. +This will create a new image with the given name. +If it already exists, it will override the existing one. + +Currently almost all of the execution time is spent in the last line. +In the future this will hopefully be solved by implementing the Python buffer protocol +for :class:`bgl.Buffer` and :class:`bpy.types.Image.pixels` (aka ``bpy_prop_array``). """ import bpy import gpu import bgl +import random from mathutils import Matrix -from gpu_extras.batch import batch_for_shader from gpu_extras.presets import draw_circle_2d -# Create and fill offscreen -########################################## +IMAGE_NAME = "Generated Image" +WIDTH = 512 +HEIGHT = 512 +RING_AMOUNT = 10 + -offscreen = gpu.types.GPUOffScreen(512, 512) +offscreen = gpu.types.GPUOffScreen(WIDTH, HEIGHT) with offscreen.bind(): bgl.glClear(bgl.GL_COLOR_BUFFER_BIT) @@ -26,61 +31,20 @@ with offscreen.bind(): gpu.matrix.load_matrix(Matrix.Identity(4)) gpu.matrix.load_projection_matrix(Matrix.Identity(4)) - amount = 10 - for i in range(-amount, amount + 1): - x_pos = i / amount - draw_circle_2d((x_pos, 0.0), (1, 1, 1, 1), 0.5, 200) - - -# Drawing the generated texture in 3D space -############################################# - -vertex_shader = ''' - uniform mat4 modelMatrix; - uniform mat4 viewProjectionMatrix; - - in vec2 position; - in vec2 uv; - - out vec2 uvInterp; - - void main() - { - uvInterp = uv; - gl_Position = viewProjectionMatrix * modelMatrix * vec4(position, 0.0, 1.0); - } -''' - -fragment_shader = ''' - uniform sampler2D image; - - in vec2 uvInterp; - - void main() - { - gl_FragColor = texture(image, uvInterp); - } -''' - -shader = gpu.types.GPUShader(vertex_shader, fragment_shader) -batch = batch_for_shader( - shader, 'TRI_FAN', - { - "position": ((-1, -1), (1, -1), (1, 1), (-1, 1)), - "uv": ((0, 0), (1, 0), (1, 1), (0, 1)), - }, -) - + for i in range(RING_AMOUNT): + draw_circle_2d( + (random.uniform(-1, 1), random.uniform(-1, 1)), + (1, 1, 1, 1), random.uniform(0.1, 1), 20) -def draw(): - bgl.glActiveTexture(bgl.GL_TEXTURE0) - bgl.glBindTexture(bgl.GL_TEXTURE_2D, offscreen.color_texture) + buffer = bgl.Buffer(bgl.GL_BYTE, WIDTH * HEIGHT * 4) + bgl.glReadBuffer(bgl.GL_BACK) + bgl.glReadPixels(0, 0, WIDTH, HEIGHT, bgl.GL_RGBA, bgl.GL_UNSIGNED_BYTE, buffer) - shader.bind() - shader.uniform_float("modelMatrix", Matrix.Translation((1, 2, 3)) @ Matrix.Scale(3, 4)) - shader.uniform_float("viewProjectionMatrix", bpy.context.region_data.perspective_matrix) - shader.uniform_float("image", 0) - batch.draw(shader) +offscreen.free() -bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW') +if not IMAGE_NAME in bpy.data.images: + bpy.data.images.new(IMAGE_NAME, WIDTH, HEIGHT) +image = bpy.data.images[IMAGE_NAME] +image.scale(WIDTH, HEIGHT) +image.pixels = [v / 255 for v in buffer] diff --git a/doc/python_api/examples/gpu.9.py b/doc/python_api/examples/gpu.9.py index 470bd8a2dad..a4db576ecc0 100644 --- a/doc/python_api/examples/gpu.9.py +++ b/doc/python_api/examples/gpu.9.py @@ -1,50 +1,41 @@ """ -Copy Offscreen Rendering result back to RAM -------------------------------------------- +Rendering the 3D View into a Texture +------------------------------------ -This will create a new image with the given name. -If it already exists, it will override the existing one. - -Currently almost all of the execution time is spent in the last line. -In the future this will hopefully be solved by implementing the Python buffer protocol -for :class:`bgl.Buffer` and :class:`bpy.types.Image.pixels` (aka ``bpy_prop_array``). +The scene has to have a camera for this example to work. +You could also make this independent of a specific camera, +but Blender does not expose good functions to create view and projection matrices yet. """ import bpy -import gpu import bgl -import random -from mathutils import Matrix -from gpu_extras.presets import draw_circle_2d +import gpu +from gpu_extras.presets import draw_texture_2d -IMAGE_NAME = "Generated Image" WIDTH = 512 -HEIGHT = 512 -RING_AMOUNT = 10 - +HEIGHT = 256 offscreen = gpu.types.GPUOffScreen(WIDTH, HEIGHT) -with offscreen.bind(): - bgl.glClear(bgl.GL_COLOR_BUFFER_BIT) - with gpu.matrix.push_pop(): - # reset matrices -> use normalized device coordinates [-1, 1] - gpu.matrix.load_matrix(Matrix.Identity(4)) - gpu.matrix.load_projection_matrix(Matrix.Identity(4)) - for i in range(RING_AMOUNT): - draw_circle_2d( - (random.uniform(-1, 1), random.uniform(-1, 1)), - (1, 1, 1, 1), random.uniform(0.1, 1), 20) +def draw(): + context = bpy.context + scene = context.scene + + view_matrix = scene.camera.matrix_world.inverted() + + projection_matrix = scene.camera.calc_matrix_camera( + context.evaluated_depsgraph_get(), x=WIDTH, y=HEIGHT) - buffer = bgl.Buffer(bgl.GL_BYTE, WIDTH * HEIGHT * 4) - bgl.glReadBuffer(bgl.GL_BACK) - bgl.glReadPixels(0, 0, WIDTH, HEIGHT, bgl.GL_RGBA, bgl.GL_UNSIGNED_BYTE, buffer) + offscreen.draw_view3d( + scene, + context.view_layer, + context.space_data, + context.region, + view_matrix, + projection_matrix) -offscreen.free() + bgl.glDisable(bgl.GL_DEPTH_TEST) + draw_texture_2d(offscreen.color_texture, (10, 10), WIDTH, HEIGHT) -if not IMAGE_NAME in bpy.data.images: - bpy.data.images.new(IMAGE_NAME, WIDTH, HEIGHT) -image = bpy.data.images[IMAGE_NAME] -image.scale(WIDTH, HEIGHT) -image.pixels = [v / 255 for v in buffer] +bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL') diff --git a/doc/python_api/requirements.txt b/doc/python_api/requirements.txt index c2b5b2fd794..263b12eb604 100644 --- a/doc/python_api/requirements.txt +++ b/doc/python_api/requirements.txt @@ -1,2 +1,2 @@ -Sphinx==1.8.5 -sphinx_rtd_theme==0.4.3 +Sphinx==3.0.3 +sphinx_rtd_theme==0.5.0rc1 diff --git a/doc/python_api/rst/info_overview.rst b/doc/python_api/rst/info_overview.rst index e341453fe93..562076c6c43 100644 --- a/doc/python_api/rst/info_overview.rst +++ b/doc/python_api/rst/info_overview.rst @@ -253,7 +253,13 @@ Registering a class with Blender results in the class definition being loaded in where it becomes available alongside existing functionality. Once this class is loaded you can access it from :mod:`bpy.types`, -using the bl_idname rather than the classes original name. +using the ``bl_idname`` rather than the classes original name. + +.. note:: + + There are some exceptions to this for class names which aren't guarantee to be unique. + In this case use: :func:`bpy.types.Struct.bl_rna_get_subclass`. + When loading a class, Blender performs sanity checks making sure all required properties and functions are found, that properties have the correct type, and that functions have the right number of arguments. diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 68a7a0df075..d4cc1d37262 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -403,32 +403,21 @@ MODULE_GROUPING = { # -------------------------------BLENDER---------------------------------------- -blender_version_strings = [str(v) for v in bpy.app.version] -is_release = bpy.app.version_cycle in {"rc", "release"} - # converting bytes to strings, due to T30154 BLENDER_REVISION = str(bpy.app.build_hash, 'utf_8') -if is_release: - # '2.62a' - BLENDER_VERSION_DOTS = ".".join(blender_version_strings[:2]) + bpy.app.version_char -else: - # '2.62.1' - BLENDER_VERSION_DOTS = ".".join(blender_version_strings) +# '2.83.0 Beta' or '2.83.0' or '2.83.1' +BLENDER_VERSION_DOTS = bpy.app.version_string if BLENDER_REVISION != "Unknown": - # '2.62a SHA1' (release) or '2.62.1 SHA1' (non-release) + # SHA1 Git hash BLENDER_VERSION_HASH = BLENDER_REVISION else: # Fallback: Should not be used BLENDER_VERSION_HASH = "Hash Unknown" -if is_release: - # '2_62a_release' - BLENDER_VERSION_PATH = "%s%s_release" % ("_".join(blender_version_strings[:2]), bpy.app.version_char) -else: - # '2_62_1' - BLENDER_VERSION_PATH = "_".join(blender_version_strings) +# '2_83' +BLENDER_VERSION_PATH = "%d_%d" % (bpy.app.version[0], bpy.app.version[1]) # --------------------------DOWNLOADABLE FILES---------------------------------- @@ -492,6 +481,11 @@ if _BPY_PROP_COLLECTION_FAKE: else: _BPY_PROP_COLLECTION_ID = "collection" +if _BPY_STRUCT_FAKE: + bpy_struct = bpy.types.bpy_struct +else: + bpy_struct = None + def escape_rst(text): """ Escape plain text which may contain characters used by RST. @@ -512,7 +506,7 @@ def is_struct_seq(value): def undocumented_message(module_name, type_name, identifier): - return "Undocumented `contribute <https://developer.blender.org/T51061>`" + return "Undocumented, consider `contributing <https://developer.blender.org/T51061>`__." def range_str(val): @@ -694,11 +688,13 @@ def py_descr2sphinx(ident, fw, descr, module_name, type_name, identifier): doc = undocumented_message(module_name, type_name, identifier) if type(descr) == GetSetDescriptorType: - fw(ident + ".. attribute:: %s\n\n" % identifier) + fw(ident + ".. attribute:: %s\n" % identifier) + fw(ident + " :noindex:\n\n") write_indented_lines(ident + " ", fw, doc, False) fw("\n") elif type(descr) == MemberDescriptorType: # same as above but use 'data' - fw(ident + ".. data:: %s\n\n" % identifier) + fw(ident + ".. data:: %s\n" % identifier) + fw(ident + " :noindex:\n\n") write_indented_lines(ident + " ", fw, doc, False) fw("\n") elif type(descr) in {MethodDescriptorType, ClassMethodDescriptorType}: @@ -738,11 +734,14 @@ def pyprop2sphinx(ident, fw, identifier, py_prop): ''' # readonly properties use "data" directive, variables use "attribute" directive if py_prop.fset is None: - fw(ident + ".. data:: %s\n\n" % identifier) + fw(ident + ".. data:: %s\n" % identifier) + fw(ident + " :noindex:\n\n") else: - fw(ident + ".. attribute:: %s\n\n" % identifier) + fw(ident + ".. attribute:: %s\n" % identifier) + fw(ident + " :noindex:\n\n") write_indented_lines(ident + " ", fw, py_prop.__doc__) if py_prop.fset is None: + fw("\n") fw(ident + " (readonly)\n\n") else: fw("\n") @@ -908,7 +907,8 @@ def pymodule2sphinx(basepath, module_name, module, title): elif issubclass(value_type, (bool, int, float, str, tuple)): # constant, not much fun we can do here except to list it. # TODO, figure out some way to document these! - fw(".. data:: %s\n\n" % attribute) + fw(".. data:: %s\n" % attribute) + fw(" :noindex:\n\n") write_indented_lines(" ", fw, "constant value %s" % repr(value), False) fw("\n") else: @@ -1052,6 +1052,7 @@ context_type_map = { "selected_editable_fcurves": ("FCurve", True), "selected_editable_objects": ("Object", True), "selected_editable_sequences": ("Sequence", True), + "selected_nla_strips": ("NlaStrip", True), "selected_nodes": ("Node", True), "selected_objects": ("Object", True), "selected_pose_bones": ("PoseBone", True), @@ -1115,7 +1116,8 @@ def pycontext2sphinx(basepath): type_descr = prop.get_type_description( class_fmt=":class:`bpy.types.%s`", collection_id=_BPY_PROP_COLLECTION_ID) - fw(".. data:: %s\n\n" % prop.identifier) + fw(".. data:: %s\n" % prop.identifier) + fw(" :noindex:\n\n") if prop.description: fw(" %s\n\n" % prop.description) @@ -1160,7 +1162,8 @@ def pycontext2sphinx(basepath): i = 0 while char_array[i] is not None: member = ctypes.string_at(char_array[i]).decode(encoding="ascii") - fw(".. data:: %s\n\n" % member) + fw(".. data:: %s\n" % member) + fw(" :noindex:\n\n") member_type, is_seq = context_type_map[member] fw(" :type: %s :class:`bpy.types.%s`\n\n" % ("sequence of " if is_seq else "", member_type)) unique.add(member) @@ -1304,7 +1307,7 @@ def pyrna2sphinx(basepath): fw(title_string(title, "=")) - fw(".. module:: %s\n\n" % struct_module_name) + fw(".. module:: %s.%s\n\n" % (struct_module_name, struct_id)) # docs first?, ok write_example_ref("", fw, "%s.%s" % (struct_module_name, struct_id)) @@ -1363,9 +1366,11 @@ def pyrna2sphinx(basepath): type_descr = prop.get_type_description(class_fmt=":class:`%s`", collection_id=_BPY_PROP_COLLECTION_ID) # readonly properties use "data" directive, variables properties use "attribute" directive if 'readonly' in type_descr: - fw(" .. data:: %s\n\n" % prop.identifier) + fw(" .. data:: %s\n" % prop.identifier) + fw(" :noindex:\n\n") else: - fw(" .. attribute:: %s\n\n" % prop.identifier) + fw(" .. attribute:: %s\n" % prop.identifier) + fw(" :noindex:\n\n") if prop.description: fw(" %s\n\n" % prop.description) @@ -1442,7 +1447,7 @@ def pyrna2sphinx(basepath): if _BPY_STRUCT_FAKE: descr_items = [ - (key, descr) for key, descr in sorted(bpy.types.Struct.__bases__[0].__dict__.items()) + (key, descr) for key, descr in sorted(bpy_struct.__dict__.items()) if not key.startswith("__") ] @@ -1458,9 +1463,6 @@ def pyrna2sphinx(basepath): for identifier, py_prop in base.get_py_properties(): lines.append(" * :class:`%s.%s`\n" % (base.identifier, identifier)) - for identifier, py_prop in base.get_py_properties(): - lines.append(" * :class:`%s.%s`\n" % (base.identifier, identifier)) - if lines: fw(".. rubric:: Inherited Properties\n\n") @@ -1484,6 +1486,8 @@ def pyrna2sphinx(basepath): lines.append(" * :class:`%s.%s`\n" % (base.identifier, func.identifier)) for identifier, py_func in base.get_py_functions(): lines.append(" * :class:`%s.%s`\n" % (base.identifier, identifier)) + for identifier, py_func in base.get_py_c_functions(): + lines.append(" * :class:`%s.%s`\n" % (base.identifier, identifier)) if lines: fw(".. rubric:: Inherited Functions\n\n") @@ -1536,7 +1540,7 @@ def pyrna2sphinx(basepath): fw(title_string(class_name, "=")) - fw(".. module:: %s\n" % class_module_name) + fw(".. module:: %s.%s\n" % (class_module_name, class_name)) fw("\n") if use_subclasses: @@ -1571,7 +1575,7 @@ def pyrna2sphinx(basepath): # write fake classes if _BPY_STRUCT_FAKE: - class_value = bpy.types.Struct.__bases__[0] + class_value = bpy_struct fake_bpy_type( "bpy.types", class_value, _BPY_STRUCT_FAKE, "built-in base class for all classes in bpy.types.", use_subclasses=True, @@ -1711,7 +1715,7 @@ class PatchedPythonDomain(PythonDomain): fw("def setup(app):\n") fw(" app.add_stylesheet('css/theme_overrides.css')\n") - fw(" app.override_domain(PatchedPythonDomain)\n\n") + fw(" app.add_domain(PatchedPythonDomain, override=True)\n\n") file.close() diff --git a/doc/python_api/sphinx_doc_gen.sh b/doc/python_api/sphinx_doc_gen.sh index 45cd6a229e5..1c5b9ec0b61 100755 --- a/doc/python_api/sphinx_doc_gen.sh +++ b/doc/python_api/sphinx_doc_gen.sh @@ -36,16 +36,10 @@ fi blender_srcdir=$(dirname -- $0)/../.. blender_version_header="$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" blender_version=$(grep "BLENDER_VERSION\s" "$blender_version_header" | awk '{print $3}') -blender_version_char=$(grep "BLENDER_VERSION_CHAR\s" "$blender_version_header" | awk '{print $3}') blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_version_header" | awk '{print $3}') -blender_subversion=$(grep "BLENDER_SUBVERSION\s" "$blender_version_header" | awk '{print $3}') unset blender_version_header -if [ "$blender_version_cycle" = "release" ] ; then - BLENDER_VERSION=$(expr $blender_version / 100)_$(expr $blender_version % 100)$blender_version_char"_release" -else - BLENDER_VERSION=$(expr $blender_version / 100)_$(expr $blender_version % 100)_$blender_subversion -fi +BLENDER_VERSION=$(expr $blender_version / 100)_$(expr $blender_version % 100) SSH_UPLOAD_FULL=$SSH_UPLOAD/"blender_python_api_"$BLENDER_VERSION diff --git a/doc/python_api/sphinx_doc_update.py b/doc/python_api/sphinx_doc_update.py index d3f42b1d26f..4495fca9274 100755 --- a/doc/python_api/sphinx_doc_update.py +++ b/doc/python_api/sphinx_doc_update.py @@ -127,11 +127,10 @@ def main(): " f.write('%d\\n' % is_release)\n" " f.write('%d\\n' % is_beta)\n" " f.write('%s\\n' % branch)\n" - " f.write('%d.%d%s\\n' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char))\n" - " f.write('%d.%d%s\\n' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char)\n" + " f.write('%d.%d\\n' % (bpy.app.version[0], bpy.app.version[1]))\n" + " f.write('%d.%d\\n' % (bpy.app.version[0], bpy.app.version[1])\n" " if (is_release or is_beta) else '%s\\n' % branch)\n" - " f.write('%d_%d%s_release' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char)\n" - " if is_release else '%d_%d_%d' % bpy.app.version)\n" + " f.write('%d_%d' % (bpy.app.version[0], bpy.app.version[1]))\n" ) get_ver_cmd = (args.blender, "--background", "-noaudio", "--factory-startup", "--python-exit-code", "1", "--python-expr", getver_script, "--", getver_file) |