diff options
Diffstat (limited to 'silx/gui/plot3d/scene/viewport.py')
-rw-r--r-- | silx/gui/plot3d/scene/viewport.py | 75 |
1 files changed, 69 insertions, 6 deletions
diff --git a/silx/gui/plot3d/scene/viewport.py b/silx/gui/plot3d/scene/viewport.py index 41aa999..6de640e 100644 --- a/silx/gui/plot3d/scene/viewport.py +++ b/silx/gui/plot3d/scene/viewport.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2015-2018 European Synchrotron Radiation Facility +# Copyright (c) 2015-2019 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -36,6 +36,7 @@ __license__ = "MIT" __date__ = "24/04/2018" +import string import numpy from silx.gui.colors import rgba @@ -45,7 +46,7 @@ from ..._glutils import gl from . import camera from . import event from . import transform -from .function import DirectionalLight, ClippingPlane +from .function import DirectionalLight, ClippingPlane, Fog class RenderContext(object): @@ -61,12 +62,33 @@ class RenderContext(object): :param Context glContext: The operating system OpenGL context in use. """ + _FRAGMENT_SHADER_SRC = string.Template(""" + void scene_post(vec4 cameraPosition) { + gl_FragColor = $fogCall(gl_FragColor, cameraPosition); + } + """) + def __init__(self, viewport, glContext): self._viewport = viewport self._glContext = glContext self._transformStack = [viewport.camera.extrinsic] self._clipPlane = ClippingPlane(normal=(0., 0., 0.)) + # cache + self.__cache = {} + + def cache(self, key, factory, *args, **kwargs): + """Lazy-loading cache to store values in the context for rendering + + :param key: The key to retrieve + :param factory: A callback taking args and kwargs as arguments + and returning the value to store. + :return: The stored or newly allocated value + """ + if key not in self.__cache: + self.__cache[key] = factory(*args, **kwargs) + return self.__cache[key] + @property def viewport(self): """Viewport doing the current rendering""" @@ -127,8 +149,7 @@ class RenderContext(object): @property def clipper(self): - """The current clipping plane - """ + """The current clipping plane (ClippingPlane)""" return self._clipPlane def setClipPlane(self, point=(0., 0., 0.), normal=(0., 0., 0.)): @@ -143,6 +164,40 @@ class RenderContext(object): """ self._clipPlane = ClippingPlane(point, normal) + def setupProgram(self, program): + """Sets-up uniforms of a program using the context shader functions. + + :param GLProgram program: The program to set-up. + It MUST be in use and using the context function. + """ + self.clipper.setupProgram(self, program) + self.viewport.fog.setupProgram(self, program) + + @property + def fragDecl(self): + """Fragment shader declaration for scene shader functions""" + return '\n'.join(( + self.clipper.fragDecl, + self.viewport.fog.fragDecl, + self._FRAGMENT_SHADER_SRC.substitute( + fogCall=self.viewport.fog.fragCall))) + + @property + def fragCallPre(self): + """Fragment shader call for scene shader functions (to do first) + + It takes the camera position (vec4) as argument. + """ + return self.clipper.fragCall + + @property + def fragCallPost(self): + """Fragment shader call for scene shader functions (to do last) + + It takes the camera position (vec4) as argument. + """ + return "scene_post" + class Viewport(event.Notifier): """Rendering a single scene through a camera in part of a framebuffer. @@ -170,6 +225,9 @@ class Viewport(event.Notifier): ambient=(0.3, 0.3, 0.3), diffuse=(0.7, 0.7, 0.7)) self._light.addListener(self._changed) + self._fog = Fog() + self._fog.isOn = False + self._fog.addListener(self._changed) @property def transforms(self): @@ -224,6 +282,11 @@ class Viewport(event.Notifier): return self._light @property + def fog(self): + """The fog function used to render the scene""" + return self._fog + + @property def origin(self): """Origin (ox, oy) of the viewport in pixels""" return self._origin @@ -351,8 +414,8 @@ class Viewport(event.Notifier): """ bounds = self.scene.bounds(transformed=True) if bounds is None: - bounds = numpy.array(((0., 0., 0.), (1., 1., 1.)), - dtype=numpy.float32) + bounds = numpy.array(((0., 0., 0.), (1., 1., 1.)), + dtype=numpy.float32) self.camera.resetCamera(bounds) def orbitCamera(self, direction, angle=1.): |