Example #1
0
class LayerWidget(Widget):
    _T_RENDER_LAYER = 1

    resolution = attributes.VectorAttribute(2)
    size = attributes.VectorAttribute(2)
    position = attributes.VectorAttribute(4)

    def __init__(self, position, size, resolution):
        super().__init__()
        self.resolution = resolution
        self.size = size
        self.position = position

        self._items = []
        self._default_configuration = {
            'color_channels': 4,
            'resolution': self.resolution,
            'type': 'static',
            'rendered': False,
        }
        self._layers = []
        self._tasks = []

    def is_ready(self):
        pass

    def forward(self):
        pass

    def render(self):
        pass

    def append(self, configuration):
        self._item.append(self._layer(configuration))
        self._task((self._T_RENDER_LAYER, len()))

    def insert(self, i, configuration):
        self._items.insert(i, self._layer(configuration))
        self._task((self._T_RENDER_LAYER, i))

    def _layer(self, configuration):
        config = copy(self._default_configuration)
        config.update(configuration)
        si = _LayerWidgetLayer(config)
        return si

    def _task(self, task):
        if task in self._tasks:
            self._tasks.remove(task)
        self._tasks.append(task)
Example #2
0
class FragmentGraph(DomainGraph):

    DEFAULT_FRAGMENT_KERNEL = """
        vec4 fragment_kernel(vec2 txcoord) {
            return tovec4($D.domain(txcoord));
        }
    """

    FRAGMENT_KERNELS = {
        'expr':
        lambda e: "vec4 fragment_kernel(vec2 txcoord) { \n\treturn " + e +
        "; \n}",
    }
    cs = attributes.VectorAttribute(4)

    # main domain name
    fragment_kernel = attributes.CastedAttribute(str)

    def __init__(self, domain=None, cs=None, fragment_kernel=None):

        super().__init__(domain)

        self.cs = cs

        if 'domain' in self.domains:
            self.fragment_kernel = fragment_kernel or self.DEFAULT_FRAGMENT_KERNEL
        elif fragment_kernel is None:
            raise ValueError(
                'argument fragment_kernel cannot be None without default domain'
            )
        else:
            self.fragment_kernel = fragment_kernel

        self.mesh = None
        self.program = None
        self._fkernel_template = None

    def init(self):
        self._build_kernel()
        self.program = self._build_shader()
        self.mesh = StridedVertexMesh(
            mesh3d_rectangle(),
            GL_TRIANGLES,
            attribute_locations=self.program.attributes)
        self.on_tick.once(self.sync_gpu)

    @cs.on_change
    def _properties_changed(self, *e):
        self.on_tick.once(self.sync_gpu)

    def _build_kernel(self):
        context = self.get_domain_glsl_substitutions()
        kernel = Template(self.fragment_kernel, context)
        kernel.context.update({'size': 'gl_PointSize', 'color': 'v_col'})
        self._fkernel_template = kernel

    def _build_shader(self):
        prg = DomainProgram(vrt_file='fragmentgraph.vrt.glsl',
                            frg_file='fragmentgraph.frg.glsl')

        prg.declare_uniform('camera',
                            components.camera.Camera2D.DTYPE,
                            variable='camera')
        prg.declare_uniform('plot',
                            plotter2d.Plotter2d.UBO_DTYPE,
                            variable='plot')

        prg.prepare_domains(self.domains)
        prg.get_shader(GL_FRAGMENT_SHADER).substitutions.update({
            'fragment_kernel':
            self._fkernel_template.render(),
        })
        prg.link()
        prg.uniform_block_binding(
            'plot', G_.CONTEXT.buffer_base('gpupy.plot.plotter2d'))
        prg.uniform_block_binding('camera',
                                  G_.CONTEXT.buffer_base('gpupy.gl.camera'))

        self._src = prg.get_shader(GL_FRAGMENT_SHADER)._precompiled_source
        return prg

    def sync_gpu(self):
        cs = self.cs.values
        self.program.uniform('cs', cs)
        self.program.uniform('cs_size',
                             (np.abs(cs[1] - cs[0]), np.abs(cs[3] - cs[2])))

    def render(self):
        # enable all domains
        domain.enable_domains(self.program, self.domains.items())

        # blending
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        # draw mesh
        self.program.use()
        self.mesh.draw()
        self.program.unuse()

    @fragment_kernel.transformation
    def set_color_kernel(self, ckrn):
        kernels = self.__class__.FRAGMENT_KERNELS
        ckrn_args, ckrn_kwargs = (), {}

        # we have ('kernel_name', ***)
        # i   ('kernel_name', {kwargs})          --> kernel(**kwargs)
        # ii  ('kernel_name', [args])            --> kernel(*args)
        # iii ('kernel_name', (args))            --> kernel(*args)
        # iv  ('kernel_name', (args), {kwargs})  --> kernel(*args, **kwargs)
        # v   ('kernel_name', x, y, z, ...)      --> kernel(x, y, z, ...)
        if isinstance(ckrn, tuple) \
        or isinstance(ckrn, list):
            if len(ckrn) == 2:  # i - iii
                if isinstance(ckrn[1], dict):
                    ckrn_kwargs = ckrn[1]
                elif isinstance(ckrn[1], tuple) \
                  or isinstance(ckrn[1], list):
                    ckrn_args = ckrn[1]
                else:
                    ckrn_args = (ckrn[1], )
            elif len(ckrn) == 3 \
             and isinstance(ckrn[2], dict) \
             and (isinstance(ckrn[1], tuple)
               or isinstance(ckrn[1], list)):
                ckrn_args, ckrn_kwargs = ckrn[1:3]  # iv
            elif len(ckrn) > 1:
                ckrn_args = ckrn[1:]  # v
            ckrn = ckrn[0]

        # if ckrn is registred, use it.
        if ckrn in kernels:
            ckrn = kernels[ckrn]

        # is it callable?
        if hasattr(ckrn, '__call__'):
            ckrn = ckrn(*ckrn_args, **ckrn_kwargs)
        elif len(ckrn_args) or len(ckrn_kwargs):
            msg = 'kernel {} is not callable, but kernel args (), kwargs () are defined.'
            raise RuntimeError(msg.format(ckrn, ckrn_args, ckrn_kwargs))
        return ckrn
Example #3
0
class Container(Widget):
    """
    like a div container, the Container widget has a position, size, margin, border and padding. 

     position
       \        size x
        +---------------------------- ... +
        |     margin
      s | 
      i |     +---------   
      z |     |    border
      e |     |   +----------
        |     |   |    padding
      y |     |   |   +-----------
        |     |   |   |    content box
        |
        ...  
        +---------------------------- ... +

    ```python
        container = Container((100, 100), margin=(10, 10), padding=(10, 10), border=(10, 10, 10, 10), border_color=(1, 0, 0, 1))
        container.widget = SomeWidget(size=container.content_size, position=container_position)
        container.tick()
        container.render()
    ```
    """
    size = attributes.VectorAttribute(2)

    position = attributes.VectorAttribute(4)
    padding = attributes.VectorAttribute(4)
    margin = attributes.VectorAttribute(4)
    border = attributes.VectorAttribute(4)
    border_color = attributes.VectorAttribute(4)

    # transformed properties
    content_position = attributes.ComputedAttribute(
        position,
        border,
        margin,
        padding,
        transformation=content_position,
        descriptor=attributes.VectorAttribute(4))

    content_size = attributes.ComputedAttribute(
        size,
        border,
        margin,
        padding,
        transformation=content_size,
        descriptor=attributes.VectorAttribute(2))

    border_size = attributes.ComputedAttribute(
        size,
        border,
        margin,
        transformation=border_size,
        descriptor=attributes.VectorAttribute(2))

    def __init__(self,
                 widget=None,
                 size=(0, 0),
                 position=(0, 0, 0, 0),
                 margin=(0, 0, 0, 0),
                 padding=(0, 0, 0, 0),
                 border=(1, 1, 1, 1),
                 border_color=(0, 0, 0, 1)):

        super().__init__()

        self.size = size
        self.position = position
        self.padding = padding
        self.border = border
        self.border_color = border_color
        self.margin = margin

        self._widget = None
        self.set_widget(widget)

        self.to_gpu = True
        self._init_borders()

    def set_widget(self, widget):
        self._widget = widget

    @border_color.on_change
    @content_size.on_change
    @border_size.on_change
    def _flag_create_mesh(self, *a):
        self.on_tick.once(self.sync_gpu)

    def sync_gpu(self):
        self._create_mesh()

    def _init_borders(self):
        self.border_program = BorderProgram()
        self.border_mesh = StridedVertexMesh(
            np.empty(0,
                     dtype=np.dtype([('vertex', np.float32, 4),
                                     ('color', np.float32, 4)])),
            GL_TRIANGLES,
            attribute_locations=self.border_program.attributes)

    def _create_mesh(self):
        b, c, s = self.border, self.border_color, self.border_size
        p = self.position + (b[3] + self.margin[3], b[0] + self.margin[0], 0,
                             0)
        crn = (p[1], p[0] + s[0], p[1] + s[1], p[0])  # corner coords
        vcnt = sum(6 * (int(l > 0) + int(l > 0 and b[(i + 1) % 4] > 0))
                   for i, l in enumerate(b))
        v = np.zeros(vcnt, self.border_mesh.buffer.dtype)
        i = 0
        if b[3] and b[0]:  # left upper corner
            v[i:i + 6] = [((crn[3] - b[3], crn[0] - b[0], 0, 1), c),
                          ((crn[3], crn[0] - b[0], 0, 1), c),
                          ((crn[3], crn[0], 0, 1), c),
                          ((crn[3], crn[0], 0, 1), c),
                          ((crn[3] - b[3], crn[0], 0, 1), c),
                          ((crn[3] - b[3], crn[0] - b[0], 0, 1), c)]
            i += 6
        if b[0]:  # top
            v[i:i + 6] = [((crn[3] - b[3], crn[0] - b[0], 0, 1), c),
                          ((crn[1], crn[0] - b[0], 0, 1), c),
                          ((crn[1], crn[0], 0, 1), c),
                          ((crn[1], crn[0], 0, 1), c),
                          ((crn[3] - b[3], crn[0] - b[0], 0, 1), c),
                          ((crn[3] - b[3], crn[0], 0, 1), c)]
            i += 6
        if b[0] and b[1]:  # right upper corner
            v[i:i + 6] = [((crn[1] + b[1], crn[0] - b[0], 0, 1), c),
                          ((crn[1], crn[0] - b[0], 0, 1), c),
                          ((crn[1], crn[0], 0, 1), c),
                          ((crn[1], crn[0], 0, 1), c),
                          ((crn[1] + b[1], crn[0], 0, 1), c),
                          ((crn[1] + b[1], crn[0] - b[0], 0, 1), c)]
            i += 6
        if b[1]:  # right
            v[i:i + 6] = [((crn[1] + b[1], crn[0], 0, 1), c),
                          ((crn[1], crn[0], 0, 1), c),
                          ((crn[1], crn[2], 0, 1), c),
                          ((crn[1], crn[2], 0, 1), c),
                          ((crn[1] + b[1], crn[2], 0, 1), c),
                          ((crn[1] + b[1], crn[0], 0, 1), c)]
            i += 6
        if b[1] and b[2]:  # right lower corner
            v[i:i + 6] = [((crn[1] + b[1], crn[2] + b[2], 0, 1), c),
                          ((crn[1], crn[2] + b[2], 0, 1), c),
                          ((crn[1], crn[2], 0, 1), c),
                          ((crn[1], crn[2], 0, 1), c),
                          ((crn[1] + b[1], crn[2], 0, 1), c),
                          ((crn[1] + b[1], crn[2] + b[2], 0, 1), c)]
            i += 6
        if b[2]:  # bottom
            v[i:i + 6] = [((crn[3] - b[3], crn[2] + b[2], 0, 1), c),
                          ((crn[1], crn[2] + b[2], 0, 1), c),
                          ((crn[1], crn[2], 0, 1), c),
                          ((crn[1], crn[2], 0, 1), c),
                          ((crn[3] - b[3], crn[2] + b[2], 0, 1), c),
                          ((crn[3] - b[3], crn[2], 0, 1), c)]
            i += 6
        if b[2] and b[3]:  # left lower corner
            v[i:i + 6] = [((crn[3] - b[3], crn[2] + b[2], 0, 1), c),
                          ((crn[3], crn[2] + b[2], 0, 1), c),
                          ((crn[3], crn[2], 0, 1), c),
                          ((crn[3], crn[2], 0, 1), c),
                          ((crn[3] - b[3], crn[2], 0, 1), c),
                          ((crn[3] - b[3], crn[2] + b[2], 0, 1), c)]
            i += 6
        if b[3]:  # left
            v[i:i + 6] = [((crn[3] - b[3], crn[0], 0, 1), c),
                          ((crn[3], crn[0], 0, 1), c),
                          ((crn[3], crn[2], 0, 1), c),
                          ((crn[3], crn[2], 0, 1), c),
                          ((crn[3] - b[3], crn[2], 0, 1), c),
                          ((crn[3] - b[3], crn[0], 0, 1), c)]
            i += 6

        self.border_mesh.buffer.set(v)

    def _render(self):
        self.border_program.use()
        self.border_mesh.draw()
        self.border_program.unuse()
Example #4
0
class TextureDomain(_GlslDeclarationDomain):
    """

    Allows to use gpupy.gl.texture's as plot 
    domains. 

    """
    # -- GLSL templates
    _GLSL_TEMPLATE_DOMAIN = """
        {ret_type:} {fname:}({arg_type:} x) {{
            return texture(tx_{upref:}, x).{rgba:};
        }}
    """

    _GLSL_TEMPLATE_DECRL = "uniform sampler{d:}D tx_{upref:};"

    WHEELS = {
        'complex':
        os.path.join(os.path.dirname(__file__), 'graph', 'res',
                     'cwheel_cmplx.jpg'),
        'complex2':
        os.path.join(os.path.dirname(__file__), 'graph', 'res',
                     'cwheel_cmplx2.png'),
        'complex3':
        os.path.join(os.path.dirname(__file__), 'graph', 'res',
                     'cwheel_cmplx3.png'),
        'keksnicoh':
        os.path.join(os.path.dirname(__file__), 'graph', 'res',
                     'keksnicoh.png'),
        'homer':
        os.path.join(os.path.dirname(__file__), 'graph', 'res', 'homer.png'),
    }

    DEFAULT_WHEEL = 'complex'

    # -- attributes
    texture = attributes.GlTexture()
    cs = attributes.VectorAttribute(4, (0, 1, 0, 1))

    @classmethod
    def load_image(cls, path, smooth=True, periodic=False):
        txt = imread(path, mode="RGB")
        d = cls(Texture2D.to_device(txt))
        d.periodic(periodic)
        d.smooth(smooth)
        return d

    @classmethod
    def colorwheel(cls, wheel=DEFAULT_WHEEL):
        if wheel not in cls.WHEELS:
            err = 'unkown wheel "{}". Available wheels: {}'
            raise ValueError(err.format(wheel, ','.join(cls.WHEELS)))
        d = cls.load_image(cls.WHEELS[wheel])
        d.periodic(False)
        d.smooth(True)
        return d

    @classmethod
    def to_device_1d(cls, data, smooth=True, periodic=False):
        d = cls(Texture1D.to_device(data))
        d.periodic(periodic)
        d.smooth(smooth)
        return d

    @classmethod
    def to_device_2d(cls, data, smooth=True, periodic=False):
        if data.dtype == np.float64:
            data = data.astype(np.float32)
        if data.dtype == np.complex128:
            data = data.astype(np.complex64)
        if data.dtype == np.complex64:
            data = np.stack((data.real, data.imag), -1)

        d = cls(Texture2D.to_device(data))
        d.periodic(periodic)
        d.smooth(smooth)
        return d

    @classmethod
    def to_device_3d(cls, data, smooth=True, periodic=False):
        d = cls(Texture3D.to_device(data))
        d.periodic(periodic)
        d.smooth(smooth)
        return d

    # --

    def __init__(self, texture, cs=None):
        self.texture = texture
        if cs is not None:
            self.cs = cs

    def periodic(self, periodic=False):
        if periodic:
            self.texture.tex_parameterf(GL_TEXTURE_WRAP_S, GL_REPEAT)
            self.texture.tex_parameterf(GL_TEXTURE_WRAP_T, GL_REPEAT)
        else:
            self.texture.tex_parameterf(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
            self.texture.tex_parameterf(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)

    def smooth(self, smooth=True):
        if smooth:
            self.texture.interpolate_linear()
        else:
            self.texture.interpolate_nearest()

    # -- domain API

    def enable(self, program, upref, texunit=0):
        self.texture.activate(texunit)
        program.uniform('tx_{}'.format(upref), self.texture)
        return texunit + 1

    def glsl_identifier(self, pref):
        t = self.texture
        ret_type = 'float' if t.channels == 1 else 'vec{}'.format(t.channels)
        return [(None, 'txdmn_{}'.format(pref), 1, ret_type)]

    # -- function domain API

    def glsl_declr(self, upref, **kwargs):
        # XXX
        # - what about other vector types?
        t = self.texture
        _, fname, _, ret_type = self.glsl_identifier(upref)[0]
        #ret_type = 'float' if  t.channels == 1 else 'vec{}'.format( t.channels)
        tmpl = self.__class__._GLSL_TEMPLATE_DOMAIN
        declr = tmpl.format(ret_type=ret_type,
                            arg_type=['float', 'vec2',
                                      'vec3'][t.dimension - 1],
                            fname=fname,
                            rgba='rgba'[0:t.channels],
                            upref=upref)
        header = self.__class__._GLSL_TEMPLATE_DECRL.format(d=t.dimension,
                                                            upref=upref)
        return header + '\n\n' + declr
Example #5
0
class Context():
    """
    context API:

    events:
    -------
    on_ready        when the context is ready to let 
                    the OpenGL.GL functions do their job.

    on_cycle        when the cycle logic should be executed

    on_resize       when the context was resized. It is allowed
                    to perform the tick and rendering logic
                    like on_cycle to provide fluid window resizing.

    """
    size = attributes.VectorAttribute(2)
    resolution = attributes.VectorAttribute(2)
    position = attributes.VectorAttribute(2)
    title = attributes.CastedAttribute(str, 'window')
    visible = attributes.CastedAttribute(bool)

    def __init__(self):
        self.gl_buffer_base_register = {}
        self._next_free_gl_buffer_base_index = 0

        self.on_ready = Event()
        self.on_cycle = Event()
        self.on_resize = Event()
        self.on_close = Event()

        self.active_keys = set()

    def buffer_base(self, name, index=None):
        """ 
        reserves a buffer base with a **name** at **index**.
        if no **index** was given, the next free buffer base
        will be reserved. 

        The reserved buffer index is then returned. 

        Example:

        ```python
            from gpupy.gl import VertexBuffer, GPUPY_GL

            ubo = VertexBuffer.to_device(ndarray, target=UNIFORM_BUFFER)
            ubo.bind_buffer_base(GPUPY_GL.CONTEXT.buffer_base('some_name'))
        ```

        """
        i_max = glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS)
        if not name in self.gl_buffer_base_register:
            if index is not None and index in self.gl_buffer_base_register:
                raise RuntimeError('allready registred.')

            index = index or self._next_free_gl_buffer_base_index
            if index > i_max:
                raise OverflowError()
            self.gl_buffer_base_register[
                name] = index or self._next_free_gl_buffer_base_index

            # find lowest free index
            ui = sorted(self.gl_buffer_base_register.values())
            for i in range(len(ui) - 1):
                if ui[i + 1] - ui[i] != 1:
                    self._next_free_gl_buffer_base_index = ui[i] + 1
                    return
            self._next_free_gl_buffer_base_index = len(ui)

        return self.gl_buffer_base_register[name]

    def __gl_context_enable__(self):
        """ activates OpenGL context """
        GPUPY_GL.CONTEXT = self
Example #6
0
class Cartesian2D(Camera):
    """
    2d cartesian camera 

    Attributes:
        screensize (float[2]): lengths of the space dimensions
        position (float[3]): camera position
        roll (float): rotation of the coordinate space

    Examples:

        XXX

    """
    screensize = attributes.VectorAttribute(2, (1, 1))
    roll = attributes.CastedAttribute(float, 0)
    position = attributes.VectorAttribute(3, (0, 0, 0))

    DTYPE = np.dtype([
        ('mat_view', np.float32, (4, 4)),
        ('mat_projection', np.float32, (4, 4)),
        ('position', np.float32, 3),
        ('roll', np.float32),
        ('direction', np.float32, 3),
        ('_b1', np.float32),
        ('direction_right', np.float32, 3),
        ('_b2', np.float32),
        ('direction_top', np.float32, 3),
    ])

    def __init__(self,
                 screensize,
                 position=(0, 0, 0),
                 roll=0,
                 buffer_base=None):

        super().__init__(
            Cartesian2D.DTYPE, buffer_base
            or GPUPY_GL.CONTEXT.buffer_base('gpupy.gl.camera'))

        self._camera = np.zeros(1, dtype=Cartesian2D.DTYPE)

        self.screensize = screensize
        self.position = position
        self.roll = roll

        self.commit()

    # -- api --

    def __buffer__(self):
        mat_projection = mat4_rot_z(self.roll) @ np.array(
            [
                1,
                0,
                0,
                -self.position.x,
                0,
                1,
                0,
                -self.position.y,
                0,
                0,
                1,
                0,
                0,
                0,
                0,
                1,
            ],
            dtype=np.float32).reshape((4, 4))
        mat_view = np.array([
            2.0 / self.screensize.x,
            0,
            0,
            0,
            0,
            -2.0 / self.screensize.y,
            0,
            0,
            0,
            0,
            1,
            0,
            0,
            0,
            0,
            1,
        ],
                            dtype=np.float32).reshape((4, 4))

        self._camera['mat_view'] = mat_view.T
        self._camera['mat_projection'] = mat_projection.T
        self._camera['roll'] = self.roll
        self._camera['position'] = self.position.xyz

        # XXX is a function of roll
        self._camera['direction'] = (0, 0, -1)
        self._camera['direction_right'] = (1, 0, 0)
        self._camera['direction_top'] = (0, 1, 0)
        return self._camera

    # -- matrix methods

    @roll.on_change
    @position.on_change
    @screensize.on_change
    def _attributes_changed(self, *e):
        self.commit()
Example #7
0
class Perspective3D(Camera):
    """
    3d perspective camera

    Attributes:
        fov (float): field of view angle
        frustum (float[2]): near and far plane 
        screensize (float[2]): coordinate space of near plane
        position (float[3]): camera position
        rotation (float[3]): roll, pitch, yaw

    Examples:

        XXX

    """
    screensize = attributes.VectorAttribute(2, (1, 1))
    rotation = attributes.VectorAttribute(3, (0, 0, 0))
    position = attributes.VectorAttribute(3, (0, 0, 0))
    frustum = attributes.VectorAttribute(2, (0.1, 10000))
    fov = attributes.CastedAttribute(float, 0.5 * 65.0 * np.pi / 180.0)

    DTYPE = np.dtype([
        ('mat_view', np.float32, (4, 4)),
        ('mat_projection', np.float32, (4, 4)),
        ('mat_viewprojection', np.float32, (4, 4)),
        ('position', np.float32, 3),
        ('yaw', np.float32),
        ('direction', np.float32, 3),
        ('pitch', np.float32),
        ('direction_right', np.float32, 3),
        ('roll', np.float32),
        ('direction_top', np.float32, 3),
    ])

    def __init__(self,
                 screensize,
                 position=(0, 0, 0),
                 rotation=(0, 0, 0),
                 buffer_base=None):

        super().__init__(
            Perspective3D.DTYPE, buffer_base
            or GPUPY_GL.CONTEXT.buffer_base('gpupy.gl.camera'))

        self._camera = np.zeros(1, dtype=Perspective3D.DTYPE)
        self._mat_projection = None
        self._mat_view = None

        self.screensize = screensize
        self.position = position
        self.rotation = rotation

        self.direction = (0, 0, 0)
        self.right = (0, 0, 0)
        self.top = (0, 0, 0)

        self.commit()

    # -- api --
    def __buffer__(self):
        # camera position and rotation matrix
        reflection_xy = mat4_reflection_xy()
        position_matrix = mat4_translation(*self.position)
        rot_roll = mat4_rot_z(self.rotation[2])
        rot_yaw = mat4_rot_y(self.rotation[1])
        rot_pitch = mat4_rot_x(self.rotation[0])
        mat_view = (
            rot_roll @ rot_pitch @ rot_yaw @ position_matrix @ reflection_xy)

        # perspective projection
        (n, f), ratio = self.frustum, self.screensize[0] / self.screensize[1]
        h = n * np.tan(self.fov)
        w = h * ratio
        mat_proj = np.array([
            n / w, 0, 0, 0, 0, n / h, 0, 0, 0, 0, -(f + n) /
            (f - n), -2.0 * f * n / (f - n), 0, 0, -1, 0
        ],
                            dtype=np.float32).reshape((4, 4))

        # ubo
        self._camera['mat_view'] = mat_view.T
        self._camera['mat_projection'] = mat_proj.T
        # remember.. (AB)^T = (B^T)(A^T)
        self._camera['mat_viewprojection'] = (mat_proj @ mat_view).T

        self._camera['roll'], \
        self._camera['pitch'], \
        self._camera['yaw'] = self.rotation

        self._camera['position'] = self.position

        self._camera['direction'] = self.direction
        self._camera['direction_right'] = self.right
        self._camera['direction_top'] = self.top

        return self._camera

    # -- camera control events --
    @position.on_change
    @screensize.on_change
    @rotation.on_change
    def _attributes_changed(self, *e):
        self.commit()
Example #8
0
class AbstractGrid(Widget):
    """

    """
    # widget configuration
    size = attributes.VectorAttribute(2)
    resolution = attributes.VectorAttribute(2)
    position = attributes.VectorAttribute(4)
    cs = attributes.VectorAttribute(4)

    # grid configuration
    major_grid = attributes.VectorAttribute(2, (.5, .5))
    major_grid_width = attributes.CastedAttribute(float, 0.5)
    major_grid_color = attributes.VectorAttribute(4, (0, 0, 0, 1))

    minor_grid_width = attributes.CastedAttribute(float, .5)
    minor_grid_color = attributes.VectorAttribute(4, (0, 0, 0, 1))
    minor_grid_n = attributes.VectorAttribute(2, (5, 5))

    antialiasing = attributes.CastedAttribute(float, .5)

    # style
    background_color = attributes.VectorAttribute(4, (1, 1, 1, 1))

    def __init__(self,
                 size,
                 position=(0, 0, 0, 1),
                 cs=(0, 0),
                 major_grid=(1, 1),
                 background_color=(1, 1, 1, 1),
                 major_grid_color=(0, 0, 0, 1),
                 resolution=None,
                 minor_grid_color=(0, 0, 0, 1),
                 minor_grid_n=(5, 5)):

        super().__init__()

        self.position = position
        self.size = size
        self.cs = cs
        self._t = time()

        self.major_grid = major_grid
        self.major_grid_color = major_grid_color
        self.minor_grid_color = minor_grid_color
        self.minor_grid_n = minor_grid_n
        self.background_color = background_color

        self._req_uniforms = True
        self.resolution = resolution or self.size
        self._dev = False

        self._mat_model = np.array([
            self.resolution.x, 0, 0, 0, 0, self.resolution.y, 0, 0, 0, 0, 1, 0,
            self.position.x, self.position.y, 0, 1
        ],
                                   dtype=np.float32).reshape((4, 4)).T

        self._init_plane()

    @size.on_change
    @cs.on_change
    @major_grid.on_change
    @minor_grid_n.on_change
    @minor_grid_width.on_change
    @major_grid_width.on_change
    @resolution.on_change
    @position.on_change
    def req_uniforms(self, *e):
        self._req_uniforms = True

    def upload_uniforms(self):
        # update model matrix
        self._mat_model[0][0] = self.resolution[0]
        self._mat_model[1][1] = self.resolution[1]
        self._mat_model[3] = self.position
        self.program.uniform('mat_model', self._mat_model)

        # -- polar
        #  self.program.uniform('u_limits1',[-5.1,+5.1,-5.1,+5.1])
        #  self.program.uniform('u_limits2',  [-5.0,+5.0, np.pi/6.0, 11.0*np.pi/6.0])
        #  self.program.uniform('u_major_grid_step', [1.00,np.pi/ 6.0])
        #  self.program.uniform('u_minor_grid_step', [0.25,np.pi/60.0])

        # -- cartesian
        # add this extra bit and assure that u_limits1 != u_limit2
        l1 = self.cs.values * 1.000
        mg = self.major_grid.values
        cs = self.cs.values

        Mw = self.minor_grid_width * max(1.0,
                                         self.resolution[0] / self.size[0])
        mw = self.major_grid_width * max(1.0,
                                         self.resolution[0] / self.size[0])
        aa = self.antialiasing

        self.program.uniform('u_limits1', l1)
        self.program.uniform('u_limits2', cs)
        self.program.uniform('u_major_grid_step', mg)
        self.program.uniform('u_minor_grid_step',
                             self.major_grid.values / self.minor_grid_n)
        self.program.uniform('u_major_grid_width', Mw)
        self.program.uniform('u_minor_grid_width', mw)
        self.program.uniform('u_major_grid_color', self.major_grid_color)
        self.program.uniform('u_minor_grid_color', self.minor_grid_color)
        self.program.uniform('u_resolution', self.resolution)
        self.program.uniform('u_antialias', aa)
        self.program.uniform('c_bg', self.background_color)

        self._req_uniforms = False

    #   print('RES', self.resolution, 'size', self.size, 'CS', self.cs)
    #   print('GRID', self.major_grid)
    def _init_plane(self):
        self.program = GridProgram()

        self.program.uniform_block_binding(
            'camera', GPUPY_GL.CONTEXT.buffer_base('gpupy.gl.camera'))
        self.upload_uniforms()

        self.mesh = StridedVertexMesh(
            mesh3d_rectangle(),
            GL_TRIANGLES,
            attribute_locations=self.program.attributes)

    def dev(self):
        self.program = GridProgramDev()
        self.program.uniform_block_binding(
            'camera', GPUPY_GL.CONTEXT.buffer_base('gpupy.gl.camera'))
        self.upload_uniforms()
        self._dev = True
        return self

    def tick(self):
        if True or self._req_uniforms:
            self.upload_uniforms()
        super().tick()

    def _render(self):
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        if self._dev:
            self.program.uniform('dev_color1', (1, 0, 0, 1))
            self.program.uniform('dev_color2', (1, 0, 1, 1))
        self.program.use()
        self.mesh.draw()
        self.program.unuse()

        if self._dev:
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
            self.program.uniform('dev_color1', (0, 1, 0, 1))
            self.program.uniform('dev_color2', (0, 1, 1, 1))
            self.program.use()
            self.mesh.draw()
            self.program.unuse()
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
Example #9
0
class FrameWidget(Widget):
    """
    Frame component uses framebuffer to render a scene on 
    a plane. 

    the state of a Frame is described by the following properties:

    Properties:

    - size: the size of the frame
    - resulution: the size of the texture which captures the scene.
                    e.g. the capture size might be higher than the size
                         of the plane to enable anti aliasing like down
                         sampling.

    - viewport: gpupy.gl.ViewPort
                if not defined the viewport is set to 
                    ViewPort((0, 0), resulution)
    - camera: camera which will be enabled when the Framebuffer 
              starts cawhichpturing
    - camera: camera for rendering the screen


         +----------------------------------------+
         |
         |             capture.x 
         |  c #####################################
         |  a #
      s  |  p #         
      i  |  t #       vp.pos          vp.w
      z  |  u #            x ---------------------
      e  |  r #            |          
      .  |  e #       vp.h | 
      y  |  . #            + ---------------------
         |  y ####################################
         |
         +----------------------------------------+

    """

    size = attributes.VectorAttribute(2)
    position = attributes.VectorAttribute(4)
    resulution = attributes.VectorAttribute(2)
    plane_size = attributes.ComputedAttribute(
        size, descriptor=attributes.VectorAttribute(2))
    clear_color = attributes.VectorAttribute(4)

    def __init__(self,
                 size,
                 resulution=None,
                 position=(0, 0, 0, 1),
                 multisampling=None,
                 post_effects=None,
                 blit=None,
                 clear_color=(0, 0, 0, 1),
                 preload_factor=2):
        """
        creates a framebuffer of *size* and *resulution* 
        at *position*.

        if *resulution* is None, the resulution is linked
        to *size*.
        """
        # XXX
        # - multisampling
        # - post effects
        # - blit/record mode

        super().__init__()
        self._res = None
        self.size = size
        self.position = position
        self.resulution = resulution if resulution is not None else self.size
        self.viewport = Viewport((0, 0), self.resulution)
        self.texture = None
        self.clear_color = clear_color
        self.preload_factor = preload_factor
        self._init_capturing()
        self._init_plane()

        self._require_resize = False

    # -- initialization --

    def _init_capturing(self):
        self._res = self.preload_factor * self.resulution.values
        self.texture = Texture2D.empty((*self._res, 4), np.float32)
        self.texture.interpolation_linear()
        self.framebuffer = Framebuffer()
        self.framebuffer.color_attachment(self.texture)
        self.texture.parameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
        self.texture.parameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)

    @resulution.on_change
    def resulution_changed(self, value):
        print('WFWEFWEFFF§§33')
        self._require_resize = True

    def _init_plane(self):
        self.program = _CameraProgram(_GLSL_VRT, _GLSL_FRG)
        self.texture.activate()

        self.program.uniform('frame_texture', self.texture)
        self.program.uniform_block_binding(
            'camera', GPUPY_GL.CONTEXT.buffer_base('gpupy.gl.camera'))

        self.program.uniform('size', self.plane_size.xy)
        self.program.uniform('mat_model', np.identity(4, dtype=np.float32))
        self.program.uniform('position', self.position.xyzw)
        self.program.uniform('rf', (self.resulution[0] / self._res[0],
                                    self.resulution[1] / self._res[1]))
        self.position.on_change.append(
            partial(self.program.uniform, 'position'))
        self.size.on_change.append(partial(self.program.uniform, 'size'))

        self.mesh = StridedVertexMesh(
            mesh3d_rectangle(),
            GL_TRIANGLES,
            attribute_locations=self.program.attributes)

    @plane_size.transformation
    @resulution.transformation
    def normalize(self, v):
        """ to avoid pixel rounding errors """
        # XXX
        # - is this the best solution?
        v = np.ceil(v)
        return (max(1, v[0]), max(1, v[1]))

    def tick(self):
        if self._require_resize:

            if self._res[0] < self.resulution[0] \
            or self._res[1] < self.resulution[1]:
                self._res = self.resulution.values * self.preload_factor
                self.texture.resize(self._res)
            self.program.uniform('rf', (self.resulution[0] / self._res[0],
                                        self.resulution[1] / self._res[1]))
            self._require_resize = False

    def render(self):
        self.draw()

    def draw(self, shader=None):
        shader = shader or self.program
        self.texture.activate()
        shader.use()
        self.mesh.draw()
        shader.unuse()

    def use(self):
        self.framebuffer.use()
        self.viewport.use((0, 0), np.array(self.resulution, dtype=np.int32))
        glClearColor(*self.clear_color)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    def unuse(self):
        self.viewport.unuse(restore=True)
        self.framebuffer.unuse()
Example #10
0
class Plotter2d(Widget):

    UBO_DTYPE = np.dtype([('mat_cs', np.float32, (4, 4)),
                          ('cs', np.float32, 4), ('cs_size', np.float32, 2)])

    # widget configuration
    size = attributes.VectorAttribute(2)
    position = attributes.VectorAttribute(4, (0, 0, 0, 1))

    # configuration space determines [minx, maxx, miny, maxy]
    cs = attributes.VectorAttribute(4, (0, 1, 0, 1))

    # axes configuration
    # size of one unit (sx, sy) in configuration space
    axes_unit = attributes.VectorAttribute(2, (0.25, 0.25))

    # division of one axes_unit into sub units
    minor_axes_n = attributes.VectorAttribute(2, (5, 5))

    # the plot plane is implemented via framebuffer. this factor
    # allows to adjust the resolution of the framebuffer viewport.
    plot_resolution_factor = attributes.CastedAttribute(float, 1)

    background_color = attributes.VectorAttribute(4, (0, 0, 0, 1))
    plot_background_color = attributes.VectorAttribute(4, (0, 0, 0, 1))
    plot_padding = attributes.VectorAttribute(4, (0, 0, 0, 0))

    # common precomputed properties
    cs_size = attributes.ComputedAttribute(
        cs, descriptor=attributes.VectorAttribute(2), transformation=cs_size)

    def __init__(self,
                 size,
                 position=(0, 0, 0, 1),
                 cs=(0, 1, 0, 1),
                 style=DEFAULT_STYLE,
                 axes_unit=None):

        super().__init__()

        # state
        self.cs = cs
        self.size = size
        self.position = position

        if axes_unit is not None:
            self.axes_unit = axes_unit

        #self.axes_unit = (0.1, 0.1)
        self._style = Style(
            {
                'border': parse_4f1_1c4,
                'background-color': parse_1c4,
                'grid-color': parse_1c4,
                'grid-sub-color': parse_1c4,
                'plot-background-color': parse_1c4,
                'plot-padding': parse_4f1,
                'min-size': parse_2f1,
                'plot-scaling': float,
            }, style)

        self.background_color = self._style['background-color']
        self.plot_background_color = self._style['plot-background-color']
        self.plot_padding = self._style['plot-padding']
        self.ubo = None

        self.on_plot = Event()

        self._plot_margin = vec4((0, 0, 0, 0))
        self.grid = None
        self.layer = None

        self._graphs = []
        self._graphs_initialized = False

        self._init()
        self.a = False
        self.last_fr = False
        self.on_plot.once(self.init_graphs)

        self.cmc = [
            [1, 0, 0, 1],
            [1, 1, 0, 1],
            [1, 0, 1, 1],
            [0, 1, 0, 1],
            [0, 0, 1, 1],
            [1, 1, 1, 1],
        ]

    # -- graph api

    def init_graphs(self):
        for graph in self._graphs:
            graph.init()
        self._graphs_initialized = True

    def append(self, graph):
        self._graphs.append(graph)
        if self._graphs_initialized:
            graph.init()
            graph.resolution = self.plotframe.resulution
            graph.viewport = self.plotframe.resulution

    def __iadd__(self, graph):
        self.append(graph)
        return self

    # -- init

    def _init(self):
        self._initlayer()
        self._initplotcam()
        self._init_grid()
        self._init_ubo()

    # -- plot ubo

    def _init_ubo(self):
        """ initializes plotting ubo """
        self.ubo = BufferObject.to_device(np.zeros(1,
                                                   dtype=Plotter2d.UBO_DTYPE),
                                          target=GL_UNIFORM_BUFFER)
        buffer_base = GPUPY_GL.CONTEXT.buffer_base('gpupy.plot.plotter2d')
        self.ubo.bind_buffer_base(buffer_base)
        self.update_ubo()

    @cs.on_change
    def update_ubo(self, *e):
        self.ubo.host['mat_cs'] = mat_cs(self.cs, self.layer.content_size)
        self.ubo.host['cs'] = self.cs.values
        self.ubo.host['cs_size'] = cs_size(self.cs)
        self.ubo.sync_gpu()

    # -- grid

    def _init_grid(self):
        """ initializes grid component """
        major_grid = observables.transform_observables(
            transformation=grid, observables=(self.axes_unit, self.cs))

        self.grid = CartesianGrid(
            size=self.layer.content_size,
            position=self.layer.content_position,
            cs=self.cs,
            major_grid=major_grid,
            major_grid_color=self._style['grid-color'],
            minor_grid_color=self._style['grid-sub-color'],
            background_color=self.plot_background_color,
            resolution=self.layer.content_size,
            minor_grid_n=self.minor_axes_n)  #.dev()

    # -- camera

    def _initplotcam(self):
        """
        creates a plot camera which is connected to
        the configuration space
        """
        pos = observables.transform_observables(
            lambda s: (s[0] * 0.5, s[1] * 0.5, 1), vecn((0, 0, 0)),
            (self.layer.content_size, ))
        self.plotcam = Camera2D(self.layer.content_size, pos)

    # -- container

    def _initlayer(self):
        """ initializes main plotcontainer.
            the plotcontainer manages border, margin padding
            and contains the main plot framebuffer """

        layer = Container(size=self.size,
                          position=self.position,
                          margin=self._plot_margin,
                          padding=self.plot_padding,
                          border=self._style['border'][0],
                          border_color=self._style['border'][1])

        self.plotframe = FrameWidget(position=layer.content_position,
                                     size=layer.content_size,
                                     resulution=layer.content_size,
                                     clear_color=(0, 0, 0, 0))
        self.layer = layer
        self.layer.content_size.on_change.append(self.update_ubo)

    def tick(self):
        self.on_tick()

        # -- tick the components
        self.plotcam.enable()
        self.layer.tick()
        self.grid.tick()
        self.plotframe.tick()

        # -- graph rendering
        self.plotframe.use()
        self.plotcam.enable()
        self.on_plot()
        self.ubo.bind_buffer_base(
            GPUPY_GL.CONTEXT.buffer_base('gpupy.plot.plotter2d'))
        for graph in self._graphs:
            graph.tick()
            graph.render()
        self.plotframe.unuse()

    def draw(self):
        self.grid.render()
        self.layer.render()
        self.plotframe.render()
Example #11
0
class FramestackWidget(Widget):
    SUBJECT = 0
    IDX = 1
    RENDERER = 2
    CLICKMAP = 3

    M_TOP_LAYER = 1
    M_LAYERS = 0

    resolution = attributes.VectorAttribute(2)
    size = attributes.VectorAttribute(2)
    position = attributes.VectorAttribute(4)

    def __init__(self, position, size, resolution, pf=1):
        super().__init__()
        print(glGetIntegerv(GL_MAX_DRAW_BUFFERS))

        self._s = []
        self.resolution = resolution
        self.size = size
        self.position = position
        self._pf = pf
        self._rs = []
        self._hrl = 0

        self._init_textures()
        self._init_fb()
        self._init_program()
        self._init_mesh()

    def _init_textures(self):
        def _texture(txres):
            txt = Texture2D.empty((self._ln(), *txres, 4),
                                  dtype=np.float32,
                                  array=True)
            txt.activate()
            txt.parameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
            txt.parameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
            return txt

        # LOW TEXTURE
        txres = self.resolution.xy
        self._rs.append(txres)
        self.tarray_rl = _texture(txres) if self._pf != 1 else None

        # MAIN TEXTURE
        txres = self.resolution.xy * self._pf
        self._rs.append(txres)
        self.tarray = _texture(txres)

        # HIGH TEXTURE
        txres = self.resolution.xy * self._pf**2
        self._rs.append(txres)
        self.tarray_rh = _texture(txres) if self._pf != 1 else None

    def _init_fb(self):
        self._rb_fb = glGenFramebuffers(1)
        self._rb_fbs = glGenFramebuffers(100)

    def _init_program(self):

        self._rs_prg = _CameraProgram(_GLSL_VRT, _GLSL_STACK_FRG)

        self._rs_prg.uniform('mat_model', np.identity(4, dtype=np.float32))

        self._rs_prg_layer = Program()
        self._rs_prg_layer.shaders.append(
            Shader(GL_VERTEX_SHADER, _GLSL_STACK_VRT_LAYER))
        self._rs_prg_layer.shaders.append(
            Shader(GL_FRAGMENT_SHADER, _GLSL_STACK_FRG_LAYER))
        self._rs_prg_layer.link()
        self._rs_prg_layer.uniform('frame_texture', self.tarray)

        self.upload_uniforms()

    def _init_mesh(self):
        self._rs_mesh = StridedVertexMesh(
            mesh3d_rectangle(),
            GL_TRIANGLES,
            attribute_locations=self._rs_prg.attributes)

    def upload_uniforms(self):
        self._rs_prg.uniform('size', self.size)
        self._rs_prg.uniform('position', self.position)
        self._rs_prg.uniform('frame_texture', self.tarray)

        self._rs_prg_layer.uniform('frame_texture', self.tarray)

    def _ln(self):
        return 35

    @resolution.on_change
    def _resolution_changed(self, *e):
        return
        if self._pf != 1:
            if self._rs[1][0] < self.resolution[0] \
            or self._rs[1][1] < self.resolution[1]:
                _G.debug('FramestackWidget swap textures HIGH')

                # swap textures
                old_tarray_rl = self.tarray_rl
                self.tarray_rl = self.tarray
                self.tarray = self.tarray_rh
                self.tarray_rh = old_tarray_rl
                self.tarray.activate()
                self._rs[0] = self._rs[1]
                self._rs[1] = self._rs[2]
                self._rs[2] = self._rs[2] * self._pf
                # resize the new small texture
                self.tarray_rh.resize((self._ln(), *self._rs[2]))
                self._rebind_active_fbo()

            elif self.resolution[0]/self._rs[1][0] <= .25 \
            and self.resolution[1]/self._rs[1][1] <= .25:
                _G.debug('FramestackWidget swap textures LOW')

                # swap textures
                old_tarray_rh = self.tarray_rh
                self.tarray_rh = self.tarray
                self.tarray = self.tarray_rl
                self.tarray_rl = old_tarray_rh
                self.tarray.activate()
                self._rs[2] = self._rs[1]
                self._rs[1] = self._rs[0]
                self._rs[0] = self._rs[0] / self._pf

                # resize the new large texture
                self.tarray_rl.resize((self._ln(), *self._rs[0]))
                self._rebind_active_fbo()

            rf = (self.resolution[0] / self._rs[1][0],
                  self.resolution[1] / self._rs[1][1])
            self._rs_prg.uniform('rf', rf)
            self._rs_prg_layer.uniform('rf', rf)
        else:
            self.tarray.resize((self._ln(), *self.resolution.xy))
            self._rs[1] = self.resolution.xy
            self._rs_prg.uniform('rf', (1, 1))
            self._rs_prg_layer.uniform('rf', (1, 1))
        self.upload_uniforms()

    @size.on_change
    @position.on_change
    def _attributes_changed(self, *e):
        self.upload_uniforms()

    def _rebind_active_fbo(self):
        tex = self.tarray.gl_texture_id
        for si in self._s:
            tidx = 2 * si[FramestackWidget.IDX]
            fb = self._rb_fbs[tidx]
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb)
            glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                      tex, 0, tidx)

            tidx = 2 * si[FramestackWidget.IDX] + 1
            fb = self._rb_fbs[tidx]
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb)
            glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                      tex, 0, tidx)

    def render_stack(self, mode=0, layers=None):
        vp = glGetIntegerv(GL_VIEWPORT)
        glViewport(0, 0, *((self.resolution.xy).astype(np.int32)))
        glClearColor(0, 1, 0, 0)
        if layers is not None:
            layers = sorted(layers)

        print('REEE')
        if self._hrl < len(self._rs) - 1:
            print('RENDER LEVEL', self._hrl)
            self._hrl += 1

        # render all layers
        # (slowest mode)
        if mode == self.M_LAYERS:
            glDisable(GL_BLEND)
            last_idx = None if layers is None or layers[0] == 0 else self._s[
                layers[0] - 1][FramestackWidget.IDX]
            self._rs_prg_layer.uniform('idxl', -1)

            stack = self._s
            if layers is not None:
                stack = [(si, i in layers)
                         for i, si in enumerate(self._s[layers[0]:], layers[0])
                         ]
            else:
                stack = [(si, True) for si in self._s]

            for si, rerender in stack:
                # render item
                if rerender:
                    glBindFramebuffer(
                        GL_DRAW_FRAMEBUFFER,
                        self._rb_fbs[_tidx(si[FramestackWidget.IDX])])
                    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
                    si[self.RENDERER]()

                # render layer
                glBindFramebuffer(
                    GL_DRAW_FRAMEBUFFER,
                    self._rb_fbs[_tidxl(si[FramestackWidget.IDX])])
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
                self._rs_prg_layer.use()
                self._rs_prg_layer.uniform('idx',
                                           _tidx(si[FramestackWidget.IDX]))
                self._rs_prg_layer.uniform('clickmap',
                                           si[FramestackWidget.CLICKMAP])
                if last_idx is not None:
                    self._rs_prg_layer.uniform('idxl', _tidxl(last_idx))
                    self._rs_prg_layer.uniform('idxc', _tidxc(last_idx))
                self._rs_mesh.draw()
                self._rs_prg_layer.unuse()
                last_idx = si[FramestackWidget.IDX]

            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)

        # render all items to the top layer directly
        # (this is the fastest rendering method)
        elif mode == self.M_TOP_LAYER:
            print('TOP')
            #glEnable(GL_BLEND)
            #glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
            fb = self._rb_fbs[_tidxl(self._s[len(self._s) -
                                             1][FramestackWidget.IDX])]
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb)
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

            stack = (self._s[i]
                     for i in layers) if layers is not None else self._s
            for si in stack:
                si[self.RENDERER]()
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)
            self._hrl = 0

        glViewport(*vp)

    def render(self):
        self.tarray.activate()
        self._rs_prg.use()
        self._rs_prg.uniform(
            'idx', _tidxl(self._s[len(self._s) - 1][FramestackWidget.IDX]))
        self._rs_mesh.draw()
        self._rs_prg.unuse()

    def _free_idx(self):
        sidx = sorted(self._s, key=lambda rsi: rsi[FramestackWidget.IDX])
        for idx, rsi in enumerate(sidx):
            if rsi[FramestackWidget.IDX] != idx:
                return idx
        return len(sidx)

    def _caller(self, renderer):
        if hasattr(renderer, '__call__'):
            return renderer
        if hasattr(renderer, 'render'):
            return renderer.render
        raise ValueError()

    def get_layer(self, renderer):
        for i, si in enumerate(self._s):
            if si[0] is renderer:
                return i

    def append(self, subject, clickmap=(0, 0, 0, 0)):
        idx = self._free_idx()
        self._init_layer(idx)

        si = _StackItem()
        si.subject = subject
        si.idx = idx
        si.clickmap = clickmap
        si.renderer = self._caller(subject)
        si.init_gl(self.resolution.xy)

        self._s.append((subject, idx, self._caller(subject), clickmap))
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)

    def insert(self, i, renderer, clickmap=(0, 0, 0, 0)):
        idx = self._free_idx()
        self._init_layer(idx)
        self._s.insert(i, (renderer, idx, self._caller(renderer), clickmap))
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)

    def _init_layer(self, idx):
        # we perform at least one clear operation on each texture on init.
        # otherwise OpenGL will lag when switching to another texture for the first
        # time.

        if self._pf != 1:
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self._rb_fbs[_tidx(idx)])
            glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                      self.tarray_rh.gl_texture_id, 0,
                                      _tidx(idx))
            glClear(GL_COLOR_BUFFER_BIT)
            glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                      self.tarray_rl.gl_texture_id, 0,
                                      _tidx(idx))
            glClear(GL_COLOR_BUFFER_BIT)

            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self._rb_fbs[_tidxl(idx)])
            glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                      self.tarray_rh.gl_texture_id, 0,
                                      _tidxl(idx))
            glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
                                      self.tarray_rl.gl_texture_id, 0,
                                      _tidxc(idx))
            glClear(GL_COLOR_BUFFER_BIT)
            glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                      self.tarray_rl.gl_texture_id, 0,
                                      _tidxl(idx))
            glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
                                      self.tarray_rl.gl_texture_id, 0,
                                      _tidxc(idx))
            glClear(GL_COLOR_BUFFER_BIT)

        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self._rb_fbs[_tidx(idx)])
        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                  self.tarray.gl_texture_id, 0, _tidx(idx))
        glClear(GL_COLOR_BUFFER_BIT)

        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self._rb_fbs[_tidxl(idx)])
        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                  self.tarray.gl_texture_id, 0, _tidxl(idx))
        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
                                  self.tarray.gl_texture_id, 0, _tidxc(idx))
        glDrawBuffers([GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1])
        glClear(GL_COLOR_BUFFER_BIT)

        glBindFramebuffer(GL_FRAMEBUFFER, 0)
Example #12
0
class RaycastingDemoWidget():
    size = attributes.VectorAttribute(2)
    zoom = attributes.VectorAttribute(3, (1, 1, 1))
    rotation = attributes.VectorAttribute(3, (0, 0, 0))
    box_rotation = attributes.VectorAttribute(3, (0, 0, 0))

    def __init__(self, size, volumedata):
        self.size = size
        self.force_viewbox_render = True
        self.volumedata = volumedata
        self.init()

    @zoom.on_change
    @rotation.on_change
    def upload_mat_volume(self, *e):
        self.program_ray.uniform(
            'mat_volume',
            mat4_rot_x(self.rotation.x) @ mat4_rot_y(self.rotation.y)
            @ np.diag([self.zoom.x, self.zoom.x, self.zoom.x, 1]))

    @box_rotation.on_change
    def upload_mat_model(self, *e):
        self.force_viewbox_render = True
        self.program_box.uniform(
            'mat_model',
            mat4_rot_x(self.box_rotation.x) @ mat4_rot_y(self.box_rotation.y))

    def init(self):

        glEnable(GL_BLEND)
        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LESS)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glFrontFace(GL_CW)

        self._create_shader()

        rect_size = self.size
        rect_position = (-rect_size[0] / 2, -rect_size[1] / 2)
        self.cube_buffer = BufferObject.to_device(
            mesh3d_cube((200, 200, 200), center=True))
        self.vao = create_vao_from_program_buffer_object(
            self.program_box, self.cube_buffer)

        # create texture for front and backside
        #
        # since we'll use the same camera inside the framebuffer we have
        # to put the framebuffer size to the size of the main window framebuffer.
        # w
        # otherwise we could scale the camera to compensate the difference in window
        # size and framebuffer size.
        self.texture_front = Texture2D.empty((*CUBE_FRAMEBUFFER, 4),
                                             np.float32)
        self.framebuffer_front = Framebuffer()
        self.framebuffer_front.color_attachment(self.texture_front)
        self.texture_back = Texture2D.empty((*CUBE_FRAMEBUFFER, 4), np.float32)
        self.framebuffer_back = Framebuffer()
        self.framebuffer_back.color_attachment(self.texture_back)

        # create framebuffer screen (this is the widget main screen)
        rect_size = [2, 2]
        rect_position = (-rect_size[0] / 2, -rect_size[1] / 2)
        self.screen_buffer = BufferObject.to_device(
            mesh3d_rectangle(center=rect_position, *rect_size))
        self.screen_vao = create_vao_from_program_buffer_object(
            self.program_ray, self.screen_buffer)

        # create 3d texture
        self.texture = Texture3D.from_numpy(self.volumedata)
        self.texture.interpolation_nearest()
        self.texture.parameters.update({
            GL_TEXTURE_WRAP_S: GL_CLAMP_TO_BORDER,
            GL_TEXTURE_WRAP_T: GL_CLAMP_TO_BORDER,
            GL_TEXTURE_WRAP_R: GL_CLAMP_TO_BORDER
        })

        self.program_ray.uniform({
            'tex':
            self.texture_front.activate(0),
            'back':
            self.texture_back.activate(1),
            'vol':
            self.texture.activate(2),
            'v_ray':
            V_RAY,
            'v_iter':
            V_ITER,
            'mat_volume':
            np.array([0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1.0],
                     dtype=np.float32)
        })

        self.force_viewbox_render = True

        self.upload_mat_model()
        self.upload_mat_volume()

    def _create_shader(self):
        """ creates the ray casting shader and the
            raydirection box shader """
        self.program_box = create_program(vertex=BOX_VRT_SHADER,
                                          fragment=BOX_FRG_SHADER,
                                          link=False)
        self.program_box.declare_uniform('camera',
                                         Perspective3D.DTYPE,
                                         variable='camera')
        self.program_box.link()

        self.program_box.uniform_blocks[
            'camera'] = GPUPY_GL.CONTEXT.buffer_base('gpupy.gl.camera')
        self.program_box.uniforms['mat_model'] = np.array(
            [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], dtype=np.float32)

        self.program_ray = create_program(vertex=RAYCASTING_VRT_SHADER,
                                          fragment=RAYCASTING_FRG_SHADER)

    def __call__(self):
        # check if we need to recalculate the culled
        # fron and back face frame buffers
        if self.force_viewbox_render:
            self._render_culled_box()
            self.force_viewbox_render = False

        # reset main frame
        glClearColor(0, 0, 0, 0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        # box for debugging purpose
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
        self._render_box()
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)

        # volumetric raycasting
        self._render_raycast()

        return True

    def _render_box(self):
        self.program_box.use()
        glBindVertexArray(self.vao)
        glDrawArrays(GL_TRIANGLES, 0, len(self.cube_buffer))
        glBindVertexArray(0)
        self.program_box.unuse()

    def _render_raycast(self):
        self.texture_front.reactivate()
        self.texture_back.reactivate()

        self.program_ray.use()
        glBindVertexArray(self.screen_vao)
        glDrawArrays(GL_TRIANGLES, 0, len(self.screen_buffer))
        glBindVertexArray(0)
        self.program_ray.unuse()

    def _render_culled_box(self):
        # prepare
        old_viewport = glGetIntegerv(GL_VIEWPORT)
        glViewport(0, 0, *CUBE_FRAMEBUFFER)
        glDisable(GL_DEPTH_TEST)
        glEnable(GL_CULL_FACE)
        glClearColor(0, 0, 0, 0)
        self.program_box.use()

        # render front faces
        self.framebuffer_front.use()
        glCullFace(GL_FRONT)
        glClear(GL_COLOR_BUFFER_BIT)
        glBindVertexArray(self.vao)
        glDrawArrays(GL_TRIANGLES, 0, len(self.cube_buffer))
        glBindVertexArray(0)
        self.framebuffer_front.unuse()

        # render back faces
        self.framebuffer_back.use()
        glClear(GL_COLOR_BUFFER_BIT)
        glCullFace(GL_BACK)
        glBindVertexArray(self.vao)
        glDrawArrays(GL_TRIANGLES, 0, len(self.cube_buffer))
        glBindVertexArray(0)
        self.framebuffer_back.unuse()

        # restore
        self.program_box.unuse()
        glEnable(GL_DEPTH_TEST)
        glDisable(GL_CULL_FACE)
        glViewport(*old_viewport)
Example #13
0
class TextWidget():
    size = attributes.VectorAttribute(2)

    def __init__(self, size):
        self.size = size
        self.init()

    def init(self):
        # note that in Widget init the context should be active!
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        self.program = create_program(vertex=VERTEX_SHADER,
                                      fragment=FRAGMENT_SHADER,
                                      link=False)

        # the shader uses {% uniform block %} tags which we must
        # declare before linking the program
        self.program.declare_uniform('camera',
                                     Cartesian2D.DTYPE,
                                     variable='camera')
        self.program.link()

        # we need to tell the shader which is is buffer base.
        # the GPUPY_GL.CONTEXT.buffer_base returns a free buffer
        # base which is reserved for the active context.
        self.program.uniform_blocks['camera'] = GPUPY_GL.CONTEXT.buffer_base(
            'gpupy.gl.camera')

        # the mesh represents VAO and VBO
        self.mesh = StridedVertexMesh(
            mesh3d_rectangle(center=(-self.size[0] / 2, -self.size[1] / 2),
                             *self.size),
            GL_TRIANGLES,
            attribute_locations=self.program.attributes)

        # create texture and buffers
        self.texture = Texture2D.from_numpy(
            np.random.random((500, 500, 3)).astype(np.float32))
        self.texture.interpolation_linear()
        self.texture.activate(0)

        self.step = 1
        self.last_random = 1

    def __call__(self):
        # a widget is something which is callable.

        # render me
        glClear(GL_COLOR_BUFFER_BIT)
        self.program.use()
        self.texture.reactivate()
        self.mesh.draw()
        self.texture.unbind()
        self.program.unuse()

        # texture update
        self._update_data()

        # to keep the widget alive return True
        return True

    def _update_data(self):
        # do some funny stuff
        if self.last_random > 0.1:
            channels, size = 4, 500
        elif self.last_random > 0.04:
            channels, size = 3, 300
        elif self.last_random > 0.02:
            channels, size = 2, 700
        else:
            channels, size = 1, 50
        new_data = np.random.random((size, size, channels))
        new_data[:][self.step % size] = 1
        new_data[:][(2 * self.step) % size] = 1
        new_data[:][(3 * self.step) % size] = 1
        new_data[:][(4 * self.step) % size] = 1
        self.texture.load(new_data.astype(np.float32))
        self.last_random = new_data[0][0][0]
        self.step += 1
Example #14
0
class GLFW_Window(Context):
    size = attributes.VectorAttribute(2)
    resolution = attributes.VectorAttribute(2)
    position = attributes.VectorAttribute(2)
    title = attributes.CastedAttribute(str, 'window')
    visible = attributes.CastedAttribute(bool)

    def __init__(self,
                 size=(400, 400),
                 title='gpupy glfw window',
                 bootstrap=True,
                 widget=None):
        super().__init__()
        self._glfw_initialized = False
        self.size = size
        self.title = title
        self.visible = True
        self._active = False
        self.active_keys = set()
        self._in_cycle = False
        if bootstrap:
            self.bootstrap()

        self.make_context()
        self.widget = widget or (lambda *a: True)

    @visible.on_change
    def set_visible(self, visible):
        if visible:
            glfwShowWindow(self._handle)
        else:
            glfwHideWindow(self._handle)

    @size.on_change
    def set_size(self, size):
        glfwSetWindowSize(self._handle, int(size[0]), int(size[1]))

    def bootstrap(self):
        """
        start GLFW window context
        """
        if self._glfw_initialized:
            raise RuntimeError('allready initialized.')

        self._handle = glfwCreateWindow(int(self.size[0]), int(self.size[1]),
                                        self.title)

        if not self._handle:
            raise RuntimeError('glfw.CreateWindow() error')

        glfwWindowHint(GLFW_VISIBLE, int(self.visible))

        def _resize_callback(window, width, height):
            self.size = (width, height)

            if len(self.on_resize):
                # at this point we only make a new context if we are not just
                # within GLFW_Application.cycle method. E.g. if GLFW_Window.set_size()
                # was performed within the GLFW_Window.cycle() method.
                if not self._in_cycle:
                    self.make_context()
                    self.on_cycle(self)
                self.on_resize(self)
                if not self._in_cycle:
                    glfwSwapBuffers(self._handle)

        def _key_callback(window, keycode, scancode, action, option):
            """ put glfw keyboard event data into active and
                pressed keyboard buffer """
            if action == GLFW_PRESS:
                self.active_keys.add(GLFW_Context.KEYBOARD_MAP[keycode])
            elif action == GLFW_RELEASE:
                self.active_keys.remove(GLFW_Context.KEYBOARD_MAP[keycode])

        def _v2_callback(attr, window, width, height):
            setattr(self, attr, (width, height))

        def _close_callback(*e):
            self.on_close(self)

        glfwSetWindowSizeCallback(self._handle, _resize_callback)
        glfwSetFramebufferSizeCallback(self._handle,
                                       partial(_v2_callback, 'resolution'))
        glfwSetWindowCloseCallback(self._handle, _close_callback)
        glfwSetKeyCallback(self._handle, _key_callback)
        glfwSetWindowTitle(self._handle, self.title)

        self.resolution = glfwGetFramebufferSize(self._handle)

        self._glfw_initialized = True

    def make_context(self):
        """
        make the glfw handle the current context
        and assigns itself to GPUPY_GL.CONTEXT.
        """
        if not self._active:
            glfwMakeContextCurrent(self._handle)
            self._active = True

        GPUPY_GL.CONTEXT = self

    def __call__(self):
        """
        runs the gl cycle and executed
        the widget. 

        Returns:
        - Bool: whether the window should be closed or not
        """
        self.make_context()
        self._in_cycle = True

        # GLFW close state
        if glfwWindowShouldClose(self._handle):
            self._active = False
            return False

        # run widget and close if return value is False
        self.on_cycle(self)
        success = self.widget()
        glfwSwapBuffers(self._handle)
        self._in_cycle = False
        if not success:
            self._active = False
            return False

        self._active = True
        return True
Example #15
0
class GLFW_Context(Context):
    KEYBOARD_MAP = {
        GLFW_KEY_SPACE: KEY_SPACE,
        GLFW_KEY_APOSTROPHE: KEY_APOSTROPHE,
        GLFW_KEY_COMMA: KEY_COMMA,
        GLFW_KEY_MINUS: KEY_MINUS,
        GLFW_KEY_PERIOD: KEY_PERIOD,
        GLFW_KEY_SLASH: KEY_SLASH,
        GLFW_KEY_0: KEY_0,
        GLFW_KEY_1: KEY_1,
        GLFW_KEY_2: KEY_2,
        GLFW_KEY_3: KEY_3,
        GLFW_KEY_4: KEY_4,
        GLFW_KEY_5: KEY_5,
        GLFW_KEY_6: KEY_6,
        GLFW_KEY_7: KEY_7,
        GLFW_KEY_8: KEY_8,
        GLFW_KEY_9: KEY_9,
        GLFW_KEY_SEMICOLON: KEY_SEMICOLON,
        GLFW_KEY_EQUAL: KEY_EQUAL,
        GLFW_KEY_A: KEY_A,
        GLFW_KEY_B: KEY_B,
        GLFW_KEY_C: KEY_C,
        GLFW_KEY_D: KEY_D,
        GLFW_KEY_E: KEY_E,
        GLFW_KEY_F: KEY_F,
        GLFW_KEY_G: KEY_G,
        GLFW_KEY_H: KEY_H,
        GLFW_KEY_I: KEY_I,
        GLFW_KEY_J: KEY_J,
        GLFW_KEY_K: KEY_K,
        GLFW_KEY_L: KEY_L,
        GLFW_KEY_M: KEY_M,
        GLFW_KEY_N: KEY_N,
        GLFW_KEY_O: KEY_O,
        GLFW_KEY_P: KEY_P,
        GLFW_KEY_Q: KEY_Q,
        GLFW_KEY_R: KEY_R,
        GLFW_KEY_S: KEY_S,
        GLFW_KEY_T: KEY_T,
        GLFW_KEY_U: KEY_U,
        GLFW_KEY_V: KEY_V,
        GLFW_KEY_W: KEY_W,
        GLFW_KEY_X: KEY_X,
        GLFW_KEY_Y: KEY_Y,
        GLFW_KEY_Z: KEY_Z,
        GLFW_KEY_LEFT_BRACKET: KEY_LEFT_BRACKET,
        GLFW_KEY_BACKSLASH: KEY_BACKSLASH,
        GLFW_KEY_RIGHT_BRACKET: KEY_RIGHT_BRACKET,
        GLFW_KEY_GRAVE_ACCENT: KEY_GRAVE_ACCENT,
        GLFW_KEY_WORLD_1: KEY_WORLD_1,
        GLFW_KEY_WORLD_2: KEY_WORLD_2,
        GLFW_KEY_ESCAPE: KEY_ESCAPE,
        GLFW_KEY_ENTER: KEY_ENTER,
        GLFW_KEY_TAB: KEY_TAB,
        GLFW_KEY_BACKSPACE: KEY_BACKSPACE,
        GLFW_KEY_INSERT: KEY_INSERT,
        GLFW_KEY_DELETE: KEY_DELETE,
        GLFW_KEY_RIGHT: KEY_RIGHT,
        GLFW_KEY_LEFT: KEY_LEFT,
        GLFW_KEY_DOWN: KEY_DOWN,
        GLFW_KEY_UP: KEY_UP,
        GLFW_KEY_PAGE_UP: KEY_PAGE_UP,
        GLFW_KEY_PAGE_DOWN: KEY_PAGE_DOWN,
        GLFW_KEY_HOME: KEY_HOME,
        GLFW_KEY_END: KEY_END,
        GLFW_KEY_CAPS_LOCK: KEY_CAPS_LOCK,
        GLFW_KEY_SCROLL_LOCK: KEY_SCROLL_LOCK,
        GLFW_KEY_NUM_LOCK: KEY_NUM_LOCK,
        GLFW_KEY_PRINT_SCREEN: KEY_PRINT_SCREEN,
        GLFW_KEY_PAUSE: KEY_PAUSE,
        GLFW_KEY_F1: KEY_F1,
        GLFW_KEY_F2: KEY_F2,
        GLFW_KEY_F3: KEY_F3,
        GLFW_KEY_F4: KEY_F4,
        GLFW_KEY_F5: KEY_F5,
        GLFW_KEY_F6: KEY_F6,
        GLFW_KEY_F7: KEY_F7,
        GLFW_KEY_F8: KEY_F8,
        GLFW_KEY_F9: KEY_F9,
        GLFW_KEY_F10: KEY_F10,
        GLFW_KEY_F11: KEY_F11,
        GLFW_KEY_F12: KEY_F12,
        GLFW_KEY_F13: KEY_F13,
        GLFW_KEY_F14: KEY_F14,
        GLFW_KEY_F15: KEY_F15,
        GLFW_KEY_F16: KEY_F16,
        GLFW_KEY_F17: KEY_F17,
        GLFW_KEY_F18: KEY_F18,
        GLFW_KEY_F19: KEY_F19,
        GLFW_KEY_F20: KEY_F20,
        GLFW_KEY_F21: KEY_F21,
        GLFW_KEY_F22: KEY_F22,
        GLFW_KEY_F23: KEY_F23,
        GLFW_KEY_F24: KEY_F24,
        GLFW_KEY_F25: KEY_F25,
        GLFW_KEY_KP_0: KEY_KP_0,
        GLFW_KEY_KP_1: KEY_KP_1,
        GLFW_KEY_KP_2: KEY_KP_2,
        GLFW_KEY_KP_3: KEY_KP_3,
        GLFW_KEY_KP_4: KEY_KP_4,
        GLFW_KEY_KP_5: KEY_KP_5,
        GLFW_KEY_KP_6: KEY_KP_6,
        GLFW_KEY_KP_7: KEY_KP_7,
        GLFW_KEY_KP_8: KEY_KP_8,
        GLFW_KEY_KP_9: KEY_KP_9,
        GLFW_KEY_KP_DECIMAL: KEY_KP_DECIMAL,
        GLFW_KEY_KP_DIVIDE: KEY_KP_DIVIDE,
        GLFW_KEY_KP_MULTIPLY: KEY_KP_MULTIPLY,
        GLFW_KEY_KP_SUBTRACT: KEY_KP_SUBTRACT,
        GLFW_KEY_KP_ADD: KEY_KP_ADD,
        GLFW_KEY_KP_ENTER: KEY_KP_ENTER,
        GLFW_KEY_KP_EQUAL: KEY_KP_EQUAL,
        GLFW_KEY_LEFT_SHIFT: KEY_LEFT_SHIFT,
        GLFW_KEY_LEFT_CONTROL: KEY_LEFT_CONTROL,
        GLFW_KEY_LEFT_ALT: KEY_LEFT_ALT,
        GLFW_KEY_LEFT_SUPER: KEY_LEFT_SUPER,
        GLFW_KEY_RIGHT_SHIFT: KEY_RIGHT_SHIFT,
        GLFW_KEY_RIGHT_CONTROL: KEY_RIGHT_CONTROL,
        GLFW_KEY_RIGHT_ALT: KEY_RIGHT_ALT,
        GLFW_KEY_RIGHT_SUPER: KEY_RIGHT_SUPER,
        GLFW_KEY_MENU: KEY_MENU,
        GLFW_KEY_LAST: KEY_LAST,
    }
    size = attributes.VectorAttribute(2)
    resolution = attributes.VectorAttribute(2)
    position = attributes.VectorAttribute(2)
    title = attributes.CastedAttribute(str, 'window')
    visible = attributes.CastedAttribute(bool)
    """ 
    a glfw context manages the window created by glfwCreateWindow.
    """
    def __init__(self, size, title='no title'):
        super().__init__()
        self.size = size
        self.title = title
        self.visible = True
        self._handle = None
        self._glfw_initialized = False
        self._active = False

    def _close_callback(self, *e):
        self.on_close(self)

    @visible.on_change
    def set_visible(self, visible):
        if visible:
            glfwShowWindow(self._handle)
        else:
            glfwHideWindow(self._handle)

    @size.on_change
    def set_size(self, size):
        glfwSetWindowSize(self._handle, int(size[0]), int(size[1]))

    def bootstrap(self):
        if self._glfw_initialized:
            raise RuntimeError('allready initialized.')

        self._handle = glfwCreateWindow(int(self.size[0]), int(self.size[1]),
                                        self.title)
        if not self._handle:
            raise RuntimeError('glfw.CreateWindow() error')

        glfwWindowHint(GLFW_VISIBLE, int(self.visible))

        def _v2_callback(attr, window, width, height):
            setattr(self, attr, (width, height))

        glfwSetWindowSizeCallback(self._handle, self.resize_callback)
        glfwSetFramebufferSizeCallback(self._handle,
                                       partial(_v2_callback, 'resolution'))
        glfwSetWindowCloseCallback(self._handle, self._close_callback)
        glfwSetKeyCallback(self._handle, self.key_callback)
        glfwSetWindowTitle(self._handle, 'wewf')
        self.resolution = glfwGetFramebufferSize(self._handle)

        self._glfw_initialized = True

    def context(self):
        if glfwWindowShouldClose(self._handle):
            self.on_close(self)

        if not self._active:
            glfwMakeContextCurrent(self._handle)
            self._active = True

        super().__gl_context_enable__()

    def resize_callback(self, window, width, height):
        """ triggers on_resize event queue and swaps GLFW buffers. """
        self.size = (width, height)

        if len(self.on_resize):
            # at this point we only make a new context if we are not just
            # within GLFW_Application.cycle method. E.g. if GLFW_Window.set_size()
            # was performed within the GLFW_Window.cycle() method.
            if not self._in_cycle:
                self.__gl_context_enable__()
            self.on_resize(self)
            if not self._in_cycle:
                glfwSwapBuffers(self._handle)

    def key_callback(self, window, keycode, scancode, action, option):
        """ put glfw keyboard event data into active and
            pressed keyboard buffer """
        if action == GLFW_PRESS:
            self.active_keys.add(GLFW_Context.KEYBOARD_MAP[keycode])
        elif action == GLFW_RELEASE:
            self.active_keys.remove(GLFW_Context.KEYBOARD_MAP[keycode])

    def cycle(self):
        if glfwWindowShouldClose(self._handle):
            raise CloseContextException()

        self._in_cycle = True
        self.__gl_context_enable__()
        self.on_cycle(self)
        glfwSwapBuffers(self._handle)
        self._in_cycle = False

    def __del__(self):
        glfwDestroyWindow(self._handle)
Example #16
0
class DomainGraph(components.widgets.Widget):
    """ 
    abstract class for graphs which are using
    the domain concept for plotting data. 

    """

    DEFAULT_DOMAIN_NAME = 'domain'

    resolution = attributes.VectorAttribute(2, (1, 1))
    viewport = attributes.VectorAttribute(2, (1, 1))

    def __init__(self, domain=None):
        """
        initializes the graph with one or many domains. 
        argument domain is an dict, it is interpreted as 
        (key, domain) pairs.
        """
        super().__init__()
        self.domains = OrderedDict()

        if isinstance(domain, dict):
            for k, v in domain.items():
                self[k] = v
        elif domain is not None:
            self[DomainGraph.DEFAULT_DOMAIN_NAME] = domain 


    def __setitem__(self, key, domain):
        """
        adds a domain to the graph
        """
        safe_name(key)
        domain.requires(list(self.domains.keys()))
        self.domains[key] = _DomainInfo(domain, 'd_{}'.format(key))


    def __getitem__(self, key):
        """
        returns a domain by key
        """
        return self.domains[key].domain


    def get_domain_glsl_substitutions(self):
        """
        returns a list of tuples 
          (glsl_substitution, glsl_identifier)

        where glsl_substitution is the name of the
        substitution e.g. ${name}
        """
        domain_sfnames = {}
        for dname, domain in self.domains.items():
            for field, glsl_id, glsl_meta, glsl_type in domain.glsl_identifier:
                substkey = 'D.'+dname
                if field is not None:
                    substkey += '.{}'.format(field)
                domain_sfnames.update({substkey: glsl_id})
        return domain_sfnames


    def _enable_domain_attrib_pointers(self):
        """
        enable all vertex attribute pointers
        from domains
        """
        for domain_info in self.domains.values():
            domain = domain_info.domain
            if hasattr(domain, 'attrib_pointers'):
                domain.attrib_pointers(domain_info.prefix, self.program.attributes)