Shady Package
The World
Class
- class Shady.World(width=None, height=None, left=None, top=None, screen=None, threaded=True, canvas=False, frame=False, fullScreenMode=None, visible=True, openglContextVersion=None, legacy=None, backend=None, acceleration=None, debugTiming=False, profile=False, syncType=-1, logfile=None, reportVersions=False, window=None, **kwargs)
Bases:
LinkGL
A
World
instance encapsulates the window and rendering environment in which you draw stimuli. By default, aWorld
will fill one screen, but its size, offset and decoration can also be tailored explicitly if necessary. When you initialize aWorld
, Shady creates an OpenGL program and compiles and links a vertex shader and a fragment shader to it: this is what allows signal generation, contrast modulation, windowing, gamma correction and dithering to be performed on the graphics processor.Once you have created the
World
, you will probably want to call need to call theStimulus()
method one or more times, to configure the things that should be drawn in it.- Parameters:
width (int) – width of drawable area in “screen coordinates” (which usually means pixels, but see the note below).
height (int) – height of drawable area in “screen coordinates” (which usually means pixels, but see the note below).
size (int, tuple or list) – width and height of drawable area in “screen coordinates” (see note below). If this is a single number, it is used for both width and height. If it is a
tuple
orlist
, it is interpreted as [width, height]. However, the separatewidth
and/orheight
arguments take precedence, if supplied.left (int) – horizontal offset from the edge of the screen, in “screen coordinates” (which usually means pixels, but see the note below).
top (int) – vertical offset from the top of the screen, in “screen coordinates” (which usually means pixels, but see the note below).
screen (int) – Screen number. 0 or
None
(default) means use whichever is designated as the primary screen. A positive integer explicitly selects a screen number. The output of the globalScreens()
function may help you choose the screen number you want.threaded (bool) – If you specify
threaded=False
, theWorld
’s main rendering/event- processing loop will not be started automatically: you will have to start it yourself, from the appropriate thread, using theRun()
method. In this case, the best way to perform initialWorld
configuration andStimulus
creation is to put the code in the body of aPrepare()
method that you specify by subclassingWorld
.With
threaded=True
, a new thread will be created to perform all the work ofWorld
construction and then, automatically, to run the main loop. Any subsequent call to theRun()
method will do nothing except sleep until the thread ends. This is the easiest way to use Shady: you can then create and manipulate stimuli either from aPrepare
method, or from wherever else you want. This appears to work well on Windows, but will have problems (which can only partially be worked-around) on other operating systems: see theShady.Documentation.Concurrency
docstring or click here.canvas (bool) – If you set this to
True
a “canvas”Stimulus
instance will be created automatically, filling the screen behind other stimuli. If you do not create one automatically like this, you can do it later by calling theMakeCanvas()
method. A canvas allows gamma-correction and dynamic-range enhancement tricks to be performed on the backdrop as well as on your foreground stimuli, and it allows theWorld
’s “atmosphere” properties (backgroundColor
,gamma
,noiseAmplitude
and friends) to take effect: see theShady.Documentation.PreciseControlOfLuminance
docstring or click here.frame (bool) – Whether or not to draw a frame and title-/drag- bar around the window.
fullScreenMode (bool) – Default behavior is to create a window that exactly covers one screen. This can be done by creating an ordinary window that just happens to be the same size as the screen (
fullScreenMode=False
) or by actually asking the system to change to full-screen mode (fullScreenMode=True
). The default on Windows isFalse
, since it allows you to switch windows (e.g. with alt-Tab) and still have the Shady window visible in the background (note however, that background windows have poor timing precision - to render precisely without skipping frames you will need to keep the window in the foreground). WithfullScreenMode=True
this is impossible: the window will disappear when it loses focus. On the Mac, the default setting for full-sized windows isfullScreenMode=True
, because this seems to be the only way to hide the menu bar at the top of the screen.For non-full-sized windows, the default is
fullScreenMode=False
. If you set it toTrue
while also explicitly designating the size of theWorld
, the OS will attempt to change resolution. This will probably be a bad idea for psychophysical applications on most modern screens: for rendering accuracy, you should address the screen at its native (maximum) resolution.(Experimental feature, only available when using the ShaDyLib accelerator:) you can also specify a number greater than 1 for
fullScreenMode
, in which case Shady will try to use this as the refresh rate for the screen.visible (bool) – If you set this to
False
, the window will be created off-screen and will only become visible when you set itsvisible
property toTrue
.debugTiming (bool) – Every
World
records the timing intervals between its frame callbacks, to aid in analyzing timing performance. If you setdebugTiming=True
, it will record additional information that breaks down the allocation of this time. By default the setting will be propagated to everyStimulus
instance as well (set eachstim.debugTiming=False
if this is not what you want—if there are many stimuli, then the timing debug calls themselves can start to have a measurable impact on performance).logfile (str) – Optionally specify the name of a text file which will log various pieces of useful diagnostic information. If your filename includes the substring
{}
, this will be replaced by ayyyymmdd-HHMMSS
local timestamp. If the file stem ends with-full
thenself.logger.logSystemInfoOnClose
will be set toTrue
by default which means that a third-party program will be run when theWorld
closes, to record extensive system information (NB: on Windows the program isdxdiag.exe
which is time-consuming and produces lengthy logs). You can write to the log file yourself withself.logger.Log()
reportVersions (bool) – If this is
True
, theWorld
instance will call itsReportVersions()
method to report version information to the console, as soon as it is set up.**kwargs – Managed property values can also be specified as optional keyword arguments during construction, for example:
w = World( ..., clearColor=[0,0,0.5], ... )
Note: The easiest way to create a
World
is by omitting all geometry arguments. Then it will fill the display screen (the primary screen by default, but you can also specify thescreen
number explicitly). However, if you choose to use explicit geometry arguments (width
,height
,size
,left
,top
) note that they are all in “screen coordinates”. Screen coordinates usually correspond to pixels, but in some systems (Macs with Retina screens) you may need to specify some fixed smaller proportion of the number of addressable pixels you actually want: for example, on a Late-2013 Macbook with 13-inch Retina screen,w = World(1280, 800)
opens a window that actually has double that number of addressable pixels (2560 x 1600). After construction,w.size
will indicate the correct (larger) number of pixels. Unfortunately, before construction, I have not yet found a general way of predicting the relationship between screen coordinates and pixels.- classmethod AddCustomUniform(name=None, defaultValue=None, **kwargs)
Modifies the class (
World
orStimulus
) so that it possesses one or more new managed properties, whose values are then accessible from inside the fragment shader. This must be performed beforeWorld
construction.Example:
Shady.World.AddCustomUniform( 'spam', [1,2,3] ) Shady.Stimulus.AddCustomUniform( eggs=4, beans=[5,6] )
Either syntax can be used in either class. The keyword-argument syntax has the advantage of being able to define multiple new properties in one call.
The default values you supply dictate whether the new property is 1-, 2-, 3- or 4-dimensional. For a 1-dimensional property, the type of your default value also determines whether the property gets defined as an integer or floating-point variable. (2-, 3- or 4- dimensional properties are always re-cast as floating-point).
The corresponding uniform variables are then automatically made available in the fragment shader code, with the first letter of the property name getting capitalized and a ‘u’ prepended. So, as a consequence of the two lines in the example above, the modified shader would then contain these definitions:
uniform vec3 uSpam; uniform int uEggs; uniform vec2 uBeans;
…all of which is useless unless you actually write some custom shader functions that access the new variables. You might use the new variables in your own custom signal-function, modulation-function, windowing-function or color-transformation snippets.
- AddForeignStimulus(stimulus, name=None, z=0, **kwargs)
stim
is either a class (or callable factory function) or an instance of a class. That class should have adraw()
method. It is drawn on every frame with the Shady shader pipeline disabled (so, no automatic linearization or dithering, etc).The intention is to allow the use of one’s own custom OpenGL primitives in drawing unusual stimuli.
- AfterClose(func, *pargs, **kwargs)
This method registers a callable
func
(and optionally the*pargs
and**kwargs
that should be passed to it) that will be called just after theWorld
closes. The method is otherwise identical toBeforeClose()
- AnimationCallback(func=None)
Decorator version of
SetAnimationCallback()
Examples:
w = Shady.World() @w.AnimationCallback def anim( self, t ): print( t )
- BeforeClose(func, *pargs, **kwargs)
This method registers a callable
func
(and optionally the*pargs
and**kwargs
that should be passed to it) that will be called just before theWorld
closes. One way to use this method is as a decorator—for example:w = Shady.World() @w.BeforeClose def Goodbye(): print( "goodbye" )
- Returns:
(1) when
func
is called, its return value will be inserted into this list; (2) theid
of the list instance uniquely identifies the callback you have just registered, so it can be used as a handle for cancelling the function withCancelOnClose()
- Return type:
an empty
list
. This has two uses
- BoundingBox(worldCoordinates=False)
This method returns the
World
’s bounding box, in pixels.- Parameters:
worldCoordinates (bool) – If
True
, then theleft
andbottom
coordinates are computed relative to theWorld
’s ownanchor
(so that gives you the bounding box within which you can draw stimuli, in coordinates aStimulus
would understand). IfFalse
, thenleft = bottom = 0
.- Returns:
[left, bottom], [width, height]
pixel coordinates for theWorld
.
- CancelOnClose(container)
Cancels a callback that had previously been scheduled to run at closing time by either
BeforeClose()
orAfterClose()
, either of which will have returned thecontainer
that you need to pass as the input argument here.
- Capture(pil=False, fullscreen=False, saveas='', size=None, origin=None, normalize='auto')
Takes a screenshot of the World and return the RGBA image data as a
numpy
array (pil=False
) or as aPIL.Image.Image
instance (pil=True
).- Parameters:
pil (bool) – If
True
, andPIL
orpillow
is installed, anImage
object is returned. Otherwise, return anumpy
array (ifnumpy
is installed) or a buffer containing the raw pixel information (if not).fullscreen (bool) – Normally, with
fullscreen=False
, we capture just theWorld
content. But if we specifyfullscreen=True
, andPIL
orpillow
is installed, and we’re on Windows, then theImageGrab
module will be used to grab a shot of the whole screen as-is (including other windows and desktop content if theWorld
fills only part of the screen or is partly obscured).saveas (str) – If a filename is specified here, and
PIL
orpillow
is installed, then the image is automatically saved under the specified filename.size (tuple, list) – This is a sequence (tuple, list, or 1-D
numpy
array) containing 2 integers: width and height, in pixels. If unspecified (None
), the size of theWorld
(self.size
) is assumed.origin (tuple, list) – This is a sequence (tuple, list, or 1-D
numpy
array) containing 2 integers: x and y, in pixels, indicating the offset in pixels between the lower left corner of theWorld
and the lower left corner of the capture are. If unspecified (None
),[0,0]
is assumed.normalize (bool or ‘auto’) – If
False
, return raw RGBA values as integers. IfTrue
, return floating-point values normalized in the range 0 to 1, and furthermore undo the effects of the currentbitCombiningMode
if any. If'auto'
, the default isFalse
except when all the following conditions are met:numpy
is installed,pil
isFalse
, andself.bitCombiningMode
is non-zero.
- Returns:
A
PIL.Image.Image
object (withpil=True
, providedPIL
orpillow
is installed) or anumpy
array (withpil=False
) containing 8-bit RGBA pixel values.
- ClearDynamics()
Remove all property dynamics from the instance.
See also:
GetDynamic()
,GetDynamics()
,SetDynamic()
- CreatePropertyArray(propertyName, *stimuli)
This method returns a
PropertyArray
object which contains anumpy
array. Each row of the array is the storage area for the named property of one of the specified stimuli. You can still address the property of each individualStimulus
in the usual way, but now you also have the option of addressing them all at once in a single array operation, which may be much more efficient if there are many stimuli.- Parameters:
propertyName (str) – The name (or alias) of a fully-fledge
ManagedProperty
of theStimulus
class (for example,'color'
or'position'
).*stimuli – This is flexible. You can pass the (string) names of
Stimulus
instances, or you can pass the instances themselves. You can pass them as separate arguments, and/or in tuples or lists. If you’re using names, you can even pass them as a single space-delimited string if you want.
- Returns:
a
PropertyArray
instance whoseA
attribute contains thenumpy
array.
Example:
import numpy, Shady w = Shady.World() p = numpy.linspace( -1.0, +1.0, 20, endpoint=True ) stims = [ w.Stimulus( xy=w.Place( p_i, 0 ), bgalpha=0, pp=1 ) for p_i in p ] position = w.CreatePropertyArray( 'xy', stims ) color = w.CreatePropertyArray( 'color', stims ) @w.AnimationCallback def Animate( self, t ): s = Shady.Sinusoid( t, p * 180 ) position.A[ :, 1 ] = 200 * s color.A[ :, 0 ] = 0.5 + 0.5 * s color.A[ :, 1 ] = 0.5 + 0.5 * s[ ::-1 ] color.A[ :, 2 ] = s ** 2 # one call with a few simple efficient numpy array operations # instead of 20 stimuli x 4 shortcuts = 80 dynamic function calls
- Culling(enable, alphaThreshold=0.25)
Depth culling is disabled by default. This means that where two stimuli overlap, every pixel is rendered in both stimuli. Depending on your stimulus arrangement, this may be a significant waste of resources.
Turn culling on with
Culling( True )
. Instead of drawing all pixels of all stimuli in furthest-to-nearest order (the painter’s algorithm), Shady will now draw them in reverse painter’s order, nearest-to-furthest, omitting calculations that would affect already-drawn-to pixels.Depth culling is fine if all your stimuli are opaque. The disadvantage to depth culling is that it affects alpha blending and composition: when a stimulus with some transparent parts is overlapped on another stimulus, depth culling alone would cause the
clearColor
of theWorld
to be drawn where there should be transparency. A partial countermeasure to this is alpha culling, which will be turned on concurrently with the depth test unless you explicitly specify a negativealphaThreshold
. With alpha culling, any pixel in any stimulus whose alpha is equal to or less thanalphaThreshold
is simply omitted, and stimuli behind it will show through at that point even with depth culling enabled. The quality of some stimuli (e.g. antialiased text on a transparent background) will vary visibly depending on the threshold you choose, and will never be perfect. Note also that semi-transparent pixels (wherealphaThreshold < alpha < 1.0
) may be rendered with inaccurate colors: stimulus colors get alpha-blended with theclearColor
, not with the colors of the stimuli behind them.Use
Culling( False )
to disable both depth and alpha culling.
- Defer(func, *pargs, **kwargs)
Any method that actually makes GL calls, such as
NewPage()
orLoadTexture()
, must be called from the same thread/context as the one where all other GL operations happen, otherwise you may fail to see any result and/or the program may crash. This is a workaround: if you call (for example)self.Defer( func, arg1, arg2, ... )
thenfunc(arg1, arg2, ...)
will be called at the end of the next frame.This function is already used, under-the-hood, by the
@DeferredCall
method decorator, to make methods likeWorld.Stimulus
orStimulus.NewPage
safe. So there may be relatively few cases in which you need to use it directly.- Parameters:
func – this is the callable object to be called at the end of the next frame. Optionally, you may influence the order in which these pending tasks are performed by supplying a tuple
(priority, func)
instead of justfunc
. The numeric valuepriority
defaults to0
. The higher its value, the earlier the task will be performed, relative to other pending tasks.*pargs and **kwargs – any additional positional arguments, and any keyword arguments, are simply passed through to
func
when it is called.
- Returns:
An empty list. When
func
is finally called, its output will be inserted into this list. Iffunc
causes an exception to be raised, the stack trace information will be wrapped in aDeferredException
instance and returned in the list. The list also serves as a handle by which you canUndefer()
a deferred task.
- EventHandler(slot=0)
Decorator version of
SetEventHandler()
Examples:
w = Shady.World() @w.EventHandler # overwrites default slot=0 def handler( self, event ): print( 'handler got %s event' % event.type ) @w.EventHandler( slot=1 ) # uses an explicit slot def handler2( self, event ): print( 'handler2 got %s event' % event.type )
- GetDynamic(name)
For dynamic properties, return the actual callable object that generates property values, rather than the current static value.
- Parameters:
name (str) – Name of the property
- Returns:
Callable object responsible for generating values for the named property (or
None
if there is no such dynamic).
See also:
GetDynamics()
,SetDynamic()
,ClearDynamics()
- GetDynamics()
Get an ordered list of (name, callable) tuples detailing all the dynamics of this instance.
See also:
GetDynamic()
,SetDynamic()
,ClearDynamics()
- HandleEvent(event)
This method is called every time an event happens. Its argument
event
is a standardized instance of classEvent
, containing details of what happened. The default (superclass) implementation responds whenevent.type
is'key_release'
and the released key is either the Q key or the escape key - this causes the window to close (and hence the drawing thread will terminate, if thisWorld
is threaded).You can overshadow this method in your
World
subclass, or you can replace it on an instance-by-instance basis using the methodSetEventHandler()
or the decoratorEventHandler()
- for example:def handler( self, event ): print( event ) w.SetEventHandler( handler )
Note that, for each event, it is possible to have more than one handler, occupying different “slots” in the cascade that is applied to each event. By default, the
HandleEvent
method occupies slot 0.
- Inherit(other)
Set the values of all managed properties of this instance to match those of another instance. Only properties common to both objects will be considered. Dynamic property values will be copied as dynamic properties.
- Parameters:
other – instance whose property values will be copied to the properties of
self
- Returns:
self
- LinkPropertiesWithMaster(master, *pargs, **kwargs)
-
- Returns:
self
- LookupTable(*pargs, **kwargs)
Creates a
LookupTable
instance usingLookupTable( world=self, ... )
- MakeCanvas(**kwargs)
Create a
canvas
stimulus that covers theWorld
and thereby allows theWorld
’sbackgroundColor
,gamma
, ‘.ditheringDenominator` and other “atmosphere” parameters to be put into effect.This is called automatically if you say
canvas=True
in yourWorld
constructor call.
- MakePropertiesIndependent(*pargs, **kwargs)
Undoes the effect of
ShareProperties()
. Optionally, set the values of the properties after unsharing.Example:
a.ShareProperties( b, c, d, alpha=1, beta=2, gamma=3 ) b.MakePropertiesIndependent( alpha=4 ) # Now `a` and `b` share properties `.beta` and `.gamma`, but # `b.alpha` is independent and already has the new value 4; # by contrast `a`, `c` and `d` still share all three properties. c.MakePropertiesIndependent( 'beta', 'gamma' ) # Now `c` does not share anything except `.alpha`, although the # property values themselves have not yet been changed. c.Set( beta=c, gamma=c ) # a syntactic shorthand for the same operation as in the previous # line
- Returns:
self
- Patch(**kwargs)
A convenience wrapper around the
Stimulus()
method, for creating patches of solid color (supplypp=1
for oval,pp=-1
for rectangular).
- Place(xp, yp=None, worldCoordinates=True, polar=False)
Convert 2-D normalized coordinates (relative to the instance, -1 to +1 in each dimension), into 2-D pixel coordinates, either relative to the
World
’s currentanchor
, or relative to theWorld
’s bottom left corner irrespective ofanchor
.Input coordinates may be given as one scalar argument, two scalar arguments, or one argument that is a sequence of two numbers. Depending on the
polar
argument, these will be interpreted asx, y
Cartesian coordinates (where, ify
omitted, it defaults toy=x
) ortheta, r
polar coordinates (where, ifr
is omitted, it defaults tor=1
).- Parameters:
worldCoordinates (bool) – If
True
, return pixel coordinates relative to theWorld
’s ownanchor
position. IfFalse
, return pixel coordinates relative to theWorld
’s bottom left corner irrespective of itsanchor
.polar (bool) – If
True
, input coordinates are interpreted as an angle (in degrees) and an optional radius (0 denoting the center, 1 denoting the edge).
Examples:
instance.Place( [ -1, 1 ] ) # top left corner instance.Place( -1, 1 ) # likewise, top left corner instance.Place( 90, polar=True ) # middle of top edge (radius 1 assumed) instance.Place( [ 90, 0.5 ], polar=True ) # halfway between center and top instance.Place( 90, 0.5, polar=True ) # likewise, halfway between center and top
- Prepare(**kwargs)
This method is called after the
World
is initialized and the shader programs are set up, but before the first frame is actually rendered. It is carried out in the same thread as initialization and rendering.In the
World
base class, this method does nothing. However, if you create a subclass ofWorld
, you can overshadow this method. It is then a good place to perform initialStimulus
creation and other configuration specific to your particular application. You can use any prototype you like for the method, as long as it has aself
argument.When you first construct the
World
, any keyword arguments that are not recognized by the constructor will be automatically passed through toPrepare()
.
- classmethod Properties(includeShortcuts=False)
Return a list of all managed properties of this class. (Class method)
- Parameters:
includeShortcuts – Determines whether
ManagedShortcut
instances should be included (True
) or not (False
; default) along withManagedProperty
instances.- Returns:
A list of
ManagedProperty
(and optionally alsoManagedShortcut
) descriptor instances.
- ReportVersions(outputType='print', importAll=False)
This method calls the global function
ReportVersions
with theWorld
instance as its first argument.
- Run()
If the
World
was created withthreaded=True
and is already rendering, then this method does nothing except sleep in the current thread until theWorld
has finished. If theWorld
was not created threaded, then this method is required to actually execute its main rendering loop. Either way, the method does not return until theWorld
closes.
- RunDeferred(func, *pargs, **kwargs)
Defer()
a function, then wait for it to run, and then return the output. NB: you’ll wait forever if theWorld
is not running…Note that you do not need to do this for most
World
methods: they have already been wrapped so that they run deferred when necessary and appropriate.
- Set(**kwargs)
Set the values of multiple managed properties in one call. An error will be raised if you try to set the value of a non-existent, or non-managed, property.
- Returns:
self
Example:
instance.Set( rotation=90, color=(0, 0, 1), contrast=0.5 )
- SetAnimationCallback(callback)
Bind the callable object
callback
as the instance’s animation callback. Each object, whether it is aWorld
or aStimulus
, may optionally have a single animation callback which is called on every frame. If thecallback
argument isNone
, any existing callback is removed.The animation callback is installed as the attribute
self.Animate
. By default, this attribute isNone
.The prototype for an animation callback can be
callback(self, t)
or justcallback(t)
(if it’s the latter then you can, alternatively, simply assign it asself.Animate = callback
).Example:
def animate( self, t ): print( t ) my_world = Shady.World().SetAnimationCallback( animate )
There is also a decorator version of the same operation, simply called
AnimationCallback()
:stim = my_world.Stimulus() @stim.AnimationCallback def Animate( self, t ): print( t )
- SetBitCombiningMode(mode, verticalGrouping='iso')
This method supports high-dynamic-range rendering on specialized vision-science hardware—see documentation for the
bitCombiningMode
property for full details. Callingw.SetBitCombiningMode(mode)
is the same as simply assigningw.bitCombiningMode = mode
. The only difference is that, whenmode=2
(sacrificing horizontal resolution to achieve 16-bit-per- channel full-color rendering), the method allows you to specify separately whether vertical resolution should also be sacrificed. Shady’s default behavior is to throw away vertical resolution at the same time, so that logical pixels remain physically square, as follows:w.SetBitCombiningMode( mode=2, verticalGrouping=2 )
However you can override this, changing the aspect ratio of your pixels and retaining full vertical resolution, as follows:
w.SetBitCombiningMode( mode=2, verticalGrouping=1 )
- classmethod SetDefault(**kwargs)
Affects the class. Sets the default values of named properties. In instances of the class created subsequently, managed properties will have the new default values.
Example:
cls.SetDefault( color=(1,0,0), rotation=90 )
- SetDynamic(name, func, order=-1, canonicalized=False)
Associate a “dynamic” (i.e. a function that can be called repeatedly to set an attribute) with the name of an attribute.
For example:
foo.Set( 'bar', lambda t: t ** 2 )
This will set
foo.bar
tot ** 2
every time the methodfoo._RunDynamics( t )
is called (this call will happen automatically from the API user’s point of view, in the object’s infrastructure implementation).A dynamic can be attached to any attribute name. If the
bar
attribute happens to be aManagedProperty
orManagedShortcut
, then it will also automatically support “dynamic value assignment”, i.e. you can do:foo.bar = lambda t: t ** 2
as a syntactic shorthand for
SetDynamic()
—the setter will detect the fact that the value is callable, and divert it to the register of dynamics rather than assigning it directly (so the actual static value you get from queryingfoo.bar
will not immediately change).- Parameters:
name (str) – name of the attribute
func – callable object, or
None
to remove any dynamic that may already be associated withname
order (int, float) – optional numeric ordering key that allows you to control the serial order in which dynamics are evaluated
canonicalized (bool) – for internal use only.
ManagedProperty
andManagedShortcut
descriptors can have multiple aliases. The default settings,canonicalized=False
says thatname
hsa not necessarily been translated to the descriptor’s canonical name, so this should be attempted
- Returns:
self
See also:
GetDynamic()
,GetDynamics()
,ClearDynamics()
- SetEventHandler(handler, slot=0)
Bind the callable
handler
as part of the instance’s cascade of event handlers. Theslot
argument determines the serial order in which handlers are run on each event (negative numbers before positive). Ifhandler
isNone
, any handler currently occupying the specified slot is removed.By default, the class’s
HandleEvent()
method is registered in slot 0.The prototype for an event handler can be
handler(self, event)
or justhandler(event)
. If the handler returns anything that evaluates toTrue
in the boolean sense, that’s the signal to abort the cascade of handlers for the event in question (i.e. skip the handlers in higher-numbered slots, this time around).Example:
def handler( self, event ): print( event ) w = Shady.World().SetEventHandler( handler, slot=-1 )
There is also a decorator version of the same operation, simply called
EventHandler()
:w = Shady.World() @w.EventHandler( slot=-1 ) def handler( self, event ): print( event )
- SetLUT(value)
Sets or unsets a
LookupTable
for aWorld
orStimulus
. (ForWorld`s, this will only be effective to the extent that the `World
’satmosphere
properties are shared withStimulus
instances—for example, the canvas.)Calling this method is the functional equivalent of setting the
lut
property:stim.SetLUT( value ) # These are equivalent stim.lut = value #
Setting a look-up table disables automatic linearization via
gamma
and automatic dynamic-range enhancement viaditheringDenominator
, and allows you to take direct control of these issues (although only for one dimension of luminance per pixel: using a look-up table is a form of indexed-color rendering).See the
Shady.Documentation.PreciseControlOfLuminance
docstring or Gamma Correction, Dynamic Range Enhancement, and the Canvas for more details.- Parameters:
value (None, str, list, numpy.ndarray, LookupTable) – A pre-existing
LookupTable
instance may be used here. Alternatively, any valid constructor argument for aLookupTable
may be used, and the instance will be constructed implicitly. That means you can use:a
numpy.ndarray
of integers inn
-by-3 orm
-by-n
-by-3 arrangement, ora list of lists that can be implicitly converted into such an array by
numpy
, orthe filename of a
npy
ornpz
file that contains such an array (under the variable namelut
in the latter case) to be loaded byShady.Linearization.LoadLUT()
, orthe filename of a
png
file containing the look-up table entries as RGB pixel values in column-first order, again to be loaded byShady.Linearization.LoadLUT()
.
Finally you have the option of setting
None
, to disable the usage of look-up tables.- Returns:
A
LookupTable
instance.
- SetSwapInterval(value)
By default, Shady attempts to update the screen on every physical frame the display hardware can produce. This corresponds to a “swap interval” of 1 and on a typical modern LCD display this usually means 60 frames per second. If you set the swap interval to 2, updates will happen on every second frame (hence typically 30 fps) allowing you more time to perform computations between frames.
To synchronize frames with the hardware at all, Shady relies on the “vertical synch” option which may have to be enabled explicitly in the control panel of your graphics card driver. Without synchronization, you may observe “tearing” artifacts.
The ability to change the swap interval is hit-and-miss, and back-end- and platform-dependent. This call may have no effect.
Share the underlying array storage of the named managed properties with other objects, so that a change to one affects all. Optionally, set the values at the same time. Calling syntax is flexible - the following examples all take certain property arrays associated with instance
a
and share them with instancesb
,c
andd
:a.ShareProperties( 'gamma noiseAmplitude backgroundColor', b, c, d ) a.ShareProperties( ['gamma', 'noiseAmplitude', 'backgroundColor'], [b, c], d ) a.ShareProperties( b, c, d, gamma=-1, noiseAmplitude=0.01, backgroundColor=0.5 ) # sets values at the same time
A similar effect can be obtained via
b.LinkPropertiesWithMaster( a, ... )
—although there you are limited to one sharee at a time—and a syntactic shorthand for this is to pretend you are assigning the master object instance itself to the target property:b.gamma = a
Undo with
MakePropertiesIndependent()
(orb.gamma = b
)- Returns:
self
- Sine(**kwargs)
A convenience wrapper around the
Stimulus()
method, for creating a functionally-generated sine-wave patch, with the linearization and dynamic-range enhancement parameters (“atmosphere” parameters) yoked to those of theWorld
by default.
- Tick()
Wait until after the next frame has been rendered. (Will have no effect, and return immediately, if your are calling this from the same thread in which your
World
runs.)
- Undefer(target_container)
Cancels a pending task that has been scheduled by
Defer() `to run at the end of the next frame. Its input argument is the output argument of `Defer()
.
- Wait()
Wait until after the next frame has been rendered. (Will have no effect, and return immediately, if your are calling this from the same thread in which your
World
runs.)
- WaitFor(condition)
This function blocks the current thread until a specified
condition
becomesTrue
. Thecondition
will be checked repeatedly in between 1-millisecond sleeps. It can be one of two things:a callable (function) which returns
True
to signal that the wait is over - e.g.:stim.WaitFor( lambda: stim.y < 0 )
a string that names a dynamic attribute belonging to the current instance. In this case, the wait ends when there is no longer a dynamic attached the the property or shortcut in question. A dynamic may be removed due to explicit action of another thread in your program, or explicit action in this instance’s
AnimationCallback
(or indeed any instance’sAnimationCallback
). Alternatively, a dynamic may automatically remove itself, by raising aStopIteration
exception (theFunction
object returned byShady.Dynamics.Transition
is an example of something that does this):stim.scaling = Shady.Transition( stim.scaling, 2, duration=5 ) # the stimulus will now double in size over the course of 5 sec stim.WaitFor( 'scaling' ) # wait until it's finished
All of this assumes that you are operating in a different thread from the
World
—if you callWaitFor
from inside one of theWorld
orStimulus
callbacks, then it will simply sleep indefinitely because nothing will get the chance to change.
- anchor
This is a managed property. It is a pair of numbers specifying where, in normalized coordinates within the rendering area of the window, pixel coordinate (0,0) should be considered to be for Stimulus positioning. An origin of [-1,-1] means the bottom left corner; [0,0] means the center; [+1,+1] means the top right corner. Translations resulting from a change in
anchor
are automatically rounded down to an integer number of pixels, to avoidanchor
becoming an unexpected source of interpolation artifacts.
- property atmosphere
This property actually encompasses multiple managed properties, all related to linearization and dynamic-range enhancement.
If you query this property, you will get a
dict
of the relevant property names and values. You can also assign such a dictionary to it.More usefully, you can use it to link all the properties between instances in one go:
stim.atmosphere = world # hard-links all the "atmosphere" properties # at once
For more information, see the
Shady.Documentation.PreciseControlOfLuminance
docstring or click here.
- ax_n
This is a managed shortcut. It is a shortcut for
anchor
[0]
- ay_n
This is a managed shortcut. It is a shortcut for
anchor
[1]
- backgroundColor
This is a managed property. It is a triplet of numbers, each in the range 0 to 1, corresponding to red, green and blue channels. It specifies the
backgroundColor
of the background canvas Stimulus, if present (theWorld
needs to be constructed with thecanvas=True
, or you otherwise need to callMakeCanvas()
). When a canvas is created, this property of theWorld
is automatically linked to the corresponding property of the canvasStimulus
instance; if there is no canvas then this property is unused, although you may wish to link it explicitly to other stimuli withShareProperties()
orLinkPropertiesWithMaster()
.Default value:
[0.5, 0.5, 0.5]
Canonical name:
backgroundColor
- Subscripting shortcuts:
bgred
is a shortcut forbackgroundColor
[0]
bggreen
is a shortcut forbackgroundColor
[1]
bgblue
is a shortcut forbackgroundColor
[2]
- bg
bg
is an alias forbackgroundColor
- bgblue
This is a managed shortcut. It is a shortcut for
backgroundColor
[2]
- bgcolor
bgcolor
is an alias forbackgroundColor
- bggreen
This is a managed shortcut. It is a shortcut for
backgroundColor
[1]
- bgred
This is a managed shortcut. It is a shortcut for
backgroundColor
[0]
- property bitCombiningMode
This non-managed property allows high-dynamic-range rendering on specialized vision-science hardware. It can be set to:
- 0, or equivalently
'C24'
: denotes standard 24-bit full-color mode (8 bits per channel, with dithering by default).
- 1, or equivalently
'M16
’ or'monoPlusPlus'
: denotes 16-bit monochrome reinterpretation of frame-buffer contents (each pixel’s red channel is the more-significant byte, and its green channel is the less-signficiant byte, of a 16 bit value). As with look-up tables, Shady reads just the red channel to determine the monochrome target value. Dithering is disabled.
- 2, or equivalently
'C48'
or'colorPlusPlus'
: denotes 48-bit color mode in which horizontal resolution is sacrificed. Dithering is disabled. Each pixel in the frame buffer is paired with its horizontal neighbor, and together they specify a 16-bit-per-channel value for the corresponding yoked pair of physical pixels. Shady also throws away vertical resolution at the same time, so that you can continue working with square pixels and sane geometry—if you do not want this, then the
SetBitCombiningMode()
method allows more control.
Values 3 and 4 are also reserved for debugging C48 mode (they will not generate correct C48 stimuli).
- 0, or equivalently
- blue
This is a managed shortcut. It is a shortcut for
clearColor
[2]
- bluegamma
This is a managed shortcut. It is a shortcut for
gamma
[2]
- bluenoise
This is a managed shortcut. It is a shortcut for
noiseAmplitude
[2]
- clearColor
This is a managed property. It is a triplet of numbers in the range 0 to 1. It specifies the color of the empty screen. Note that these values are never linearized or dithered. For more precise control over the background, construct your
World
with the argumentcanvas=True
and then you can manipulatebackgroundColor
,gamma
, ‘.ditheringDenominator’ andnoiseAmplitude
.Default value: varies according to
BackEnd()
settings- Subscripting shortcuts:
red
is a shortcut forclearColor
[0]
green
is a shortcut forclearColor
[1]
blue
is a shortcut forclearColor
[2]
- dd
dd
is an alias forditheringDenominator
- ditheringDenominator
This is a managed property. It is a floating-point number. It should be 0 or negative to disable dithering, or otherwise equal to the maximum DAC value (255 for most video cards). It specifies the
ditheringDenominator
for the background canvas Stimulus, if present (theWorld
needs to be constructed with thecanvas=True
, or you otherwise need to callMakeCanvas()
). When a canvas is created, this property of theWorld
is automatically linked to the corresponding property of the canvasStimulus
instance; if there is no canvas then this property is unused, although you may wish to link it explicitly to other stimuli withShareProperties()
orLinkPropertiesWithMaster()
.Default value: dithering enabled (value determined automatically)
Canonical name:
ditheringDenominator
Other aliases:
dd
- property fakeFrameRate
By default, with
fakeFrameRate
equal toNone
, aWorld
will try to update itself at the frame rate of the display hardware (though of couse it may end up being slower if you are doing too much computation between frames, or if there are other tasks that are using too many CPU or GPU resources). The time argumentt
that gets passed into animation callbacks and dynamic property evaluations will reflect the real wall-time at which each frame is drawn.However, if you set
fakeFrameRate
to a positive value, now frames can take as long as they like in real time, and thet
argument will reflect the theoretical amount of time passed based on the number of frames completed, assuming the specified frame rate. This allows you to run animations in slower-than-real time. One of the main applications would be for capturing stills or movies ofWorld
animation (the capture operation itself tends to be slow).If you do not fully understand the explanation above, do not change this property. It should be left as
None
whenever you want to display time-accurate animation (which should be the case under nearly all circumstances).
- gamma
This is a managed property. It is a triplet of numbers, each in the range 0 to 1, corresponding to red, green and blue channels. It specifies the
gamma
of the background canvas Stimulus, if present (theWorld
needs to be constructed with thecanvas=True
, or you otherwise need to callMakeCanvas()
). When a canvas is created, this property of theWorld
is automatically linked to the corresponding property of the canvasStimulus
instance; if there is no canvas then this property is unused, although you may wish to link it explicitly to other stimuli withShareProperties()
orLinkPropertiesWithMaster()
.gamma = 1
is linear;gamma = -1
gives you the sRGB gamma profile (a piecewise function visually very similar togamma = 2.2
)
- green
This is a managed shortcut. It is a shortcut for
clearColor
[1]
- greengamma
This is a managed shortcut. It is a shortcut for
gamma
[1]
- greennoise
This is a managed shortcut. It is a shortcut for
noiseAmplitude
[1]
- height
This is a managed shortcut. It is a shortcut for
size
[1]
- property lut
The value of this property will either be
None
, or an instance ofLookupTable
. Assigning to this property is equivalent to calling theSetLUT()
method—so you can assign any of the valid argument types accepted by that function. AssigningNone
disables look-up.
- noise
noise
is an alias fornoiseAmplitude
- noiseAmplitude
This is a managed property. It is a triplet of floating-point numbers corresponding to red, green and blue channels. It specifies the
noiseAmplitude
for the background canvas Stimulus, if present (theWorld
needs to be constructed with thecanvas=True
, or you otherwise need to callMakeCanvas()
). When a canvas is created, this property of theWorld
is automatically linked to the corresponding property of the canvasStimulus
instance; if there is no canvas then this property is unused, although you may wish to link it explicitly to other stimuli withShareProperties()
orLinkPropertiesWithMaster()
.Default value:
[0.0, 0.0, 0.0]
Canonical name:
noiseAmplitude
Other aliases:
noise
- Subscripting shortcuts:
rednoise
is a shortcut fornoiseAmplitude
[0]
greennoise
is a shortcut fornoiseAmplitude
[1]
bluenoise
is a shortcut fornoiseAmplitude
[2]
- outOfRangeAlpha
This is a managed property. It is a number in the range 0 to 1. It specifies the
outOfRangeAlpha
for the background canvas Stimulus, if present (theWorld
needs to be constructed with thecanvas=True
, or you otherwise need to callMakeCanvas()
). When a canvas is created, this property of theWorld
is automatically linked to the corresponding property of the canvasStimulus
instance; if there is no canvas then this property is unused, although you may wish to link it explicitly to other stimuli withShareProperties()
orLinkPropertiesWithMaster()
.Default value:
1.0
- outOfRangeColor
This is a managed property. It is a triplet of numbers, each in the range 0 to 1, corresponding to red, green and blue channels. It specifies the
outOfRangeColor
for the background canvas Stimulus, if present (theWorld
needs to be constructed with thecanvas=True
, or you otherwise need to callMakeCanvas()
). When a canvas is created, this property of theWorld
is automatically linked to the corresponding property of the canvasStimulus
instance; if there is no canvas then this property is unused, although you may wish to link it explicitly to other stimuli withShareProperties()
orLinkPropertiesWithMaster()
.Default value:
[1.0, 0.0, 1.0]
- pixelGrouping
Developer note on pixelGrouping: Explicit rounding, in the shader, to the nearest screen pixel location, is disabled by default. However you can see the tiny rounding errors this creates if you create, for example, a signal function that hits exactly 0 at multiple places on top of a background value of 0.5, such as:
Shady.AddCustomSignalFunction(''' float Tartan(vec2 p) { p = mod(p, 2.0); return 0.25 * (p.x - p.y); } ''') w=Shady.World(fullScreenMode=0,bitCombiningMode=1);s=w.Stimulus(sigfunc=Shady.SIGFUNC.Tartan)
Compare this under
w.pixelGrouping = 0
withw.pixelGrouping = 1
but be aware that (a) the differences are tiny, rounding to values 1/65535th apart and only visible because of the red-green split, (b) pixel rounding is not computationally trivial on the GPU - it requires a per-fragment matrix multiplication.You can change the default with
Shady.World.SetDefault( pixelGrouping=1 )
- then this setting will be respected automatically whenever you change tow.bitCombiningMode=0
orw.bitCombiningMode=1
.
- red
This is a managed shortcut. It is a shortcut for
clearColor
[0]
- redgamma
This is a managed shortcut. It is a shortcut for
gamma
[0]
- rednoise
This is a managed shortcut. It is a shortcut for
noiseAmplitude
[0]
- size
This is a managed property. It is a pair of integers denoting the width and height of the
World
in pixels. Do not attempt to change these values - it will not alter the size of the window and may have unexpected side effects.
- t
t
is an alias fortimeInSeconds
- timeInSeconds
This is a managed property. It is a floating-point scalar value indicating the time in seconds since the
World
started rendering.Default value:
0.0
Canonical name:
timeInSeconds
Other aliases:
t
- visible
This is a managed property. It is a scalar boolean value indicating whether or not the
World
should be visible or not. On Windows the transition from visible to invisible and back is reasonably instantaneous. On the Mac you may have to endure the minimize/restore animation (although this is backend-dependent).
- width
This is a managed shortcut. It is a shortcut for
size
[0]
The Stimulus
Class
- class Shady.Stimulus(world, source=None, name=None, page=None, multipage=False, debugTiming=None, **kwargs)
Bases:
LinkGL
A
Stimulus
is an entity that is drawn automatically within its parentWorld
on every frame. It has a number of properties whose values govern its appearance independent of other stimuli.- Parameters:
world (World) – The required first argument is a
World
instance. To make this more readable you can alternatively call theStimulus
constructor as aWorld
method:w = World( ... ) s = w.Stimulus( source, ... )
source (str, list, numpy.ndarray, None) – The second argument is the
source
of the carrier texture. This may be omitted (or equivalently set toNone
) if your stimulus is just a blank patch, or if its carrier signal is defined purely by a function in the shader (see thesignalFunction
property). Alternativelysource
may be a string denoting an image filename or glob pattern for image filenames, anumpy
array specifying texture data explicitly, or a list of strings and/ornumpy
arrays - seeLoadTexture()
for details.name (str) – This is a string that will identify this
Stimulus
in the containerw.stimuli
of theWorld
to which it belongs. To ensure uniqueness of the names in thisdict
, you may include a single numeric printf-style pattern in the name (the defaultname
, for example, is'stim%02d'
).page (int) – You may optionally initialize the
page
property here.multipage (bool) – If you set this to
True
, multiple image frames will loaded using theLoadPages()
method: this transfers each frame to the graphics card as a separate texture, which you switch between using thepage
property.By contrast, if you leave it at the default value
False
, multiple image frames are handled by concatenating them horizontally into a single texture, and you switch between them using theframe
property, which indirectly manipulatescarrierTranslation
.You may need to use
multipage=True
for animated images that have a large width and/or high number of frames, because the normal concatenation method may lead to the texture exceeding the maximum allowable width.**kwargs – Managed property values can also be specified as optional keyword arguments during construction—for example:
s = w.Stimulus( ..., foregroundColor=[1, 0, 0], ... )
The
width
,height
and/orsize
arguments (all shortcuts/aliases into theenvelopeSize
managed property) are worth mentioning specifically: these can be used to specify the dimensions of the envelope in pixels. For texture stimuli these can usually be omitted, since usually they will be dictated by the dimensions of the underlyingsource
material. However, they can be specified explicitly if you want to crop or repeat an image texture. Note that you should specify dimensions in the same units as the underlying texture (i.e. unscaled pixels). If you want to change the physical size of the rendered stimulus by magnifying or shrinking the texture, manipulate theenvelopeScaling
property either directly, or indirectly viascaledSize
(but remember this will produce interpolation artifacts).
- classmethod AddCustomUniform(name=None, defaultValue=None, **kwargs)
Modifies the class (
World
orStimulus
) so that it possesses one or more new managed properties, whose values are then accessible from inside the fragment shader. This must be performed beforeWorld
construction.Example:
Shady.World.AddCustomUniform( 'spam', [1,2,3] ) Shady.Stimulus.AddCustomUniform( eggs=4, beans=[5,6] )
Either syntax can be used in either class. The keyword-argument syntax has the advantage of being able to define multiple new properties in one call.
The default values you supply dictate whether the new property is 1-, 2-, 3- or 4-dimensional. For a 1-dimensional property, the type of your default value also determines whether the property gets defined as an integer or floating-point variable. (2-, 3- or 4- dimensional properties are always re-cast as floating-point).
The corresponding uniform variables are then automatically made available in the fragment shader code, with the first letter of the property name getting capitalized and a ‘u’ prepended. So, as a consequence of the two lines in the example above, the modified shader would then contain these definitions:
uniform vec3 uSpam; uniform int uEggs; uniform vec2 uBeans;
…all of which is useless unless you actually write some custom shader functions that access the new variables. You might use the new variables in your own custom signal-function, modulation-function, windowing-function or color-transformation snippets.
- AnimationCallback(func=None)
Decorator version of
SetAnimationCallback()
Examples:
w = Shady.World() @w.AnimationCallback def anim( self, t ): print( t )
- BoundingBox(worldCoordinates=False)
This method returns the bounding box of the
Stimulus
, in pixels.- Parameters:
worldCoordinates (bool) – If
True
, then theleft
andbottom
coordinates are computed relative to theWorld
’sanchor
. IfFalse
, then[0,0]
is considered to be the bottom-left corner of theWorld
, regardless of itsanchor
.- Returns:
[left, bottom], [width, height]
pixel coordinates for theStimulus
.
- Known Issues:
The method takes account of scaling (due to
envelopeScaling
) and translation (due toenvelopeOrigin
,envelopeTranslation
,Stimulus.anchor
andWorld.anchor
). But it does not take account ofenvelopeRotation
- Capture(pil=False, saveas='', normalize='auto')
This captures the pixel data from a particular
Stimulus
. Note that it accomplishes this simply by callingWorld.Capture()
with the appropriate bounding box. Therefore, two caveats: (1) if other stimuli overlap this one, the capture will contain image data composited from all of them; (2) the bounding- box method is smart enough to compensate forenvelopeTranslation
andenvelopeScaling
, but notenvelopeRotation
.- Parameters:
pil (bool) – If
True
, and ifPIL
orpillow
is installed, return the image data as aPIL.Image.Image
instance. IfFalse
, return the data as anumpy
array.saveas (str) – If
PIL
orpillow
is installed, you can use this argument to specify an optional filename for immediately saving the image data.normalize (bool or ‘auto’) – If
False
, return raw RGBA values as integers. IfTrue
, return floating-point values normalized in the range 0 to 1, and furthermore undo the effects of the currentbitCombiningMode
if any. If'auto'
, the default isFalse
except when all the following conditions are met:numpy
is installed,pil
isFalse
, andself.bitCombiningMode
is non-zero.
- Returns:
Either a
numpy.ndarray
or aPIL.Image.Image
instance, depending on thepil
argument.
- ClearDynamics()
Remove all property dynamics from the instance.
See also:
GetDynamic()
,GetDynamics()
,SetDynamic()
- Enter(**props)
If a
Stimulus
instance has previously left the stage withLeave()
, theEnter()
method allows it to come back.You may simultaneously change its properties, using keyword arguments.
- GetDynamic(name)
For dynamic properties, return the actual callable object that generates property values, rather than the current static value.
- Parameters:
name (str) – Name of the property
- Returns:
Callable object responsible for generating values for the named property (or
None
if there is no such dynamic).
See also:
GetDynamics()
,SetDynamic()
,ClearDynamics()
- GetDynamics()
Get an ordered list of (name, callable) tuples detailing all the dynamics of this instance.
See also:
GetDynamic()
,SetDynamic()
,ClearDynamics()
- Inherit(other)
Set the values of all managed properties of this instance to match those of another instance. Only properties common to both objects will be considered. Dynamic property values will be copied as dynamic properties.
- Parameters:
other – instance whose property values will be copied to the properties of
self
- Returns:
self
- Leave(deferAfterAdditionalFrames=0)
If a
Stimulus
instancestim
is made invisible withstim.visible=False
, it is not rendered on screen. However, it is still a member of thestimuli
dictionary of theWorld
to which it belongs, and itsAnimationCallback
(if any), and any dynamics attached to its individual properties, are still evaluated on every frame.On the other hand, you tell a
Stimulus
instance toLeave()
the stage entirely, it is removed from thestimuli
dictionary of itsWorld
, it is not rendered (regardless of itsvisible
setting), and none of its callbacks and dynamics are called—not until you tell it toEnter()
again.- Returns:
the
Stimulus
instance itself.
- LinkPropertiesWithMaster(master, *pargs, **kwargs)
-
- Returns:
self
- LinkTextureWithMaster(master)
This is a wrapper around
LinkPropertiesWithMaster()
that allowsStimulus
instances to share a texture—it shares thetextureID
,textureSlotNumber
anduseTexture
managed properties.
- LoadPages(sources, keys=0, updateEnvelopeSize=True, page=0, **kwargs)
This method prepares a
Stimulus
instance for animation using thepage
mechanism (rather than the defaultframe
mechanism). It loads multiple textures in multiple pages, indexed by the specifiedkeys
(or by integers starting atkeys
, ifkeys
is an integer). Subsequently, you can switch between pages by setting thepage
property or equivalently calling theSwitchTo()
method.This method is called when constructing a
Stimulus
instance with themultipage
constructor option. It can also be called explicitly, which is especially useful if you want to re-use texture buffers that have already been allocated on the graphics card, for new stimulus content.
- LoadSubTexture(source, x=0, y=0)
This is similar to
LoadTexture()
in its interpretation of thesource
argument. The difference is that theStimulus
must already have an existing texture, and the new source is pasted over the old one (or over part of it, depending on the new source’s size).x
andy
are pixel coordinates relative to the existing texture’s lower-left corner. They specify the position of the lower-left corner of the incoming piece of the texture.
- LoadTexture(source, updateEnvelopeSize=True, useTexture=True)
Loads texture data from
source
and associates it with this Stimulus.- Parameters:
source – the source of the carrier texture data. This may be:
omitted or set to
None
if there is no texture (just a constant carrier signal, or one defined by a function in the shader)a string (possibly including glob characters
'*'
and/or'?'
) denoting one or more image files to be used as animation framesa
numpy
array specifying the pixel values of a texture image, in which case:source.dtype
must be one of:numpy.dtype('uint8')
: 8-bit pixel values in the range 0 to 255numpy.dtype('float32')
: pixel value in the range 0.0 to 1.0numpy.dtype('float64')
: pixel value in the range 0.0 to 1.0 (will be converted to float32 automatically)
source.shape
must be one of:[height, width]
: LUMINANCE image[height, width, 1]
: LUMINANCE image[height, width, 2]
: LUMINANCE_ALPHA image[height, width, 3]
: RGB image[height, width, 4]
: RGBA image
a
list
ortuple
containing filenames and/ornumpy
arrays as above, to be used as multiple frames
updateEnvelopeSize (bool) – whether or not to update the envelope size to match the dimensions of the new texture
useTexture (bool) – new value for the
useTexture
property attribute that enables or disables the use of this texture
- MakePropertiesIndependent(*pargs, **kwargs)
Undoes the effect of
ShareProperties()
. Optionally, set the values of the properties after unsharing.Example:
a.ShareProperties( b, c, d, alpha=1, beta=2, gamma=3 ) b.MakePropertiesIndependent( alpha=4 ) # Now `a` and `b` share properties `.beta` and `.gamma`, but # `b.alpha` is independent and already has the new value 4; # by contrast `a`, `c` and `d` still share all three properties. c.MakePropertiesIndependent( 'beta', 'gamma' ) # Now `c` does not share anything except `.alpha`, although the # property values themselves have not yet been changed. c.Set( beta=c, gamma=c ) # a syntactic shorthand for the same operation as in the previous # line
- Returns:
self
- NewPage(source, key=None, updateEnvelopeSize=True, **kwargs)
Create a new page from the specified
source
. A page is a bundle of properties that determine texture, envelope size, and (viadrawMode
andpoints
) envelope shape.Note that this can be automated, to load multiple sources as multiple pages, either by specifying
multipage=True
when you construct theStimulus
instance, or by explicitly callingLoadPages()
.- Parameters:
source – Any valid input to
LoadTexture()
, includingNone
.key – By default, a new page is unlabelled, but if you specify a
key
here,SavePage( key )
will be called automatically to store and label the new texture settings. This will enable you toSwitchTo()
this page in future.**kwargs – Additional keyword arguments can be used to set property values at the same time, if you want. (NB: you can set any property at all this way, but remember that not all properties get paged in and out—apart from the ones whose values get inferred from
source
automatically, the others that are most meaningful here aredrawMode
andpoints
)
See also:
page
,SavePage()
,SwitchTo()
andLoadPages()
- Place(xp, yp=None, worldCoordinates=True, polar=False)
Convert 2-D normalized coordinates (relative to the instance, -1 to +1 in each dimension), into 2-D pixel coordinates, either relative to the
World
’s currentanchor
, or relative to theWorld
’s bottom left corner irrespective ofanchor
.Input coordinates may be given as one scalar argument, two scalar arguments, or one argument that is a sequence of two numbers. Depending on the
polar
argument, these will be interpreted asx, y
Cartesian coordinates (where, ify
omitted, it defaults toy=x
) ortheta, r
polar coordinates (where, ifr
is omitted, it defaults tor=1
).- Parameters:
worldCoordinates (bool) – If
True
, return pixel coordinates relative to theWorld
’s ownanchor
position. IfFalse
, return pixel coordinates relative to theWorld
’s bottom left corner irrespective of itsanchor
.polar (bool) – If
True
, input coordinates are interpreted as an angle (in degrees) and an optional radius (0 denoting the center, 1 denoting the edge).
Examples:
instance.Place( [ -1, 1 ] ) # top left corner instance.Place( -1, 1 ) # likewise, top left corner instance.Place( 90, polar=True ) # middle of top edge (radius 1 assumed) instance.Place( [ 90, 0.5 ], polar=True ) # halfway between center and top instance.Place( 90, 0.5, polar=True ) # likewise, halfway between center and top
- classmethod Properties(includeShortcuts=False)
Return a list of all managed properties of this class. (Class method)
- Parameters:
includeShortcuts – Determines whether
ManagedShortcut
instances should be included (True
) or not (False
; default) along withManagedProperty
instances.- Returns:
A list of
ManagedProperty
(and optionally alsoManagedShortcut
) descriptor instances.
- ResetClock(other=None)
A
Stimulus
may have callback functions that are called on every frame—for example, a function that you have registered as itsAnimationCallback
, or functions that you assign to its managed properties (dynamic value assignment). In all cases, the argument that is passed to these callbacks on each frame ist
, time in seconds. By default, thist
is the same as theWorld
’st
, i.e. the number of seconds have elapsed since theWorld
began rendering. However, if you wish, you can alter thet0
from which eachStimulus
instance’s clock counts:stim.ResetClock() # resets the clock to 0 stim.ResetClock( otherStim ) # synchronizes with `otherStim`
- SavePage(key)
Save the current “page” (a bundle of properties determining texture, envelope size and envelope shape) in the dictionary
self.pages
under the specifiedkey
.See also:
page
,NewPage()
, andSwitchTo()
- Set(**kwargs)
Set the values of multiple managed properties in one call. An error will be raised if you try to set the value of a non-existent, or non-managed, property.
- Returns:
self
Example:
instance.Set( rotation=90, color=(0, 0, 1), contrast=0.5 )
- SetAnimationCallback(callback)
Bind the callable object
callback
as the instance’s animation callback. Each object, whether it is aWorld
or aStimulus
, may optionally have a single animation callback which is called on every frame. If thecallback
argument isNone
, any existing callback is removed.The animation callback is installed as the attribute
self.Animate
. By default, this attribute isNone
.The prototype for an animation callback can be
callback(self, t)
or justcallback(t)
(if it’s the latter then you can, alternatively, simply assign it asself.Animate = callback
).Example:
def animate( self, t ): print( t ) my_world = Shady.World().SetAnimationCallback( animate )
There is also a decorator version of the same operation, simply called
AnimationCallback()
:stim = my_world.Stimulus() @stim.AnimationCallback def Animate( self, t ): print( t )
- classmethod SetDefault(**kwargs)
Affects the class. Sets the default values of named properties. In instances of the class created subsequently, managed properties will have the new default values.
Example:
cls.SetDefault( color=(1,0,0), rotation=90 )
- SetDynamic(name, func, order=-1, canonicalized=False)
Associate a “dynamic” (i.e. a function that can be called repeatedly to set an attribute) with the name of an attribute.
For example:
foo.Set( 'bar', lambda t: t ** 2 )
This will set
foo.bar
tot ** 2
every time the methodfoo._RunDynamics( t )
is called (this call will happen automatically from the API user’s point of view, in the object’s infrastructure implementation).A dynamic can be attached to any attribute name. If the
bar
attribute happens to be aManagedProperty
orManagedShortcut
, then it will also automatically support “dynamic value assignment”, i.e. you can do:foo.bar = lambda t: t ** 2
as a syntactic shorthand for
SetDynamic()
—the setter will detect the fact that the value is callable, and divert it to the register of dynamics rather than assigning it directly (so the actual static value you get from queryingfoo.bar
will not immediately change).- Parameters:
name (str) – name of the attribute
func – callable object, or
None
to remove any dynamic that may already be associated withname
order (int, float) – optional numeric ordering key that allows you to control the serial order in which dynamics are evaluated
canonicalized (bool) – for internal use only.
ManagedProperty
andManagedShortcut
descriptors can have multiple aliases. The default settings,canonicalized=False
says thatname
hsa not necessarily been translated to the descriptor’s canonical name, so this should be attempted
- Returns:
self
See also:
GetDynamic()
,GetDynamics()
,ClearDynamics()
- SetLUT(value)
Sets or unsets a
LookupTable
for aWorld
orStimulus
. (ForWorld`s, this will only be effective to the extent that the `World
’satmosphere
properties are shared withStimulus
instances—for example, the canvas.)Calling this method is the functional equivalent of setting the
lut
property:stim.SetLUT( value ) # These are equivalent stim.lut = value #
Setting a look-up table disables automatic linearization via
gamma
and automatic dynamic-range enhancement viaditheringDenominator
, and allows you to take direct control of these issues (although only for one dimension of luminance per pixel: using a look-up table is a form of indexed-color rendering).See the
Shady.Documentation.PreciseControlOfLuminance
docstring or Gamma Correction, Dynamic Range Enhancement, and the Canvas for more details.- Parameters:
value (None, str, list, numpy.ndarray, LookupTable) – A pre-existing
LookupTable
instance may be used here. Alternatively, any valid constructor argument for aLookupTable
may be used, and the instance will be constructed implicitly. That means you can use:a
numpy.ndarray
of integers inn
-by-3 orm
-by-n
-by-3 arrangement, ora list of lists that can be implicitly converted into such an array by
numpy
, orthe filename of a
npy
ornpz
file that contains such an array (under the variable namelut
in the latter case) to be loaded byShady.Linearization.LoadLUT()
, orthe filename of a
png
file containing the look-up table entries as RGB pixel values in column-first order, again to be loaded byShady.Linearization.LoadLUT()
.
Finally you have the option of setting
None
, to disable the usage of look-up tables.- Returns:
A
LookupTable
instance.
Share the underlying array storage of the named managed properties with other objects, so that a change to one affects all. Optionally, set the values at the same time. Calling syntax is flexible - the following examples all take certain property arrays associated with instance
a
and share them with instancesb
,c
andd
:a.ShareProperties( 'gamma noiseAmplitude backgroundColor', b, c, d ) a.ShareProperties( ['gamma', 'noiseAmplitude', 'backgroundColor'], [b, c], d ) a.ShareProperties( b, c, d, gamma=-1, noiseAmplitude=0.01, backgroundColor=0.5 ) # sets values at the same time
A similar effect can be obtained via
b.LinkPropertiesWithMaster( a, ... )
—although there you are limited to one sharee at a time—and a syntactic shorthand for this is to pretend you are assigning the master object instance itself to the target property:b.gamma = a
Undo with
MakePropertiesIndependent()
(orb.gamma = b
)- Returns:
self
This is a wrapper around
ShareProperties()
that allowsStimulus
instances to share a texture—it shares thetextureID
,textureSlotNumber
,textureSize
anduseTexture
managed properties.
- SwitchTo(key)
Switch to the “page” associated with the given
key
. A page is a bundle of properties that determine texture, envelope size and envelope shape. Thekey
argument must be one of the keys in the dictionaryself.pages
. Note that if the current settings have not been stored (viaSavePage()
, via the explicit specification of a key duringNewPage()
, or via the automated loop ofNewPage()
calls provided byLoadPages()
) then this method will cause the current settings to be lost.See also:
page
,NewPage()
,LoadPages()
andSavePage()
- WaitFor(condition)
This function blocks the current thread until a specified
condition
becomesTrue
. Thecondition
will be checked repeatedly in between 1-millisecond sleeps. It can be one of two things:a callable (function) which returns
True
to signal that the wait is over - e.g.:stim.WaitFor( lambda: stim.y < 0 )
a string that names a dynamic attribute belonging to the current instance. In this case, the wait ends when there is no longer a dynamic attached the the property or shortcut in question. A dynamic may be removed due to explicit action of another thread in your program, or explicit action in this instance’s
AnimationCallback
(or indeed any instance’sAnimationCallback
). Alternatively, a dynamic may automatically remove itself, by raising aStopIteration
exception (theFunction
object returned byShady.Dynamics.Transition
is an example of something that does this):stim.scaling = Shady.Transition( stim.scaling, 2, duration=5 ) # the stimulus will now double in size over the course of 5 sec stim.WaitFor( 'scaling' ) # wait until it's finished
All of this assumes that you are operating in a different thread from the
World
—if you callWaitFor
from inside one of theWorld
orStimulus
callbacks, then it will simply sleep indefinitely because nothing will get the chance to change.
- addb
This is a managed shortcut. It is a shortcut for
offset
[2]
- addg
This is a managed shortcut. It is a shortcut for
offset
[1]
- addr
This is a managed shortcut. It is a shortcut for
offset
[0]
- alpha
This is a managed property. It is a floating-point number from 0 to 1. It specifies the opacity of the
Stimulus
as a whole. Note that with psychophysical stimuli you should always ensurealpha
== 1, and manipulatebackgroundColor
andnormalizedContrast
instead: this is because alpha-blending is carried out by the graphics card AFTER our linearization (via thegamma
property or via a look-up table) is applied. Therefore a blended result will no longer be linearized.
- anchor
This is a managed property. It is a sequence of two floating-point numbers expressed in normalized coordinates (from -1 to +1). It denotes where, on the surface of the envelope, the anchor point will be. This anchor point is the point whose coordinates are manipulated directly by the other properties, and it also serves as the origin of any scaling and rotation of the envelope. The default value is
[0.0, 0.0]
denoting the center, whereas[-1.0, -1.0]
would be the bottom left corner.The translation caused by changes to
anchor
is always rounded down to an integer number of pixels, to avoid it becoming an unforeseen cause of interpolation artifacts.
- angle
angle
is an alias forenvelopeRotation
- property aspect
Non-managed property that affects the behavior of
scaledWidth
andscaledHeight
manipulations. The value may be aNone
, the string'fixed'
, or a floating-point number.Assigning a floating-point number to
scaledAspectRatio
will immediately reduce either the horizontal or the vertical component ofenvelopeScaling
as necessary to achieve the target aspect ratio.Once the value is set to something other than
None
, future manipulation of either thescaledWidth
property or thescaledHeight
property will cause the other property to be adjusted simultaneously, to maintain the target aspect ratio. If the value is'fixed'
, then the target value is simply “whatever it was before you made the manipulation”.This prospective control only applies to the
scaled*
properties, however—if you directly manipulateenvelopeSize
orenvelopeScaling
, thescaledAspectRatio
setting will not be automatically reasserted.
- property atmosphere
This property actually encompasses multiple managed properties, all related to linearization and dynamic-range enhancement.
If you query this property, you will get a
dict
of the relevant property names and values. You can also assign such a dictionary to it.More usefully, you can use it to link all the properties between instances in one go:
stim.atmosphere = world # hard-links all the "atmosphere" properties # at once
For more information, see the
Shady.Documentation.PreciseControlOfLuminance
docstring or click here.
- ax_n
This is a managed shortcut. It is a shortcut for
anchor
[0]
- ay_n
This is a managed shortcut. It is a shortcut for
anchor
[1]
- backgroundAlpha
This is a managed property. It is a floating-point number from 0 to 1, indicating the opacity at locations where the signal has been attenuated away completely (by windowing via
plateauProportion
, by a custommodulationFunction
, or by manipulation of overallnormalizedContrast
).For psychophysical stimuli, ensure
backgroundAlpha
is 1.0 and manipulatebackgroundColor
instead: although alpha can be used for windowing in this way, alpha-blending is applied post- linearization so the result will not be well linearized, except in very fragile special cases.Default value:
1.0
Canonical name:
backgroundAlpha
Other aliases:
bgalpha
- backgroundColor
This is a managed property. It is a triplet of numbers, each in the range 0 to 1, corresponding to red, green and blue channels. It specifies the color at locations in which the carrier signal (texture and/or foreground color and/or functionally generated carrier signal) has been attenuated away completely (by contrast scaling, windowing, or custom contrast modulation pattern).
Default value:
[0.5, 0.5, 0.5]
Canonical name:
backgroundColor
- Subscripting shortcuts:
bgred
is a shortcut forbackgroundColor
[0]
bggreen
is a shortcut forbackgroundColor
[1]
bgblue
is a shortcut forbackgroundColor
[2]
- bg
bg
is an alias forbackgroundColor
- bgalpha
bgalpha
is an alias forbackgroundAlpha
- bgblue
This is a managed shortcut. It is a shortcut for
backgroundColor
[2]
- bgcolor
bgcolor
is an alias forbackgroundColor
- bggreen
This is a managed shortcut. It is a shortcut for
backgroundColor
[1]
- bgred
This is a managed shortcut. It is a shortcut for
backgroundColor
[0]
- blue
This is a managed shortcut. It is a shortcut for
color
[2]
- bluegamma
This is a managed shortcut. It is a shortcut for
gamma
[2]
- bluenoise
This is a managed shortcut. It is a shortcut for
noiseAmplitude
[2]
- carrierRotation
This is a managed property. It is a scalar number, expressed in degrees. The carrier will be rotated counter-clockwise by this number of degrees around the center of the envelope. Note that if your rotation values is not divisible by 90, this will introduce interpolation artifacts into stimuli that use textures. (Unlike
envelopeRotation
, however, this will not compromise pure functionally-generated stimuli.)Default value:
0.0
Canonical name:
carrierRotation
Other aliases:
cr
- carrierScaling
This is a managed property. It is a sequence of two floating-point numbers denoting horizontal and vertical scaling factors. The carrier will be magnified by these factors relative to an origin the center of the envelope. Note that scaling values != 1.0 will introduce interpolation artifacts into stimuli that use textures (but unlike
envelopeScaling
, this will not compromise pure functionally-generated stimuli).Default value:
[1.0, 1.0]
Canonical name:
carrierScaling
- Subscripting shortcuts:
cxscale
is a shortcut forcarrierScaling
[0]
cyscale
is a shortcut forcarrierScaling
[1]
- carrierTranslation
This is a managed property. It is a sequence of two numbers, expressed in pixels, corresponding to x and y dimensions. It shifts the carrier (texture stimulus and/or shader function) relative to the envelope. Note that non-integer translation values will introduce interpolation artifacts into stimuli that use textures (but unlike
envelopeTranslation
, this should not compromise pure functionally-generated stimuli).Default value:
[0.0, 0.0]
- Subscripting shortcuts:
cx
is a shortcut forcarrierTranslation
[0]
cy
is a shortcut forcarrierTranslation
[1]
- color
This is a managed property. It is a triplet of numbers, each in the range 0 to 1, corresponding to red, green and blue channels. Values may also be negative, in which case no colorization is applied in the corresponding channel.
Where non-negative, foreground color plays slightly different roles depending on other parameters:
If the
Stimulus
uses a texture, the pixel values from the texture are tinted via multiplication with thecolor
values.If the
Stimulus
uses asignalFunction
then the signal is also multiplied by thecolor
before being added.If there is no texture and no
signalFunction
, the carrier image consists of just the specified uniform solidcolor
. TheStimulus
color may still be attenuated towards thebackgroundColor
—uniformly by settingnormalizedContrast
< 1.0, and/or as a function of space by settingplateauProportion
>= 0.0
or by using amodulationFunction
).
- colorTransformation
This is a managed property. It is an integer specifying the index of a shader-side color transformation function. If it is set to 0, no special color transformation is performed (but the standard
gamma
transformation can still be independently applied).Further values may be supported if you add support for them yourself using
AddCustomColorTransformation()
.In the shader, the color transformation function takes one input argument (a
vec4
containing pre-linearization RGBA values) and return a transformedvec4
. The return value will then be passed on to the standardgamma
linearization step, if used.See also:
gamma
Default value:
0
- contrast
contrast
is an alias fornormalizedContrast
- cr
cr
is an alias forcarrierRotation
- cscale
cscale
is an alias forcarrierScaling
- cscaling
cscaling
is an alias forcarrierScaling
- cx
This is a managed shortcut. It is a shortcut for
carrierTranslation
[0]
- cxscale
This is a managed shortcut. It is a shortcut for
carrierScaling
[0]
- cy
This is a managed shortcut. It is a shortcut for
carrierTranslation
[1]
- cyscale
This is a managed shortcut. It is a shortcut for
carrierScaling
[1]
- dd
dd
is an alias forditheringDenominator
- depthPlane
depthPlane
is an alias forz
- ditheringDenominator
This is a managed property. It is a floating-point number. It should be 0 or negative to disable dithering, or otherwise equal to the maximum DAC value (255 for most video cards). It allows implementation of the “noisy-bit” dithering approach (Allard & Faubert, 2008) for increasing effective dynamic range.
This is distinct from the
noiseAmplitude
property, which specifies noise that is (a) applied pre-gamma-correction, (b) can be scaled differently in different color channels, but (c) is otherwise perfectly correlated across color channels. Noisy-bit dithering, on the other hand (a) is applied post-gamma-correction, (b) has the same amplitude in all color channels but (c) is indepdent in each color channel.Note that, like gamma-correction, noisy-bit dithering is disabled for stimuli that use a
lut
Default value: dithering enabled (value determined automatically)
Canonical name:
ditheringDenominator
Other aliases:
dd
- drawMode
This is a managed property. It is an integer that selects between different drawing behaviors. The different values are given meaningful names in the namespace
DRAWMODE
, whose documentation also explains the behavior of the different draw modes.Default value:
1
- envelopeOrigin
This is a managed property. It is a triplet of numbers, expressed in pixels, denoting the starting-point, in the coordinate system of the parent
World
, of the offsetsenvelopeTranslation
(which is composed ofx
andy
) and depth coordinatez
. The actual rendered position of the anchor point ofStimulus
s
will be:[ int(s.x) + s.ox, int(s.y) + s.oy, s.z + s.oz ]
relative to the
World
’s ownorigin
.You can manipulate
envelopeOrigin
exclusively and leaveenvelopeTranslation
at 0, as an alternative way of specifyingStimulus
position. This is the way to go if you prefer to work in 3D floating-point coordinates instead of 2D integers: unlikeenvelopeTranslation
, this property gives you the opportunity to represent non-integer coordinate values. With that flexibility comes a caveat: non-whole-number values ofox
andoy
may result in artifacts in any kind ofStimulus
(textured or not) due to linear interpolation during rendering. You may therefore wish to take care to round any values you assign, if you choose to use this property. If you exclusively useenvelopeTranslation
instead, this pitfall is avoided (as you can see in the formula above, its componentsx
andy
are rounded down to integer values when they are applied).Note also that for all stimuli, you should ensure that the total depth coordinate,
s.z + s.oz
, is in the range ( -1, +1 ].Default value:
[0.0, 0.0, 0.0]
- Subscripting shortcuts:
ox
is a shortcut forenvelopeOrigin
[0]
oy
is a shortcut forenvelopeOrigin
[1]
oz
is a shortcut forenvelopeOrigin
[2]
- envelopePosition
envelopePosition
is an alias forenvelopeTranslation
- envelopeRotation
This is a managed property. It is a scalar number, expressed in degrees. The envelope will be rotated counter-clockwise by this number of degrees around its
anchor
. Note that such transformations of the envelope (except at multiples of 90 degrees) will introduce small artifacts into any stimulus, due to linear interpolation.Default value:
0.0
Canonical name:
envelopeRotation
Other aliases:
angle
orientation
rotation
- envelopeScaling
This is a managed property. It is a sequence of two floating-point numbers denoting horizontal and vertical scaling factors. The actual rendered size, in pixels, of the scaled
Stimulus
s
will bes.envelopeScaling * s.envelopeSize
Note that such transformations of the envelope will introduce small artifacts into any stimulus, due to linear interpolation.Default value:
[1.0, 1.0]
Canonical name:
envelopeScaling
- Subscripting shortcuts:
xscaling
is a shortcut forenvelopeScaling
[0]
yscaling
is a shortcut forenvelopeScaling
[1]
- envelopeSize
This is a managed property. It is a sequence of two numbers denoting the unscaled width and height of the envelope (i.e. width and height in texel units). Change these numbers if, for example, you want to crop or repeat a texture, or to load new differently-shaped texture (the easiest way to do the latter is to call
LoadTexture()
method with argumentupdateEnvelopeSize=True
). To change the size of the envelope by stretching the image content to fit, manipulateenvelopeScaling
orscaledSize
instead.Default value:
[200, 200]
Canonical name:
envelopeSize
Other aliases:
size
- Subscripting shortcuts:
width
is a shortcut forenvelopeSize
[0]
height
is a shortcut forenvelopeSize
[1]
- envelopeTranslation
This is a managed property. It is a pair of numbers, expressed in pixels. It dictates the two- dimensional coordinates of the
Stimulus
location within the drawing area. The values are rounded down to integer values when they are applied, to avoid artifacts that might otherwise be introduced inadvertently due to linear interpolation during rendering.See also:
envelopeOrigin
Default value:
[0.0, 0.0]
Canonical name:
envelopeTranslation
Other aliases:
envelopePosition
pos
position
xy
- Subscripting shortcuts:
x
is a shortcut forenvelopeTranslation
[0]
y
is a shortcut forenvelopeTranslation
[1]
- foregroundColor
foregroundColor
is an alias forcolor
- property frame
This non-managed property is an integer denoting the index of the current frame of a multi-frame stimulus. Note that frames are concatenated horizontally in the underlying carrier texture, so a change in
frame
is actually achieved by manipulatingcx
, otherwise known ascarrierTranslation[0]
.
- gamma
This is a managed property. It is a triplet of values denoting the screen gamma that should be corrected-for in each of the red, green and blue channels. A gamma value of 1 corresponds to the assumption that your screen is already linear. Setting gamma values other than 1 is an alternative to using a pre-linearized lookup-table or
lut
.Any value less than or equal to 0.0 is interpreted to denote the sRGB function, which is a standard piecewise function that follows the
gamma=2.2
curve quite closely (although the exponent it uses is actually slightly higher).
- green
This is a managed shortcut. It is a shortcut for
color
[1]
- greengamma
This is a managed shortcut. It is a shortcut for
gamma
[1]
- greennoise
This is a managed shortcut. It is a shortcut for
noiseAmplitude
[1]
- height
This is a managed shortcut. It is a shortcut for
envelopeSize
[1]
- property linearMagnification
This property governs the interpolation behavior applied when a textured
Stimulus
is enlarged (i.e. when itsenvelopeScaling
orcarrierScaling
are greater than 1).If
True
(default), interpolate pixel values linearly when enlarged.If
False
, take the “nearest pixel” method when enlarged.
- property lut
The value of this property will either be
None
, or an instance ofLookupTable
. Assigning to this property is equivalent to calling theSetLUT()
method—so you can assign any of the valid argument types accepted by that function. AssigningNone
disables look-up.
- moda
moda
is an alias formodulationDepth
- modd
modd
is an alias formodulationDepth
- modf
modf
is an alias formodulationFrequency
- modfunc
modfunc
is an alias formodulationFunction
- modo
modo
is an alias formodulationOrientation
- modp
modp
is an alias formodulationPhase
- modulationAmplitude
modulationAmplitude
is an alias formodulationDepth
- modulationDepth
This is a managed shortcut. It is a shortcut for
modulationParameters
[0]
(amplitude, i.e. modulation depth, from 0 to 1)Canonical name:
modulationDepth
Other aliases:
moda
modd
modulationAmplitude
- modulationFrequency
This is a managed shortcut. It is a shortcut for
modulationParameters
[1]
(frequency in cycles/pixel)Canonical name:
modulationFrequency
Other aliases:
modf
- modulationFunction
This is a managed property. It is an integer specifying the index of a shader-side contrast modulation function. If it is left at 0, no function is used: the stimulus contrast is then dependent only on the overall
normalizedContrast
and on the window applied according toplateauProportion
.A value of 1 (which can also be referenced as the constant
MODFUNC.SinewaveModulation
) corresponds to the one and only shader- side modulation function that we provide out of the box, namelySinewaveModulation
which performs sinusoidal contrast modulation. The parameters of this modulation pattern are determined by themodulationParameters
property.Further values, and hence further functions, may be supported if you add them yourself using
AddCustomModulationFunction()
.In the shader, the return value of a modulation function is a
float
. This return value is used as a multiplier for stimulus contrast.See also:
modulationParameters
,signalFunction
,signalParameters
,windowingFunction
Default value:
0
Canonical name:
modulationFunction
Other aliases:
modfunc
- modulationOrientation
This is a managed shortcut. It is a shortcut for
modulationParameters
[2]
(orientation in degrees)Canonical name:
modulationOrientation
Other aliases:
modo
- modulationParameters
This is a managed property. It is a 4-element vector that can be used to pass parameters to the shader-side contrast-modulation function chosen by
modulationFunction
.If
modulationFunction
is left at its default value of 0, these four values are ignored. For the one built-in shader modulation function (modulationFunction=1
corresponding to the shader functionSinewaveModulation
), the values are interpreted as depth, frequency, orientation and phase of the desired sinusoidal modulation pattern.If you’re adding your own custom shader function via
AddCustomModulationFunction()
, your implementation of that function may choose to ignore or reinterpret this property as you wish. If you choose to use it, your shader code can access it as the uniformvec4
variableuModulationParameters.
See also:
modulationFunction
,signalFunction
,signalParameters
Default value:
[0.0, 0.005, 0.0, 90.0]
- Subscripting shortcuts:
modulationDepth
is a shortcut formodulationParameters
[0]
(amplitude, i.e. modulation depth, from 0 to 1)modulationFrequency
is a shortcut formodulationParameters
[1]
(frequency in cycles/pixel)modulationOrientation
is a shortcut formodulationParameters
[2]
(orientation in degrees)modulationPhase
is a shortcut formodulationParameters
[3]
(phase in degrees)
- modulationPhase
This is a managed shortcut. It is a shortcut for
modulationParameters
[3]
(phase in degrees)Canonical name:
modulationPhase
Other aliases:
modp
- property nFrames
Read-only non-managed property that returns the width of each frame, if the texture pixel data is divided up horizontally into multiple frames.
- noise
noise
is an alias fornoiseAmplitude
- noiseAmplitude
This is a managed property. It is a triplet of floating-point numbers corresponding to red, green and blue channels. Negative values lead to uniform noise in the range
[s.noiseAmplitude[i], -s.noiseAmplitude[i]]
. Positive values lead to Gaussian noise with standard deviation equal to thenoiseAmplitude
value.The noise specified in this way is applied before gamma-correction, and is monochromatic (i.e. perfectly correlated across color channels, though it may have different amplitudes in each channel). It is particularly useful for applying very-low-amplitude noise prior to look-up in a high-dynamic-range bit-stealing look-up table. It can also be useful at higher amplitudes, to create visible noise effects.
It is not to be confused with noisy-bit dithering, which is applied post-gamma-correction (and only when a look-up table is not used), and which is controlled independently by the
ditheringDenominator
property.Default value:
[0.0, 0.0, 0.0]
Canonical name:
noiseAmplitude
Other aliases:
noise
- Subscripting shortcuts:
rednoise
is a shortcut fornoiseAmplitude
[0]
greennoise
is a shortcut fornoiseAmplitude
[1]
bluenoise
is a shortcut fornoiseAmplitude
[2]
- normalizedContrast
This is a managed property. It is a scalar floating-point value in the range 0.0 to 1.0 which scales the overall contrast of the
Stimulus
. At a contrast of 0, theStimulus
is reduced to itsbackgroundColor
.Default value:
1.0
Canonical name:
normalizedContrast
Other aliases:
contrast
- offset
This is a managed property. It is a triplet of numbers, each in the range 0.0 to 1.0, corresponding to red, green and blue channels. This is added uniformly to all pixel values before they are scaled by
normalizedContrast
or by windowing (viaplateauProportion
andwindowingFunction
) and/or custom modulation (viamodulationFunction
).
- orientation
orientation
is an alias forenvelopeRotation
- outOfRangeAlpha
This is a managed property. It is a floating-point number from 0 to 1. It specifies the color that should be used for pixels whose values go out of range. A negative value disables this feature (the alpha value of an out-of- range pixel is left unchanged).
Default value:
1.0
- outOfRangeColor
This is a managed property. It is a triplet of numbers, each in the range 0 to 1, corresponding to red, green and blue channels. It specifies the color that should be used for pixels whose values go out of range. A negative value means “do not flag out-of-range values in this color channel” (values are merely clipped in the range 0 to 1 in that case).
Default value:
[1.0, 0.0, 1.0]
- ox
This is a managed shortcut. It is a shortcut for
envelopeOrigin
[0]
- oy
This is a managed shortcut. It is a shortcut for
envelopeOrigin
[1]
- oz
This is a managed shortcut. It is a shortcut for
envelopeOrigin
[2]
- property page
A
Stimulus
may optionally have more than one “page”. A page is a label attached to a particular set of property values that determine texture, envelope size and envelope shape.A page may have any hashable label—integers and strings are usually the most meaningful. The
page
property allows you to query the label of the current page, or switch to a different page according to its label. It is not a managed property, but it does support dynamic value assignment.See also:
LoadPages()
,NewPage()
,SavePage()
, andSwitchTo()
- penThickness
This is a managed property. It is a scalar floating-point value that determines the width, in pixels, of of lines and points drawn when you set
drawMode
toDRAWMODE.POINTS
,DRAWMODE.LINES
,DRAWMODE.LINE_STRIP
orDRAWMODE.LINE_LOOP
. Implementation is driver-dependent however: many graphics cards seem to consider line-thickness to be a legacy feature and have dropped support for it (for lines, but maybe not for points) in their pure modern-OpenGL contexts.Default value:
1.0
- plateauProportion
This is a managed property. It is sequence of two floating-point values corresponding to the x and y dimensions.
A negative value indicates that no windowing is to be performed in the corresponding dimension.
A value in the range [0, 1] causes windowing to occur: with the default (raised cosine)
windowingFunction
, aplateauProportion
of 0 gives a Hann window, 1 gives a boxcar window, and intermediate values combine the specified amount of constant plateau with a raised- cosine falloff to the edge of the envelope (i.e., a Tukey window).A non-zero plateau proportion can also be combined with other (custom self-written)
windowingFunction
implementations.Note that this means [1, 1] gives a circular or elliptical envelope with sharp edges, in contrast to [-1, -1] which gives a square or rectangular envelope.
Default value:
[-1.0, -1.0]
Canonical name:
plateauProportion
Other aliases:
pp
- Subscripting shortcuts:
ppx
is a shortcut forplateauProportion
[0]
ppy
is a shortcut forplateauProportion
[1]
- property points
This is a view into the
Stimulus
instance’s optional array of coordinates. If you do not have the third-party packagenumpy
installed, then this is fairly limited (although you can assign a list of alternating x and y coordinates to it, you will not be able to do any array arithmetic operations with it, which is where its power lies). Withnumpy
, yourpoints
will appear as ann
-by-2 array of coordinates (you can also view the same data as a sequence of complex numbers, by accessing aspointsComplex
). These coordinates are not used in the defaultdrawMode
, which isDRAWMODE.QUAD
. To learn how other draw modes use the coordinates, see the documentation for theDRAWMODE
namespace.Assignment to
points
is interchangeable with assignment topointsComplex
—in either case, the input can be a sequence ofn
complex numbers OR ann
-by-2 array of real-valued coordinates. Under the hood, assignment topoints
changes the content of the managed propertypointsXY
and also adjusts the managed propertynPoints
The coordinate system of the
points
is always in pixels relative to the bottom-left corner of theStimulus
bounding-box—i.e. the bottom-left corner of the rectangle you would see if you were to switch theStimulus
back todrawMode=Shady.DRAWMODE.QUAD
. TheWorld.anchor
,Stimulus.position
,Stimulus.anchor
andStimulus.size
determine where this local origin actually lies on screen, but thepoints
themselves are expressed independently of these, and points defined outside the bounding-box (e.g. with negative coordinates) still get drawn.
- property pointsComplex
This is a view into the
Stimulus
instance’s optional array of coordinates. The same data are also accessible aspoints
. The only difference is that when you ask forpointsComplex
, the data are interpreted as a sequence of complex numbers (requires the third-party packagenumpy
).Assignment to
pointsComplex
is interchangeable with assignment topoints
—in either case, the input can be a sequence ofn
complex numbers OR ann
-by-2 array of real-valued coordinates.
- pos
pos
is an alias forenvelopeTranslation
- position
position
is an alias forenvelopeTranslation
- pp
pp
is an alias forplateauProportion
- ppx
This is a managed shortcut. It is a shortcut for
plateauProportion
[0]
- ppy
This is a managed shortcut. It is a shortcut for
plateauProportion
[1]
- red
This is a managed shortcut. It is a shortcut for
color
[0]
- redgamma
This is a managed shortcut. It is a shortcut for
gamma
[0]
- rednoise
This is a managed shortcut. It is a shortcut for
noiseAmplitude
[0]
- rotation
rotation
is an alias forenvelopeRotation
- scale
scale
is an alias forenvelopeScaling
- property scaledAspectRatio
Non-managed property that affects the behavior of
scaledWidth
andscaledHeight
manipulations. The value may be aNone
, the string'fixed'
, or a floating-point number.Assigning a floating-point number to
scaledAspectRatio
will immediately reduce either the horizontal or the vertical component ofenvelopeScaling
as necessary to achieve the target aspect ratio.Once the value is set to something other than
None
, future manipulation of either thescaledWidth
property or thescaledHeight
property will cause the other property to be adjusted simultaneously, to maintain the target aspect ratio. If the value is'fixed'
, then the target value is simply “whatever it was before you made the manipulation”.This prospective control only applies to the
scaled*
properties, however—if you directly manipulateenvelopeSize
orenvelopeScaling
, thescaledAspectRatio
setting will not be automatically reasserted.
- property scaledHeight
Non-managed property that reflects the product of
envelopeSize[1]
andenvelopeScaling[1]
. Assigning to this property will changeenvelopeScaling[1]
accordingly. Dynamic value assignment is supported.If the
scaledAspectRatio
property is either'fixed'
or a numeric value, then the value ofscaledWidth
will simultaneously be adjusted to ensure aspect ratio is preserved. IfscaledAspectRatio
isNone
, thenscaledWidth
will not be adjusted.
- property scaledSize
Non-managed property that reflects the product of
envelopeSize
andenvelopeScaling
. Assigning to this property will changeenvelopeScaling
accordingly. Dynamic value assignment is supported. Note that you can also addressscaledWidth
andscaledHeight
separately if you wish.If the
scaledAspectRatio
property is eitherNone
or'fixed'
, then the explicitly-specifiedscaledSize
value will be respected exactly. However, if you have previously set the value ofscaledAspectRatio
to a numeric constant, then the requestedscaledSize
values may be adjusted (one of them will be reduced) if necessary to preserve that aspect ratio.
- property scaledWidth
Non-managed property that reflects the product of
envelopeSize[0]
andenvelopeScaling[0]
. Assigning to this property will changeenvelopeScaling[0]
accordingly. Dynamic value assignment is supported.If the
scaledAspectRatio
property is either'fixed'
or a numeric value, then the value ofscaledHeight
will simultaneously be adjusted to ensure aspect ratio is preserved. IfscaledAspectRatio
isNone
, thenscaledHeight
will not be adjusted.
- scaling
scaling
is an alias forenvelopeScaling
- siga
siga
is an alias forsignalAmplitude
- sigf
sigf
is an alias forsignalFrequency
- sigfunc
sigfunc
is an alias forsignalFunction
- signalAmplitude
This is a managed shortcut. It is a shortcut for
signalParameters
[0]
(amplitude from 0 to 1)Canonical name:
signalAmplitude
Other aliases:
siga
- signalFrequency
This is a managed shortcut. It is a shortcut for
signalParameters
[1]
(frequency in cycles/pixel)Canonical name:
signalFrequency
Other aliases:
sigf
- signalFunction
This is a managed property. It is an integer specifying the index of a shader-side signal function. If it is left at 0, no function is used: the carrier content is then dependent purely on the texture, if any, or is blank if no texture was specified. A value of 1 (which can also be referenced as the constant
SIGFUNC.SinewaveSignal
) corresponds to the one and only shader-side signal function that we provide out of the box, namelySinewaveSignal
which generates a sinusoid. The parameters of the sinusoid are determined by thesignalParameters
property.Further values, and hence further functions, may be supported if you add them yourself using
AddCustomSignalFunction()
.In the shader, the return value of a signal functions is either a
vec3
or afloat
. This return value gets multiplied by thecolor
of theStimulus
, and added to itsbackgroundColor
(and/or its texture, if any). Ifcolor
is negative (i.e. disabled, as it is by default) then the function output is multiplied byvec3(1.0, 1.0, 1.0)
.See also:
signalParameters
,modulationFunction
,modulationParameters
,windowingFunction
Default value:
0
Canonical name:
signalFunction
Other aliases:
sigfunc
- signalOrientation
This is a managed shortcut. It is a shortcut for
signalParameters
[2]
(orientation in degrees)Canonical name:
signalOrientation
Other aliases:
sigo
- signalParameters
This is a managed property. It is a 4-element vector that can be used to pass parameters to the shader-side carrier-signal-generating function chosen by
signalFunction
. IfsignalFunction
is left at its default value of 0, thesignalParameters
are ignored. For the one built-in shader signal function (signalFunction=1
corresponding to the shader functionSinewaveSignal
), these parameters are interpreted as amplitude, frequency, orientation and phase of the sinusoidal pattern. Signal functions are additive to your background and/or texture, so if you have no texture and a background color of, for example, 0.3 or 0.7, a sinewave amplitude greater than 0.3 will go out of range at full contrast. (Beware also the additive effect of noise, if yournoiseAmplitude
is not 0.)If you’re adding your own custom shader function via
AddCustomSignalFunction()
, your implementation of that function may choose to ignore or reinterpret this property as you wish. If you choose to use it, your shader code can access it as the uniformvec4
variableuSignalParameters.
See also:
signalFunction
,modulationFunction
,modulationParameters
Default value:
[1.0, 0.05, 0.0, 0.0]
- Subscripting shortcuts:
signalAmplitude
is a shortcut forsignalParameters
[0]
(amplitude from 0 to 1)signalFrequency
is a shortcut forsignalParameters
[1]
(frequency in cycles/pixel)signalOrientation
is a shortcut forsignalParameters
[2]
(orientation in degrees)signalPhase
is a shortcut forsignalParameters
[3]
(phase in degrees)
- signalPhase
This is a managed shortcut. It is a shortcut for
signalParameters
[3]
(phase in degrees)Canonical name:
signalPhase
Other aliases:
sigp
- sigo
sigo
is an alias forsignalOrientation
- sigp
sigp
is an alias forsignalPhase
- size
size
is an alias forenvelopeSize
- smoothing
This is a managed property. It is an integer value that determines whether lines, dots and polygons should be drawn with or without smoothing. The results are unfortunately unpredictable as they vary according to your graphics card and drivers. Example: with
DRAWMODE.POINTS
, settingsmoothing=1
causes the dots to be round rather than square—but with some graphics drivers, they will remain square regardless (to guarantee round dots, it’s better to draw tiny many-sided polygons). A value of 0 means no smoothing. A value of 1 means points and lines should be smoothed. A value of 2 means lines, points and polygons are smoothed (note that polygon smoothing causes diagonal “crack” artifacts on many graphics cards/drivers, so this option is not enabled by default).Default value:
1
- property text
To use the
text
property of theStimulus
class, you must first explicitlyimport Shady.Text
(seeShady.Text
for documentation on this property).
- textureChannels
This is a managed property. It is an integer value denoting whether the texture has 1, 2, 3 or 4 channels. If there is no texture, the value is -1. You should consider this property read-only—do not change the value by hand.
Default value:
-1
- textureSize
This is a managed property. It is a pair of values denoting the width and height of the texture data, in pixels. If there is no texture, both values are -1. You should consider this property read-only—do not change the values by hand.
Default value:
[-1, -1]
- useTexture
This is a managed property. It is a boolean value. The default value is
True
if a texture has been specified, and this causes pixel values to be drawn from the texture specified by the constructor argumentsource
(or thesource
argument to a subsequentNewPage()
orLoadTexture()
call). IfuseTexture
is set toFalse
, the pixel values are determined bybackgroundColor
and/orforegroundColor
(as well asoffset
,normalizedContrast
, and any windowing and shader-sidesignalFunction
ormodulationFunction
).Default value:
1
- property video
To use the
video
property of theStimulus
class, you must first explicitlyimport Shady.Video
(seeShady.Video
for documentation on this property).
- visible
This is a managed property. It is a boolean value that determines whether the
Stimulus
is rendered or not.
- width
This is a managed shortcut. It is a shortcut for
envelopeSize
[0]
- windowFunction
windowFunction
is an alias forwindowingFunction
- windowingFunction
This is a managed property. It is an integer specifying the index of a shader-side windowing function. If it is set to 0 (or if the
plateauProportion
property is negative), no spatial windowing is used.The default value of 1 (which can also be referenced as the constant
WINFUNC.Hann
) corresponds to the one and only shader-side windowing function that we provide out of the box, namelyHann
, which causes contrast to fall off according to a raised cosine function of radial distance.Further values, and hence further functions, may be supported if you add them yourself using
AddCustomWindowingFunction()
.In the shader, the windowing function takes one input argument (a
float
whose value will range from 0 at peak of the window to 1 at the edge) and return afloat
. This return value is used as a multiplier for stimulus contrast.See also:
signalFunction
,modulationFunction
Default value:
1
Canonical name:
windowingFunction
Other aliases:
windowFunction
winfunc
- winfunc
winfunc
is an alias forwindowingFunction
- x
This is a managed shortcut. It is a shortcut for
envelopeTranslation
[0]
- xscaling
This is a managed shortcut. It is a shortcut for
envelopeScaling
[0]
- xy
xy
is an alias forenvelopeTranslation
- y
This is a managed shortcut. It is a shortcut for
envelopeTranslation
[1]
- yscaling
This is a managed shortcut. It is a shortcut for
envelopeScaling
[1]
- z
This is a managed property. It is a floating-point number that determines the depth plane of the
Stimulus
. The convention is that negative values put you closer to the camera, and positive further away; also, you must ensure -1 <= z <= +1. Since the projection is orthographic, the value is purely used for depth-sorting of stimuli: therefore, settingz
to a non-integer value will not cause interpolation artifacts.Default value:
0.0
Canonical name:
z
Other aliases:
depth
depthPlane
Global Functions and Constants
- Shady.AddCustomSignalFunction(code)
Defines a new signal function in the fragment shader.
Must be called, before construction of your
World
. Thecode
argument is a (usually triple-quoted multi-line) string containing the complete definition of a function in GLSL.The protoype for the function may be one of the following:
float MySignalFunction( vec2 xy ) { ... } vec3 MySignalFunction( vec2 xy ) { ... }
where
xy
are coordinates measured in pixels relative to the center of the stimulus. Obviously we’re usingMySignalFunction
here as a placeholder—use your own descriptive name for the new function. Your function mustreturn
either a floating-point signal value, or three-dimensional (red, green, blue) signal value. If non-negative values have been supplied in aStimulus
instance’scolor
property, your signal function will get multiplied by these. Then, any desired contrast modulation and windowing will be applied. Then, the result will be added to thebackgroundColor
.Your new function can be applied to a
Stimulus
instancestim
as follows:stim.signalFunction = Shady.SIGFUNC.MySignalFunction
If you want to parameterize your new function further, you can use the existing
uniform vec4 uSignalParameters
variable, which is linked to theStimulus.signalParameters
property. You can also define your own additional properties/uniform variables with theAddCustomUniform()
class method.
- Shady.AddCustomModulationFunction(code)
Defines a new contrast-modulation function in the fragment shader.
Must be called before construction of your
World
. Thecode
argument is a (usually triple-quoted multi-line) string containing the complete definition of a function in GLSL.The protoype for the function must be:
float MyModulationFunction( vec2 xy ) { ... }
where
xy
are coordinates measured in pixels relative to the center of the stimulus. Obviously we’re usingMyModulationFunction
here as a placeholder—use your own descriptive name for the new function. Your function mustreturn
a floating-point contrast multiplier.Your new function can be applied to a
Stimulus
instancestim
as follows:stim.modulationFunction = Shady.MODFUNC.MyModulationFunction
If you want to parameterize your new function further, you can use the existing
uniform vec4 uModulationParameters
variable, which is linked to theStimulus.modulationParameters
property. You can also define your own additional properties/uniform variables with theAddCustomUniform()
class method.
- Shady.AddCustomWindowingFunction(code)
Defines a new spatial windowing function in the fragment shader.
Must be called before construction of your
World
. Thecode
argument is a (usually triple-quoted multi-line) string containing the complete definition of a function in GLSL.The protoype for the function must be:
float MyWindowingFunction( float r ) { ... }
where the domain of
r
if from 0 (in the center of theStimulus
, or indeed anywhere on its plateau if it has one) to 1 (at outer edge of the largest oval that fits in theStimulus
bounding box). Obviously we’re usingMyWindowingFunction
here as a placeholder— use your own descriptive name for the new function. Your function mustreturn
a floating-point contrast multiplier.Your new function can be applied to a
Stimulus
instancestim
as follows (bearing in mind that a negativeplateauProportion
value disables windowing entirely):stim.windowingFunction = Shady.WINFUNC.MyWindowingFunction stim.plateauProportion = 0
If you want to parameterize your new function further, you can define your own additional properties/uniform variables with the
AddCustomUniform()
class method.
- Shady.AddCustomColorTransformation(code)
Defines a new color transformation function in the fragment shader.
Must be called before construction of your
World
. Thecode
argument is a (usually triple-quoted multi-line) string containing the complete definition of a function in GLSL.The protoype for the function must be:
vec4 MyColorTransformation( vec4 color ) { ... }
where the input and output arguments are both RGBA vectors in the domain [0, 1]. The custom transformation step is applied to the pixel color immediately before standard
gamma
linearization, if any.Your new function can be applied to a
Stimulus
instancestim
as follows:stim.colorTransformation = Shady.COLORTRANS.MyColorTransformation
If you want to parameterize your new function further, you can define your own additional properties/uniform variables with the
AddCustomUniform()
class method.
- Shady.BackEnd(windowing=None, acceleration=None)
Globally specify the back-end windowing and rendering systems that future
World
instances should use.- Parameters:
windowing – specifies the windowing system. Possible values are as follows:
'default'
:use the ShaDyLib dynamic library if available, else fall back on pyglet.
'shadylib'
,'accel'
, or'glfw'
:use the ShaDyLib dynamic library (windowing is handled via the GLFW library from http://glfw.org ).
'pyglet'
:use pyglet (a third-party package that you will need to install separately if you want to use this option)
'pygame'
:use pygame (a third-party package that you will need to install separately if you want to use this option)
acceleration – specifies the rendering implementation, i.e. whether to use the ShaDyLib dynamic library (and if so, whether to use the “development” copy of ShaDyLib in cases where you have the entire Shady repository including the C++ sources for ShaDyLib) or whether to fall back on Python code for rendering (not recommended). Possible values are:
None
:leave things as they were (default).
False
:disable ShaDyLib and fall back on the
pyglet
orPyOpenGL
code in thePyEngine
submodule (this option is not recommended for time-critical presentation).True
:if ShaDyLib is already imported, leave things as they are; if not, import either version of ShaDyLib or die trying. Prefer the development version, if available. Print the outcome.
'bundled'
:silently import the bundled version of ShaDyLib from the Shady.accel sub-package, or die trying.
'devel'
:silently import the development version of ShaDyLib from
/../accel-src/release/
, or die trying.'auto'
:try to import ShaDyLib. Prefer the development version, if available. Don’t die in the attempt. Whatever happens, print the outcome.
- Returns:
If both input arguments are
None
, the name of the current windowing back-end is returned. Otherwise, returnsNone
.
- Shady.Screens(pretty_print=False)
Get details of any attached screens using the
Screens()
method of whichever windowing backend is enabled.- Parameters:
pretty_print (bool) – determines the type of the return value
- Returns:
If
pretty_print
isTrue
, returns a human-readable string. Ifpretty_print
isFalse
, returns adict
.
- class Shady.SIGFUNC
This class is an enum container: a namespace of values that can be assigned to the
signalFunction
property of aStimulus
instance. Its members are named according to the signal functions available in the shader. The only built-in function isSinewaveSignal
which has a value of 1. So, when you set thesignalFunction
property of aStimulus
to 1, theSinewaveSignal
function is selected in the shader, and when you set it to 0, no signal function is selected.You can define further signal functions, and hence add names and values to this namespace, with
AddCustomSignalFunction
.
- class Shady.MODFUNC
This class is an enum container: a namespace of values that can be assigned to the
modulationFunction
property of aStimulus
instance. Its members are named according to the modulation functions available in the shader. The only built-in function isSinewaveModulation
which has a value of 1. So, when you set themodulationFunction
property of aStimulus
to 1, theSinewaveModulation
function is selected in the shader, and when you set it to 0, no modulation function is selected.You can define further modulation functions, and hence add names and values to this namespace, with
AddCustomModulationFunction
.
- class Shady.WINFUNC
This class is an enum container: a namespace of values that can be assigned to the
windowingFunction
property of aStimulus
instance. Its members are named according to the windowing functions available in the shader. The only built-in function isHann
which has a value of 1. So, when you set thewindowingFunction
property of aStimulus
to 1, theHann
function is selected in the shader, and when you set it to 0, no windowing function is selected.You can define further windowing functions, and hence add names and values to this namespace, with
AddCustomWindowingFunction
.
- class Shady.COLORTRANS
This class is an enum container: a namespace of values that can be assigned to the
colorTransformation
property of aStimulus
instance.You can define color transformations, and hence add names and values to this namespace, with
AddCustomColorTransformation
.
- class Shady.DRAWMODE
This class is an enum container: a namespace of values that can be assigned to the
drawMode
property of aStimulus
instance. The defaultdrawMode
isDRAWMODE.QUAD
: that means that eachStimulus
is automatically drawn as a rectangle according to itsenvelopeSize
.Other modes rely on the
points
property, which contains a sequence of two-dimensional coordinates:DRAWMODE.POINTS
draws a disconnected dot at each location.DRAWMODE.LINES
takes two locations at a time and connects each pair with a line segment, disconnected from previous or subsequent line segments.DRAWMODE.LINE_STRIP
draws line segments continuously from one location to the next, only taking the pen off the paper if it enounters a NaN coordinate.DRAWMODE.LINE_LOOP
is like LINE_STRIP, but the last point in each group is joined back to the first (where a “group” is delimited by NaNs in the sequence of coordinates).DRAWMODE.POLYGON
also connects successive locations continuously, and fills the area bounded by the lines thus drawn (a NaN coordinate is a way to delimit multiple polygons)