Package VisionEgg :: Module Gratings
[frames] | no frames]

Source Code for Module VisionEgg.Gratings

  1  # The Vision Egg: Gratings 
  2  # 
  3  # Copyright (C) 2001-2003 Andrew Straw. 
  4  # Copyright (C) 2005,2008 California Institute of Technology 
  5  # 
  6  # URL: <http://www.visionegg.org/> 
  7  # 
  8  # Distributed under the terms of the GNU Lesser General Public License 
  9  # (LGPL). See LICENSE.TXT that came with this file. 
 10   
 11  """ 
 12  Grating stimuli. 
 13   
 14  """ 
 15   
 16  #################################################################### 
 17  # 
 18  #        Import all the necessary packages 
 19  # 
 20  #################################################################### 
 21   
 22  import logging                              # available in Python 2.3 
 23   
 24  import VisionEgg 
 25  import VisionEgg.Core 
 26  import VisionEgg.Textures 
 27  import VisionEgg.ParameterTypes as ve_types 
 28  import numpy 
 29  import math, types, string 
 30  import VisionEgg.GL as gl # get all OpenGL stuff in one namespace 
 31  import _vegl 
 32   
33 -def _get_type_info( bitdepth ):
34 """Private helper function to calculate type info based on bit depth""" 35 if bitdepth == 8: 36 gl_type = gl.GL_UNSIGNED_BYTE 37 numpy_dtype = numpy.uint8 38 max_int_val = float((2**8)-1) 39 elif bitdepth == 12: 40 gl_type = gl.GL_SHORT 41 numpy_dtype = numpy.int16 42 max_int_val = float((2**15)-1) 43 elif bitdepth == 16: 44 gl_type = gl.GL_INT 45 numpy_dtype = numpy.int32 46 max_int_val = float((2.**31.)-1) # do as float to avoid overflow 47 else: 48 raise ValueError("supported bitdepths are 8, 12, and 16.") 49 return gl_type, numpy_dtype, max_int_val
50
51 -class LuminanceGratingCommon(VisionEgg.Core.Stimulus):
52 """Base class with common code to all ways of drawing luminance gratings. 53 54 Parameters 55 ========== 56 bit_depth -- precision with which grating is calculated and sent to OpenGL (UnsignedInteger) 57 Default: 8 58 """ 59 60 parameters_and_defaults = VisionEgg.ParameterDefinition({ 61 'bit_depth':(8, 62 ve_types.UnsignedInteger, 63 'precision with which grating is calculated and sent to OpenGL'), 64 }) 65 66 __slots__ = ( 67 'gl_internal_format', 68 'format', 69 'gl_type', 70 'numpy_dtype', 71 'max_int_val', 72 'cached_bit_depth', 73 ) 74
76 """Calculate a number of parameters dependent on bit depth.""" 77 bit_depth_warning = False 78 p = self.parameters # shorthand 79 80 red_bits = gl.glGetIntegerv( gl.GL_RED_BITS ) 81 green_bits = gl.glGetIntegerv( gl.GL_GREEN_BITS ) 82 blue_bits = gl.glGetIntegerv( gl.GL_BLUE_BITS ) 83 min_bits = min( (red_bits,green_bits,blue_bits) ) 84 if min_bits < p.bit_depth: 85 logger = logging.getLogger('VisionEgg.Gratings') 86 logger.warning("Requested bit depth of %d in " 87 "LuminanceGratingCommon, which is " 88 "greater than your current OpenGL context " 89 "supports (%d)."% (p.bit_depth,min_bits)) 90 self.gl_internal_format = gl.GL_LUMINANCE 91 self.format = gl.GL_LUMINANCE 92 self.gl_type, self.numpy_dtype, self.max_int_val = _get_type_info( p.bit_depth ) 93 self.cached_bit_depth = p.bit_depth
94
95 -class AlphaGratingCommon(VisionEgg.Core.Stimulus):
96 """Base class with common code to all ways of drawing gratings in alpha. 97 98 This class is currently not used by any other classes. 99 100 Parameters 101 ========== 102 bit_depth -- precision with which grating is calculated and sent to OpenGL (UnsignedInteger) 103 Default: 8 104 """ 105 106 parameters_and_defaults = VisionEgg.ParameterDefinition({ 107 'bit_depth':(8, 108 ve_types.UnsignedInteger, 109 'precision with which grating is calculated and sent to OpenGL'), 110 }) 111 112 __slots__ = ( 113 'gl_internal_format', 114 'format', 115 'gl_type', 116 'numpy_dtype', 117 'max_int_val', 118 'cached_bit_depth', 119 ) 120
122 """Calculate a number of parameters dependent on bit depth.""" 123 p = self.parameters # shorthand 124 alpha_bit_depth = gl.glGetIntegerv( gl.GL_ALPHA_BITS ) 125 if alpha_bit_depth < p.bit_depth: 126 logger = logging.getLogger('VisionEgg.Gratings') 127 logger.warning("Requested bit depth of %d, which is " 128 "greater than your current OpenGL context " 129 "supports (%d)."% (p.bit_depth,min_bits)) 130 self.gl_internal_format = gl.GL_ALPHA 131 self.format = gl.GL_ALPHA 132 self.gl_type, self.numpy_dtype, self.max_int_val = _get_type_info( p.bit_depth ) 133 self.cached_bit_depth = p.bit_depth
134
135 -class SinGrating2D(LuminanceGratingCommon):
136 """Sine wave grating stimulus 137 138 This is a general-purpose, realtime sine-wave luminace grating 139 generator. To acheive an arbitrary orientation, this class rotates 140 a textured quad. To draw a grating with sides that always remain 141 horizontal and vertical, draw a large grating in a small viewport. 142 (The viewport will clip anything beyond its edges.) 143 144 Parameters 145 ========== 146 anchor -- specifies how position parameter is interpreted (String) 147 Default: center 148 bit_depth -- precision with which grating is calculated and sent to OpenGL (UnsignedInteger) 149 Inherited from LuminanceGratingCommon 150 Default: 8 151 color1 -- (AnyOf(Sequence3 of Real or Sequence4 of Real)) 152 Default: (1.0, 1.0, 1.0) 153 color2 -- optional color with which to perform interpolation with color1 in RGB space (AnyOf(Sequence3 of Real or Sequence4 of Real)) 154 Default: (determined at runtime) 155 contrast -- (Real) 156 Default: 1.0 157 depth -- (Real) 158 Default: (determined at runtime) 159 ignore_time -- (Boolean) 160 Default: False 161 mask -- optional masking function (Instance of <class 'VisionEgg.Textures.Mask2D'>) 162 Default: (determined at runtime) 163 max_alpha -- (Real) 164 Default: 1.0 165 num_samples -- (UnsignedInteger) 166 Default: 512 167 on -- draw stimulus? (Boolean) 168 Default: True 169 orientation -- (Real) 170 Default: 0.0 171 pedestal -- (Real) 172 Default: 0.5 173 phase_at_t0 -- (Real) 174 Default: 0.0 175 position -- (units: eye coordinates) (Sequence2 of Real) 176 Default: (320.0, 240.0) 177 recalculate_phase_tolerance -- (Real) 178 Default: (determined at runtime) 179 size -- defines coordinate size of grating (in eye coordinates) (Sequence2 of Real) 180 Default: (640.0, 480.0) 181 spatial_freq -- frequency defined relative to coordinates defined in size parameter (units: cycles/eye_coord_unit) (Real) 182 Default: 0.0078125 183 t0_time_sec_absolute -- (Real) 184 Default: (determined at runtime) 185 temporal_freq_hz -- (Real) 186 Default: 5.0 187 """ 188 189 parameters_and_defaults = VisionEgg.ParameterDefinition({ 190 'on':(True, 191 ve_types.Boolean, 192 "draw stimulus?"), 193 'mask':(None, # allows window onto otherwise (tilted) rectangular grating 194 ve_types.Instance(VisionEgg.Textures.Mask2D), 195 "optional masking function"), 196 'contrast':(1.0, 197 ve_types.Real), 198 'pedestal':(0.5, 199 ve_types.Real), 200 'position':((320.0,240.0), # in eye coordinates 201 ve_types.Sequence2(ve_types.Real), 202 "(units: eye coordinates)"), 203 'anchor':('center', 204 ve_types.String, 205 "specifies how position parameter is interpreted"), 206 'depth':(None, # if not None, turns on depth testing and allows for occlusion 207 ve_types.Real), 208 'size':((640.0,480.0), 209 ve_types.Sequence2(ve_types.Real), 210 "defines coordinate size of grating (in eye coordinates)", 211 ), 212 'spatial_freq':(1.0/128.0, # cycles/eye coord units 213 ve_types.Real, 214 "frequency defined relative to coordinates defined in size parameter (units: cycles/eye_coord_unit)", 215 ), 216 'temporal_freq_hz':(5.0, # hz 217 ve_types.Real), 218 't0_time_sec_absolute':(None, # Will be assigned during first call to draw() 219 ve_types.Real), 220 'ignore_time':(False, # ignore temporal frequency variable - allow control purely with phase_at_t0 221 ve_types.Boolean), 222 'phase_at_t0':(0.0, # degrees [0.0-360.0] 223 ve_types.Real), 224 'orientation':(0.0, # 0=right, 90=up 225 ve_types.Real), 226 'num_samples':(512, # number of spatial samples, should be a power of 2 227 ve_types.UnsignedInteger), 228 'max_alpha':(1.0, # controls "opacity": 1.0 = completely opaque, 0.0 = completely transparent 229 ve_types.Real), 230 'color1':((1.0, 1.0, 1.0), # alpha is ignored (if given) -- use max_alpha parameter 231 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 232 ve_types.Sequence4(ve_types.Real))), 233 'color2':(None, # perform interpolation with color1 in RGB space. 234 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 235 ve_types.Sequence4(ve_types.Real)), 236 "optional color with which to perform interpolation with color1 in RGB space"), 237 'recalculate_phase_tolerance':(None, # only recalculate texture when phase is changed by more than this amount, None for always recalculate. (Saves time.) 238 ve_types.Real), 239 }) 240 241 __slots__ = ( 242 '_texture_object_id', 243 '_last_phase', 244 ) 245
246 - def __init__(self,**kw):
247 LuminanceGratingCommon.__init__(self,**kw) 248 249 p = self.parameters # shorthand 250 251 self._texture_object_id = gl.glGenTextures(1) 252 if p.mask: 253 gl.glActiveTextureARB(gl.GL_TEXTURE0_ARB) 254 gl.glBindTexture(gl.GL_TEXTURE_1D,self._texture_object_id) 255 256 # Do error-checking on texture to make sure it will load 257 max_dim = gl.glGetIntegerv(gl.GL_MAX_TEXTURE_SIZE) 258 if p.num_samples > max_dim: 259 raise NumSamplesTooLargeError("Grating num_samples too large for video system.\nOpenGL reports maximum size of %d"%(max_dim,)) 260 261 self.calculate_bit_depth_dependencies() 262 263 w = p.size[0] 264 inc = w/float(p.num_samples) 265 phase = 0.0 # this data won't get used - don't care about phase 266 self._last_phase = phase 267 floating_point_sin = numpy.sin(2.0*math.pi*p.spatial_freq*numpy.arange(0.0,w,inc,dtype=numpy.float)+(phase/180.0*math.pi))*0.5*p.contrast+p.pedestal 268 floating_point_sin = numpy.clip(floating_point_sin,0.0,1.0) # allow square wave generation if contrast > 1 269 texel_data = (floating_point_sin*self.max_int_val).astype(self.numpy_dtype).tostring() 270 271 # Because the MAX_TEXTURE_SIZE method is insensitive to the current 272 # state of the video system, another check must be done using 273 # "proxy textures". 274 gl.glTexImage1D(gl.GL_PROXY_TEXTURE_1D, # target 275 0, # level 276 self.gl_internal_format, # video RAM internal format 277 p.num_samples, # width 278 0, # border 279 self.format, # format of texel data 280 self.gl_type, # type of texel data 281 texel_data) # texel data (irrelevant for proxy) 282 if gl.glGetTexLevelParameteriv(gl.GL_PROXY_TEXTURE_1D, # Need PyOpenGL >= 2.0 283 0, 284 gl.GL_TEXTURE_WIDTH) == 0: 285 raise NumSamplesTooLargeError("Grating num_samples is too wide for your video system!") 286 287 # If we got here, it worked and we can load the texture for real. 288 gl.glTexImage1D(gl.GL_TEXTURE_1D, # target 289 0, # level 290 self.gl_internal_format, # video RAM internal format 291 p.num_samples, # width 292 0, # border 293 self.format, # format of texel data 294 self.gl_type, # type of texel data 295 texel_data) # texel data 296 297 # Set texture object defaults 298 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_WRAP_S,gl.GL_CLAMP_TO_EDGE) 299 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_WRAP_T,gl.GL_CLAMP_TO_EDGE) 300 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_MAG_FILTER,gl.GL_LINEAR) 301 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_MIN_FILTER,gl.GL_LINEAR) 302 303 if p.color2 is not None: 304 if VisionEgg.Core.gl_renderer == 'ATi Rage 128 Pro OpenGL Engine' and VisionEgg.Core.gl_version == '1.1 ATI-1.2.22': 305 logger = logging.getLogger('VisionEgg.Gratings') 306 logger.warning("Your video card and driver have known " 307 "bugs which prevent them from rendering " 308 "color gratings properly.")
309
310 - def __del__(self):
311 gl.glDeleteTextures( [self._texture_object_id] )
312
313 - def draw(self):
314 p = self.parameters # shorthand 315 if p.on: 316 # calculate center 317 center = VisionEgg._get_center(p.position,p.anchor,p.size) 318 if p.mask: 319 gl.glActiveTextureARB(gl.GL_TEXTURE0_ARB) 320 gl.glBindTexture(gl.GL_TEXTURE_1D,self._texture_object_id) 321 322 gl.glEnable(gl.GL_TEXTURE_1D) 323 gl.glDisable(gl.GL_TEXTURE_2D) 324 if p.bit_depth != self.cached_bit_depth: 325 self.calculate_bit_depth_dependencies() 326 327 # Clear the modeview matrix 328 gl.glMatrixMode(gl.GL_MODELVIEW) 329 gl.glPushMatrix() 330 331 # Rotate about the center of the texture 332 gl.glTranslate(center[0], 333 center[1], 334 0) 335 gl.glRotate(p.orientation,0,0,1) 336 337 if p.depth is None: 338 gl.glDisable(gl.GL_DEPTH_TEST) 339 depth = 0.0 340 else: 341 gl.glEnable(gl.GL_DEPTH_TEST) 342 depth = p.depth 343 344 # allow max_alpha value to control blending 345 gl.glEnable( gl.GL_BLEND ) 346 gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA ) 347 348 if p.color2: 349 gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_BLEND) 350 gl.glTexEnvfv(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_COLOR, p.color2) 351 ## alpha is ignored because the texture base internal format is luminance 352 else: 353 gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl