[go: up one dir, main page]

File: RenderPass.py

package info (click to toggle)
uranium 3.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 5,876 kB
  • sloc: python: 22,349; sh: 111; makefile: 11
file content (136 lines) | stat: -rw-r--r-- 5,251 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# Copyright (c) 2017 Ultimaker B.V.
# Uranium is released under the terms of the LGPLv3 or higher.

from UM.Application import Application

from UM.Logger import Logger

from UM.View.GL.OpenGL import OpenGL


##  Base class for a rendering pass.
#
#   The RenderPass class encapsulates a render pass, that is a single
#   step in the rendering process.
#
#   \note While the render pass could technically support render to
#   texture without using Framebuffer Objects, the PyQt bindings object
#   lacks support for any function like glReadPixels. Therefore, the
#   Qt OpenGL initialization code checks for FBO support and aborts the
#   program if no support is found.
class RenderPass:
    ##  The maximum priority of a render pass. Priority should always be
    #   less than this.
    MaximumPriority = 999

    def __init__(self, name: str, width: int, height: int, priority:int = 0):
        self._name = name
        self._width = width
        self._height = height
        self._priority = priority

        self._gl = OpenGL.getInstance().getBindingsObject()

        self._fbo = None

    ##  Get the name of this RenderPass.
    #
    #   \return \type{string} The name of the render pass.
    def getName(self):
        return self._name

    def getSize(self):
        return self._width, self._height

    ##  Get the priority of this RenderPass.
    #
    #   The priority is used for ordering the render passes. Lower priority render passes
    #   are rendered earlier and are available for later render passes to use as texture
    #   sources.
    #
    #   \return \type{int} The priority of this render pass.
    def getPriority(self):
        return self._priority

    ##  Set the size of this render pass.
    #
    #   \param width \type{int} The new width of the render pass.
    #   \param height \type{int} The new height of the render pass.
    #
    #   \note This will recreate the storage object used by the render
    #   pass. Due to that, the contents will be invalid after resizing
    #   until the render pass is rendered again.
    def setSize(self, width: int, height: int):
        if self._width != width or self._height != height:
            self._width = width
            self._height = height
            self._fbo = None  # Ensure the fbo is re-created next render pass.

    ##  Bind the render pass so it can be rendered to.
    #
    #   This will make sure everything is set up so the contents of
    #   this render pass will be updated correctly. It should be called
    #   as part of your render() implementation.
    #
    #   \note It is very important to call release() after a call to
    #   bind(), once done with rendering.
    def bind(self):
        if self._fbo is None:
            # Ensure that the fbo is created. This is done on (first) bind, as this needs to be done on the main thread.
            self._updateRenderStorage()

        if self._fbo:
            self._fbo.bind()

            # Ensure we can actually write to the relevant FBO components.
            self._gl.glColorMask(self._gl.GL_TRUE, self._gl.GL_TRUE,self._gl.GL_TRUE, self._gl.GL_TRUE)
            self._gl.glDepthMask(self._gl.GL_TRUE)

            self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT)

    ##  Release the render pass.
    #
    #   This makes sure the contents of this render pass are properly
    #   updated at the end of rendering.
    def release(self):
        self._fbo.release()

        # Workaround for a driver bug with recent Intel chips on OSX.
        # Releasing the current FBO does not properly clear the depth buffer, so we have to do that manually.
        #if Platform.isOSX() and OpenGL.getInstance().getGPUVendor() == OpenGL.Vendor.Intel:
            #self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT)

    ##  Render the contents of this render pass.
    #
    #   This method should be reimplemented by subclasses to perform the
    #   actual rendering of the render pass.
    def render(self):
        raise NotImplementedError("Should be implemented by subclasses")

    ##  Get the texture ID of this render pass so it can be reused by other passes.
    #
    #   \return \type{int} The OpenGL texture ID used by this pass.
    def getTextureId(self):
        return self._fbo.getTextureId()

    ##  Get the pixel data produced by this render pass.
    #
    #   This returns an object that contains the pixel data for this render pass.
    #
    #   \note The current object type returned is currently dependant on the specific
    #   implementation of the UM.View.GL.FrameBufferObject class.
    def getOutput(self):
        return self._fbo.getContents()

    ## private:

    def _updateRenderStorage(self):
        # On Mac OS X, this function may get called by a main window resize signal during closing.
        # This will cause a crash, so don't do anything when it is shutting down.
        if Application.getInstance().isShuttingDown():
            return
        if self._width <= 0 or self._height <= 0:
            Logger.log("w", "Tried to create render pass with size <= 0")
            return

        self._fbo = OpenGL.getInstance().createFrameBufferObject(self._width, self._height)