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.GL_TEXTURE_ENV_MODE, gl.GL_MODULATE) 354 355 if p.t0_time_sec_absolute is None and not p.ignore_time: 356 p.t0_time_sec_absolute = VisionEgg.time_func() 357 358 w = p.size[0] 359 inc = w/float(p.num_samples) 360 if p.ignore_time: 361 phase = p.phase_at_t0 362 else: 363 t_var = VisionEgg.time_func() - p.t0_time_sec_absolute 364 phase = t_var*p.temporal_freq_hz*-360.0 + p.phase_at_t0 365 if p.recalculate_phase_tolerance is None or abs(self._last_phase - phase) > p.recalculate_phase_tolerance: 366 self._last_phase = phase # we're re-drawing the phase at this angle 367 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 368 floating_point_sin = numpy.clip(floating_point_sin,0.0,1.0) # allow square wave generation if contrast > 1 369 texel_data = (floating_point_sin*self.max_int_val).astype(self.numpy_dtype) 370 # PyOpenGL 2.0.1.09 has a bug, so use our own wrapper 371 _vegl.veglTexSubImage1D(gl.GL_TEXTURE_1D, # target 372 0, # level 373 0, # x offset 374 p.num_samples, # width 375 self.format, # format of new texel data 376 self.gl_type, # type of new texel data 377 texel_data) # new texel data 378 if 0: 379 compare_array = numpy.empty(texel_data.shape,dtype=texel_data.dtype) 380 pixels = _vegl.veglGetTexImage(gl.GL_TEXTURE_1D, # target 381 0, # level 382 self.format, # format 383 self.gl_type, # type 384 compare_array) 385 assert numpy.allclose( compare_array, texel_data ) 386 387 h_w = p.size[0]/2.0 388 h_h = p.size[1]/2.0 389 390 l = -h_w 391 r = h_w 392 b = -h_h 393 t = h_h 394 395 # in the case of only color1, 396 # the texel data multiplies color1 to produce a color 397 398 # with color2, 399 # the texel data linearly interpolates between color1 and color2 400 401 gl.glColor4f(p.color1[0],p.color1[1],p.color1[2],p.max_alpha) 402 403 if p.mask: 404 p.mask.draw_masked_quad(0.0,1.0,0.0,1.0, # l,r,b,t for texture coordinates 405 l,r,b,t, # l,r,b,t in eye coordinates 406 depth ) # also in eye coordinates 407 else: 408 # draw unmasked quad 409 gl.glBegin(gl.GL_QUADS) 410 411 gl.glTexCoord2f(0.0,0.0) 412 gl.glVertex3f(l,b,depth) 413 414 gl.glTexCoord2f(1.0,0.0) 415 gl.glVertex3f(r,b,depth) 416 417 gl.glTexCoord2f(1.0,1.0) 418 gl.glVertex3f(r,t,depth) 419 420 gl.glTexCoord2f(0.0,1.0) 421 gl.glVertex3f(l,t,depth) 422 gl.glEnd() # GL_QUADS 423 424 gl.glDisable(gl.GL_TEXTURE_1D) 425 gl.glPopMatrix()
426
427 -class SinGrating3D(LuminanceGratingCommon):
428 """Sine wave grating stimulus texture mapped onto quad in 3D 429 430 This is a general-purpose, realtime sine-wave luminace grating 431 generator. This 3D version doesn't support an orientation 432 parameter. This could be implemented, but for now should be done 433 by orienting the quad in 3D. 434 435 Parameters 436 ========== 437 bit_depth -- precision with which grating is calculated and sent to OpenGL (UnsignedInteger) 438 Inherited from LuminanceGratingCommon 439 Default: 8 440 color1 -- (AnyOf(Sequence3 of Real or Sequence4 of Real)) 441 Default: (1.0, 1.0, 1.0) 442 color2 -- optional color with which to perform interpolation with color1 in RGB space (AnyOf(Sequence3 of Real or Sequence4 of Real)) 443 Default: (determined at runtime) 444 contrast -- (Real) 445 Default: 1.0 446 depth -- (Real) 447 Default: (determined at runtime) 448 depth_test -- perform depth test? (Boolean) 449 Default: True 450 ignore_time -- (Boolean) 451 Default: False 452 lowerleft -- vertex position (units: eye coordinates) (AnyOf(Sequence3 of Real or Sequence4 of Real)) 453 Default: (0.0, 0.0, -1.0) 454 lowerright -- vertex position (units: eye coordinates) (AnyOf(Sequence3 of Real or Sequence4 of Real)) 455 Default: (1.0, 0.0, -1.0) 456 mask -- optional masking function (Instance of <class 'VisionEgg.Textures.Mask2D'>) 457 Default: (determined at runtime) 458 max_alpha -- (Real) 459 Default: 1.0 460 num_samples -- (UnsignedInteger) 461 Default: 512 462 on -- draw stimulus? (Boolean) 463 Default: True 464 pedestal -- (Real) 465 Default: 0.5 466 phase_at_t0 -- (Real) 467 Default: 0.0 468 recalculate_phase_tolerance -- (Real) 469 Default: (determined at runtime) 470 size -- defines coordinate size of grating (in eye coordinates) (Sequence2 of Real) 471 Default: (1.0, 1.0) 472 spatial_freq -- frequency defined relative to coordinates defined in size parameter (units; cycles/eye_coord_unit) (Real) 473 Default: 4.0 474 t0_time_sec_absolute -- (Real) 475 Default: (determined at runtime) 476 temporal_freq_hz -- (Real) 477 Default: 5.0 478 upperleft -- vertex position (units: eye coordinates) (AnyOf(Sequence3 of Real or Sequence4 of Real)) 479 Default: (0.0, 1.0, -1.0) 480 upperright -- vertex position (units: eye coordinates) (AnyOf(Sequence3 of Real or Sequence4 of Real)) 481 Default: (1.0, 1.0, -1.0) 482 """ 483 484 parameters_and_defaults = VisionEgg.ParameterDefinition({ 485 'on':(True, 486 ve_types.Boolean, 487 "draw stimulus?"), 488 'mask':(None, # allows window onto otherwise (tilted) rectangular grating 489 ve_types.Instance(VisionEgg.Textures.Mask2D), 490 "optional masking function"), 491 'contrast':(1.0, 492 ve_types.Real), 493 'pedestal':(0.5, 494 ve_types.Real), 495 'depth':(None, # if not None, turns on depth testing and allows for occlusion 496 ve_types.Real), 497 'size':((1.0,1.0), # in eye coordinates 498 ve_types.Sequence2(ve_types.Real), 499 "defines coordinate size of grating (in eye coordinates)"), 500 'spatial_freq':(4.0, # cycles/eye coord units 501 ve_types.Real, 502 "frequency defined relative to coordinates defined in size parameter (units; cycles/eye_coord_unit)"), 503 'temporal_freq_hz':(5.0, # hz 504 ve_types.Real), 505 't0_time_sec_absolute':(None, # Will be assigned during first call to draw() 506 ve_types.Real), 507 'ignore_time':(False, # ignore temporal frequency variable - allow control purely with phase_at_t0 508 ve_types.Boolean), 509 'phase_at_t0':(0.0, # degrees [0.0-360.0] 510 ve_types.Real), 511 'num_samples':(512, # number of spatial samples, should be a power of 2 512 ve_types.UnsignedInteger), 513 'max_alpha':(1.0, # controls "opacity": 1.0 = completely opaque, 0.0 = completely transparent 514 ve_types.Real), 515 'color1':((1.0, 1.0, 1.0), # alpha is ignored (if given) -- use max_alpha parameter 516 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 517 ve_types.Sequence4(ve_types.Real))), 518 'color2':(None, # perform interpolation with color1 in RGB space. 519 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 520 ve_types.Sequence4(ve_types.Real)), 521 "optional color with which to perform interpolation with color1 in RGB space"), 522 'recalculate_phase_tolerance':(None, # only recalculate texture when phase is changed by more than this amount, None for always recalculate. (Saves time.) 523 ve_types.Real), 524 'depth_test':(True, 525 ve_types.Boolean, 526 "perform depth test?"), 527 'lowerleft':((0.0,0.0,-1.0), # in eye coordinates 528 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 529 ve_types.Sequence4(ve_types.Real)), 530 "vertex position (units: eye coordinates)"), 531 'lowerright':((1.0,0.0,-1.0), # in eye coordinates 532 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 533 ve_types.Sequence4(ve_types.Real)), 534 "vertex position (units: eye coordinates)"), 535 'upperleft':((0.0,1.0,-1.0), # in eye coordinates 536 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 537 ve_types.Sequence4(ve_types.Real)), 538 "vertex position (units: eye coordinates)"), 539 'upperright':((1.0,1.0,-1.0), # in eye coordinates 540 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 541 ve_types.Sequence4(ve_types.Real)), 542 "vertex position (units: eye coordinates)"), 543 }) 544 545 __slots__ = ( 546 '_texture_object_id', 547 '_last_phase', 548 ) 549
550 - def __init__(self,**kw):
551 LuminanceGratingCommon.__init__(self,**kw) 552 553 p = self.parameters # shorthand 554 555 self._texture_object_id = gl.glGenTextures(1) 556 if p.mask: 557 gl.glActiveTextureARB(gl.GL_TEXTURE0_ARB) 558 gl.glBindTexture(gl.GL_TEXTURE_1D,self._texture_object_id) 559 560 # Do error-checking on texture to make sure it will load 561 max_dim = gl.glGetIntegerv(gl.GL_MAX_TEXTURE_SIZE) 562 if p.num_samples > max_dim: 563 raise NumSamplesTooLargeError("Grating num_samples too large for video system.\nOpenGL reports maximum size of %d"%(max_dim,)) 564 565 self.calculate_bit_depth_dependencies() 566 567 w = p.size[0] 568 inc = w/float(p.num_samples) 569 phase = 0.0 # this data won't get used - don't care about phase 570 self._last_phase = phase 571 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 572 floating_point_sin = numpy.clip(floating_point_sin,0.0,1.0) # allow square wave generation if contrast > 1 573 texel_data = (floating_point_sin*self.max_int_val).astype(self.numpy_dtype).tostring() 574 575 # Because the MAX_TEXTURE_SIZE method is insensitive to the current 576 # state of the video system, another check must be done using 577 # "proxy textures". 578 gl.glTexImage1D(gl.GL_PROXY_TEXTURE_1D, # target 579 0, # level 580 self.gl_internal_format, # video RAM internal format 581 p.num_samples, # width 582 0, # border 583 self.format, # format of texel data 584 self.gl_type, # type of texel data 585 texel_data) # texel data (irrelevant for proxy) 586 if gl.glGetTexLevelParameteriv(gl.GL_PROXY_TEXTURE_1D, # Need PyOpenGL >= 2.0 587 0, 588 gl.GL_TEXTURE_WIDTH) == 0: 589 raise NumSamplesTooLargeError("Grating num_samples is too wide for your video system!") 590 591 # If we got here, it worked and we can load the texture for real. 592 gl.glTexImage1D(gl.GL_TEXTURE_1D, # target 593 0, # level 594 self.gl_internal_format, # video RAM internal format 595 p.num_samples, # width 596 0, # border 597 self.format, # format of texel data 598 self.gl_type, # type of texel data 599 texel_data) # texel data 600 601 # Set texture object defaults 602 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_WRAP_S,gl.GL_CLAMP_TO_EDGE) 603 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_WRAP_T,gl.GL_CLAMP_TO_EDGE) 604 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_MAG_FILTER,gl.GL_LINEAR) 605 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_MIN_FILTER,gl.GL_LINEAR) 606 607 if p.color2 is not None: 608 if VisionEgg.Core.gl_renderer == 'ATi Rage 128 Pro OpenGL Engine' and VisionEgg.Core.gl_version == '1.1 ATI-1.2.22': 609 logger = logging.getLogger('VisionEgg.Gratings') 610 logger.warning("Your video card and driver have known " 611 "bugs which prevent them from rendering " 612 "color gratings properly.")
613
614 - def __del__(self):
615 gl.glDeleteTextures( [self._texture_object_id] )
616
617 - def draw(self):
618 p = self.parameters # shorthand 619 if p.on: 620 if p.mask: 621 gl.glActiveTextureARB(gl.GL_TEXTURE0_ARB) 622 if p.depth_test: 623 gl.glEnable(gl.GL_DEPTH_TEST) 624 else: 625 gl.glDisable(gl.GL_DEPTH_TEST) 626 gl.glBindTexture(gl.GL_TEXTURE_1D,self._texture_object_id) 627 gl.glEnable(gl.GL_TEXTURE_1D) 628 gl.glDisable(gl.GL_TEXTURE_2D) 629 if p.bit_depth != self.cached_bit_depth: 630 self.calculate_bit_depth_dependencies() 631 632 # allow max_alpha value to control blending 633 gl.glEnable( gl.GL_BLEND ) 634 gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA ) 635 636 if p.color2: 637 gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_BLEND) 638 gl.glTexEnvfv(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_COLOR, p.color2) 639 ## alpha is ignored because the texture base internal format is luminance 640 else: 641 gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_MODULATE) 642 643 if p.t0_time_sec_absolute is None and not p.ignore_time: 644 p.t0_time_sec_absolute = VisionEgg.time_func() 645 646 w = p.size[0] 647 inc = w/float(p.num_samples) 648 if p.ignore_time: 649 phase = p.phase_at_t0 650 else: 651 t_var = VisionEgg.time_func() - p.t0_time_sec_absolute 652 phase = t_var*p.temporal_freq_hz*-360.0 + p.phase_at_t0 653 if p.recalculate_phase_tolerance is None or abs(self._last_phase - phase) > p.recalculate_phase_tolerance: 654 self._last_phase = phase # we're re-drawing the phase at this angle 655 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 656 floating_point_sin = numpy.clip(floating_point_sin,0.0,1.0) # allow square wave generation if contrast > 1 657 texel_data = (floating_point_sin*self.max_int_val).astype(self.numpy_dtype).tostring() 658 659 gl.glTexSubImage1D(gl.GL_TEXTURE_1D, # target 660 0, # level 661 0, # x offset 662 p.num_samples, # width 663 self.format, # format of new texel data 664 self.gl_type, # type of new texel data 665 texel_data) # new texel data 666 667 # in the case of only color1, 668 # the texel data multiplies color1 to produce a color 669 670 # with color2, 671 # the texel data linearly interpolates between color1 and color2 672 673 gl.glColor4f(p.color1[0],p.color1[1],p.color1[2],p.max_alpha) 674 675 if p.mask: 676 p.mask.draw_masked_quad_3d(0.0,1.0,0.0,1.0, # for texture coordinates 677 p.lowerleft,p.lowerright,p.upperright,p.upperleft) 678 else: 679 # draw unmasked quad 680 gl.glBegin(gl.GL_QUADS) 681 682 gl.glTexCoord2f(0.0,0.0) 683 gl.glVertex3f(*p.lowerleft) 684 685 gl.glTexCoord2f(1.0,0.0) 686 gl.glVertex3f(*p.lowerright) 687 688 gl.glTexCoord2f(1.0,1.0) 689 gl.glVertex3f(*p.upperright) 690 691 gl.glTexCoord2f(0.0,1.0) 692 gl.glVertex3f(*p.upperleft) 693 gl.glEnd() # GL_QUADS 694 695 gl.glDisable(gl.GL_TEXTURE_1D)
696
697 -class NumSamplesTooLargeError( RuntimeError ):
698 pass
699