1
2
3
4
5
6
7
8
9
10
11
12 """
13 Stimuli on spheres, including texture maps.
14
15 """
16
17 import math, types
18
19 import logging
20
21 import VisionEgg.Core
22 import VisionEgg.Textures
23 import VisionEgg.Text
24 import VisionEgg.Gratings
25 import VisionEgg.ThreeDeeMath
26 import VisionEgg.ParameterTypes as ve_types
27
28 import numpy
29 import numpy.oldnumeric as Numeric
30 import Image
31
32 import VisionEgg.GL as gl
33
34 __version__ = VisionEgg.release_name
35
37 """Spherical grid of iso-azimuth and iso-elevation lines.
38
39 Parameters
40 ==========
41 anti_aliasing -- (Boolean)
42 Default: True
43 center_azimuth -- (Real)
44 Default: 0.0
45 center_elevation -- (Real)
46 Default: 0.0
47 major_line_color -- (AnyOf(Sequence3 of Real or Sequence4 of Real))
48 Default: (0.0, 0.0, 0.0)
49 major_line_width -- (Real)
50 Default: 2.0
51 minor_line_color -- (AnyOf(Sequence3 of Real or Sequence4 of Real))
52 Default: (0.0, 0.0, 1.0)
53 minor_line_width -- (Real)
54 Default: 1.0
55 my_viewport -- (Instance of <class 'VisionEgg.Core.Viewport'>)
56 Default: (determined at runtime)
57 on -- (Boolean)
58 Default: True
59 text_offset -- (Sequence2 of Real)
60 Default: (3, -2)
61
62 Constant Parameters
63 ===================
64 az_major_spacing -- (Real)
65 Default: 30.0
66 az_minor_spacing -- (Real)
67 Default: 10.0
68 el_major_spacing -- (Real)
69 Default: 30.0
70 el_minor_spacing -- (Real)
71 Default: 10.0
72 font_size -- (UnsignedInteger)
73 Default: 24
74 num_samples_per_circle -- (UnsignedInteger)
75 Default: 100
76 radius -- (Real)
77 Default: 1.0
78 text_anchor -- (String)
79 Default: lowerleft
80 text_color -- (AnyOf(Sequence3 of Real or Sequence4 of Real))
81 Default: (0.0, 0.0, 0.0)
82 use_text -- (Boolean)
83 Default: True
84 """
85
86 parameters_and_defaults = {
87 'on':(True,
88 ve_types.Boolean),
89 'center_azimuth':(0.0,
90 ve_types.Real),
91 'center_elevation':(0.0,
92 ve_types.Real),
93 'minor_line_width':(1.0,
94 ve_types.Real),
95 'major_line_width':(2.0,
96 ve_types.Real),
97 'minor_line_color':((0.0,0.0,1.0),
98 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real),
99 ve_types.Sequence4(ve_types.Real))),
100 'major_line_color':((0.0,0.0,0.0),
101 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real),
102 ve_types.Sequence4(ve_types.Real))),
103 'my_viewport':(None,
104 ve_types.Instance(VisionEgg.Core.Viewport)),
105 'text_offset':((3,-2),
106 ve_types.Sequence2(ve_types.Real)),
107 'anti_aliasing' : ( True,
108 ve_types.Boolean ),
109 }
110
111 constant_parameters_and_defaults = {
112 'use_text':(True,
113 ve_types.Boolean),
114 'radius':(1.0,
115 ve_types.Real),
116 'az_minor_spacing':(10.0,
117 ve_types.Real),
118 'az_major_spacing':(30.0,
119 ve_types.Real),
120 'el_minor_spacing':(10.0,
121 ve_types.Real),
122 'el_major_spacing':(30.0,
123 ve_types.Real),
124 'num_samples_per_circle':(100,
125 ve_types.UnsignedInteger),
126 'font_size':(24,
127 ve_types.UnsignedInteger),
128 'text_color':((0.0,0.0,0.0),
129 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real),
130 ve_types.Sequence4(ve_types.Real))),
131 'text_anchor':('lowerleft',
132 ve_types.String),
133 }
134
135 __slots__ = (
136 'cached_minor_lines_display_list',
137 'cached_major_lines_display_list',
138 'text_viewport',
139 'text_viewport_orig',
140 '_gave_alpha_warning',
141 'labels',
142 'labels_xyz',
143 )
144
146 VisionEgg.Core.Stimulus.__init__(self,**kw)
147 self.cached_minor_lines_display_list = gl.glGenLists(1)
148 self.cached_major_lines_display_list = gl.glGenLists(1)
149 self.__rebuild_display_lists()
150 self.text_viewport = None
151 self._gave_alpha_warning = False
152
154 def get_xyz(theta,phi,radius):
155
156
157 y = radius * math.cos( theta )
158 w = radius * math.sin( theta )
159 x = w * math.cos( phi )
160 z = w * math.sin( phi )
161 return x,y,z
162 def draw_half_great_circle(az):
163 for i in range(cp.num_samples_per_circle/2):
164
165 theta_start = i/float(cp.num_samples_per_circle)*2*math.pi
166 theta_stop = (i+1)/float(cp.num_samples_per_circle)*2*math.pi
167 phi_start = phi_stop = (az-90.0)/180.0*math.pi
168 x_start,y_start,z_start = get_xyz(theta_start,phi_start,cp.radius)
169 x_stop,y_stop,z_stop = get_xyz(theta_stop,phi_stop,cp.radius)
170 gl.glVertex3f(x_start, y_start, z_start)
171 gl.glVertex3f(x_stop, y_stop, z_stop)
172 def draw_iso_elevation_circle(el):
173
174 theta_start = theta_stop = -(el-90) / 180.0 * math.pi
175 for i in range(cp.num_samples_per_circle):
176 phi_start = i/float(cp.num_samples_per_circle)*2*math.pi
177 phi_stop = (i+1)/float(cp.num_samples_per_circle)*2*math.pi
178 x_start,y_start,z_start = get_xyz(theta_start,phi_start,cp.radius)
179 x_stop,y_stop,z_stop = get_xyz(theta_stop,phi_stop,cp.radius)
180 gl.glVertex3f(x_start, y_start, z_start)
181 gl.glVertex3f(x_stop, y_stop, z_stop)
182
183 cp = self.constant_parameters
184
185 azs_major = numpy.concatenate((
186 numpy.arange(0.0,180.0,cp.az_major_spacing),
187 -numpy.arange(0.0,180.0,cp.az_major_spacing)[1:]))
188 azs_minor = numpy.concatenate((
189 numpy.arange(0.0,180.0,cp.az_minor_spacing),
190 -numpy.arange(0.0,180.0,cp.az_minor_spacing)[1:]))
191 els_major = numpy.concatenate((
192 numpy.arange(0.0,90.0,cp.el_major_spacing),
193 -numpy.arange(0.0,90.0,cp.el_major_spacing)[1:]))
194 els_minor = numpy.concatenate((
195 numpy.arange(0.0,90.0,cp.el_minor_spacing),
196 -numpy.arange(0.0,90.0,cp.el_minor_spacing)[1:]))
197
198 gl.glNewList(self.cached_minor_lines_display_list,gl.GL_COMPILE)
199 gl.glBegin(gl.GL_LINES)
200
201 for az in azs_minor:
202 if az in azs_major:
203 continue
204 draw_half_great_circle(az)
205 for el in els_minor:
206 if el in els_major:
207 continue
208 draw_iso_elevation_circle(el)
209 gl.glEnd()
210 gl.glEndList()
211
212 gl.glNewList(self.cached_major_lines_display_list,gl.GL_COMPILE)
213 gl.glBegin(gl.GL_LINES)
214 for az in azs_major:
215 draw_half_great_circle(az)
216 for el in els_major:
217 draw_iso_elevation_circle(el)
218 gl.glEnd()
219 gl.glEndList()
220
221 if cp.use_text:
222 self.labels = []
223 self.labels_xyz = []
224 els_major = list(els_major)+[90.0]
225 for el in els_major:
226 for az in azs_major:
227 theta = -(el-90) / 180.0 * math.pi
228 phi = (az-90.0)/180.0*math.pi
229 x,y,z = get_xyz(theta,phi,cp.radius)
230 self.labels_xyz.append((x,y,z))
231 self.labels.append(
232 VisionEgg.Text.Text( text = '%.0f, %.0f'%(az,el),
233 font_size = cp.font_size,
234 color = cp.text_color,
235 anchor = cp.text_anchor,
236 )
237 )
238 if (el == -90) or (el == 90):
239 self.labels[-1].parameters.text = 'x, %.0f'%(el,)
240 break
241
242 self.labels_xyz = Numeric.array(self.labels_xyz)
243
245 p = self.parameters
246 cp = self.constant_parameters
247 if p.on:
248
249 gl.glDisable( gl.GL_DEPTH_TEST )
250 gl.glDisable( gl.GL_TEXTURE_2D )
251 gl.glMatrixMode(gl.GL_MODELVIEW)
252 gl.glPushMatrix()
253 gl.glRotatef(p.center_azimuth,0.0,-1.0,0.0)
254 gl.glRotatef(p.center_elevation,1.0,0.0,0.0)
255
256 if p.anti_aliasing:
257 if len(p.minor_line_color) == 4 and not self._gave_alpha_warning:
258 if p.minor_line_color[3] != 1.0:
259 logger = logging.getLogger('VisionEgg.SphereMap')
260 logger.warning("The parameter anti_aliasing is "
261 "set to true in the AzElGrid "
262 "stimulus class, but the color "
263 "parameter specifies an alpha "
264 "value other than 1.0. To "
265 "acheive the best anti-aliasing, "
266 "ensure that the alpha value for "
267 "the color parameter is 1.0.")
268 self._gave_alpha_warning = 1
269 if len(p.major_line_color) == 4 and not self._gave_alpha_warning:
270 if p.major_line_color[3] != 1.0:
271 logger = logging.getLogger('VisionEgg.SphereMap')
272 logger.warning("The parameter anti_aliasing is "
273 "set to true in the AzElGrid "
274 "stimulus class, but the color "
275 "parameter specifies an alpha "
276 "value other than 1.0. To "
277 "acheive the best anti-aliasing, "
278 "ensure that the alpha value for "
279 "the color parameter is 1.0.")
280 self._gave_alpha_warning = 1
281 gl.glEnable( gl.GL_LINE_SMOOTH )
282
283 gl.glEnable( gl.GL_BLEND )
284 gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA )
285 else:
286 gl.glDisable( gl.GL_BLEND )
287
288 if len(p.minor_line_color)==3:
289 gl.glColor3f(*p.minor_line_color)
290 elif len(p.minor_line_color)==4:
291 gl.glColor4f(*p.minor_line_color)
292 gl.glLineWidth(p.minor_line_width)
293 gl.glCallList(self.cached_minor_lines_display_list)
294
295 if len(p.major_line_color)==3:
296 gl.glColor3f(*p.major_line_color)
297 elif len(p.major_line_color)==4:
298 gl.glColor4f(*p.major_line_color)
299 gl.glLineWidth(p.major_line_width)
300 gl.glCallList(self.cached_major_lines_display_list)
301
302 if p.anti_aliasing:
303 gl.glDisable( gl.GL_LINE_SMOOTH )
304
305 if cp.use_text:
306 my_view = p.my_viewport
307 if (my_view is None) or (not my_view._is_drawing):
308 raise ValueError('use_text is True, but my_viewport not (properly) assigned')
309
310 if self.text_viewport is None or self.text_viewport_orig != my_view:
311
312 vp = my_view.parameters
313 self.text_viewport = VisionEgg.Core.Viewport(screen=vp.screen,
314 position=vp.position,
315 size=vp.size,
316 anchor=vp.anchor,
317 )
318 lowerleft = VisionEgg._get_lowerleft(vp.position,vp.anchor,vp.size)
319 self.text_viewport.parameters.projection.stateless_translate(-lowerleft[0],-lowerleft[1],0)
320 self.text_viewport_orig = p.my_viewport
321
322
323 my_proj = my_view.parameters.projection
324
325 xyz = self.labels_xyz
326
327 t = VisionEgg.ThreeDeeMath.TransformMatrix()
328 t.rotate( p.center_azimuth,0.0,-1.0,0.0 )
329 t.rotate( p.center_elevation,1.0,0.0,0.0 )
330
331 xyz = t.transform_vertices(self.labels_xyz)
332
333 clip = my_proj.eye_2_clip(xyz)
334 try:
335
336 window_coords = my_view.clip_2_window(clip)
337 all_at_once = True
338 except OverflowError:
339 all_at_once = False
340 draw_labels = []
341 for i in range(len(self.labels)):
342 if clip[i,3] < 0: continue
343 label = self.labels[i]
344 if all_at_once:
345 this_pos = window_coords[i,:2]
346 else:
347 try:
348 window_coords = my_view.clip_2_window(clip[i,:])
349 except OverflowError:
350 continue
351 this_pos = window_coords[:2]
352 label.parameters.position = (this_pos[0] + p.text_offset[0],
353 this_pos[1] + p.text_offset[1])
354 draw_labels.append(label)
355 self.text_viewport.parameters.stimuli = draw_labels
356 self.text_viewport.draw()
357 my_view.make_current()
358 gl.glPopMatrix()
359
360 -class SphereMap(VisionEgg.Textures.TextureStimulusBaseClass):
361 """Mercator mapping of rectangular texture onto sphere.
362
363 Parameters
364 ==========
365 center_azimuth -- (Real)
366 Default: 0.0
367 center_elevation -- (Real)
368 Default: 0.0
369 contrast -- (Real)
370 Default: 1.0
371 on -- (Boolean)
372 Default: True
373 radius -- (Real)
374 Default: 1.0
375 slices -- (UnsignedInteger)
376 Default: 30
377 stacks -- (UnsignedInteger)
378 Default: 30
379 texture -- source of texture data (Instance of <class 'VisionEgg.Textures.Texture'>)
380 Inherited from VisionEgg.Textures.TextureStimulusBaseClass
381 Default: (determined at runtime)
382 texture_mag_filter -- OpenGL filter enum (Integer)
383 Inherited from VisionEgg.Textures.TextureStimulusBaseClass
384 Default: GL_LINEAR (9729)
385 texture_min_filter -- OpenGL filter enum (Integer)
386 Inherited from VisionEgg.Textures.TextureStimulusBaseClass
387 Default: (GL enum determined at runtime)
388 texture_wrap_s -- OpenGL texture wrap enum (Integer)
389 Inherited from VisionEgg.Textures.TextureStimulusBaseClass
390 Default: (GL enum determined at runtime)
391 texture_wrap_t -- OpenGL texture wrap enum (Integer)
392 Inherited from VisionEgg.Textures.TextureStimulusBaseClass
393 Default: (GL enum determined at runtime)
394
395 Constant Parameters
396 ===================
397 internal_format -- format with which OpenGL uses texture data (OpenGL data type enum) (Integer)
398 Default: GL_RGB (6407)
399 mipmaps_enabled -- Are mipmaps enabled? (Boolean)
400 Default: True
401 shrink_texture_ok -- Allow automatic shrinking of texture if too big? (Boolean)
402 Default: False
403 """
404
405 parameters_and_defaults = {
406 'on':(True,
407 ve_types.Boolean),
408 'contrast':(1.0,
409 ve_types.Real),
410 'center_azimuth':(0.0,
411 ve_types.Real),
412 'center_elevation':(0.0,
413 ve_types.Real),
414
415
416 'radius':(1.0,
417 ve_types.Real),
418 'slices':(30,
419 ve_types.UnsignedInteger),
420 'stacks':(30,
421 ve_types.UnsignedInteger)}
422
423 __slots__ = (
424 'cached_display_list',
425 '_cached_radius',
426 '_cached_slices',
427 '_cached_stacks',
428 )
429
434
436 p = self.parameters
437
438 s_gain = p.texture.buf_rf - p.texture.buf_lf
439 t_gain = p.texture.buf_bf - p.texture.buf_tf
440
441 s_offs = p.texture.buf_lf
442 t_offs = p.texture.buf_tf
443
444 gl.glNewList(self.cached_display_list,gl.GL_COMPILE)
445 gl.glBegin(gl.GL_QUADS)
446
447 for stack in range(p.stacks):
448 stack_upper_frac = float(stack+1)/p.stacks
449 stack_lower_frac = float(stack)/p.stacks
450 theta_upper = stack_upper_frac * math.pi
451 theta_lower = stack_lower_frac * math.pi
452 y_upper = p.radius * math.cos( theta_upper )
453 w_upper = p.radius * math.sin( theta_upper )
454 y_lower = p.radius * math.cos( theta_lower )
455 w_lower = p.radius * math.sin( theta_lower )
456 for slice in range(p.slices):
457 slice_start_frac = float(slice)/p.slices
458 slice_stop_frac = float(slice+1)/p.slices
459 phi_start = slice_start_frac * 2 * math.pi
460 phi_stop = slice_stop_frac * 2 * math.pi
461 x_start_upper = w_upper * math.cos(phi_start)
462 x_start_lower = w_lower * math.cos(phi_start)
463 x_stop_upper = w_upper * math.cos(phi_stop)
464 x_stop_lower = w_lower * math.cos(phi_stop)
465 z_start_upper = w_upper * math.sin(phi_start)
466 z_start_lower = w_lower * math.sin(phi_start)
467 z_stop_upper = w_upper * math.sin(phi_stop)
468 z_stop_lower = w_lower * math.sin(phi_stop)
469
470 tex_l = slice_start_frac*s_gain+s_offs
471 tex_r = slice_stop_frac*s_gain+s_offs
472 tex_b = stack_lower_frac*t_gain+t_offs
473 tex_t = stack_upper_frac*t_gain+t_offs
474
475 gl.glTexCoord2f(tex_l,tex_t)
476 gl.glVertex3f(x_start_upper, y_upper, z_start_upper)
477
478 gl.glTexCoord2f(tex_r,tex_t)
479 gl.glVertex3f(x_stop_upper, y_upper, z_stop_upper)
480
481 gl.glTexCoord2f(tex_r,tex_b)
482 gl.glVertex3f(x_stop_lower, y_lower, z_stop_lower)
483
484 gl.glTexCoord2f(tex_l,tex_b)
485 gl.glVertex3f(x_start_lower, y_lower, z_start_lower)
486
487 gl.glEnd()
488 gl.glEndList()
489 self._cached_radius = p.radius
490 self._cached_slices = p.slices
491 self._cached_stacks = p.stacks
492
494 """Redraw the scene on every frame.
495 """
496 p = self.parameters
497
498 if self._cached_radius != p.radius or self._cached_slices != p.slices or self._cached_stacks != p.stacks:
499 self.__rebuild_display_list()
500
501 if p.on:
502
503 gl.glEnable( gl.GL_DEPTH_TEST )
504 gl.glEnable( gl.GL_TEXTURE_2D )
505 gl.glEnable( gl.GL_BLEND )
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523 gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA )
524
525 gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_DECAL)
526
527
528 gl.glMatrixMode(gl.GL_MODELVIEW)
529 gl.glPushMatrix()
530 gl.glColor4f(0.5,0.5,0.5,p.contrast)
531
532 if not self.constant_parameters.mipmaps_enabled:
533 if p.texture_min_filter in VisionEgg.Textures.TextureStimulusBaseClass._mipmap_modes:
534 raise RuntimeError("Specified a mipmap mode in texture_min_filter, but mipmaps not enabled.")
535 self.texture_object.set_min_filter( p.texture_min_filter )
536 self.texture_object.set_mag_filter( p.texture_mag_filter )
537 self.texture_object.set_wrap_mode_s( p.texture_wrap_s )
538 self.texture_object.set_wrap_mode_t( p.texture_wrap_t )
539
540
541 gl.glRotatef(p.center_azimuth,0.0,-1.0,0.0)
542 gl.glRotatef(p.center_elevation,1.0,0.0,0.0)
543
544 gl.glCallList(self.cached_display_list)
545 gl.glPopMatrix()
546
548 """Map 2D sinusoidal grating onto sphere.
549
550 Parameters
551 ==========
552 bit_depth -- precision with which grating is calculated and sent to OpenGL (UnsignedInteger)
553 Inherited from VisionEgg.Gratings.LuminanceGratingCommon
554 Default: 8
555 check_texture_size -- (Boolean)
556 Default: True
557 contrast -- (Real)
558 Default: 1.0
559 grating_center_azimuth -- (Real)
560 Default: 0.0
561 grating_center_elevation -- (Real)
562 Default: 0.0
563 ignore_time -- (Boolean)
564 Default: False
565 lowpass_cutoff_cycles_per_texel -- helps prevent spatial aliasing (Real)
566 Default: 0.5
567 min_filter -- OpenGL filter enum (Integer)
568 Default: GL_LINEAR (9729)
569 num_samples -- (UnsignedInteger)
570 Default: 1024
571 on -- (Boolean)
572 Default: True
573 orientation -- (Real)
574 Default: 0.0
575 phase_at_t0 -- (Real)
576 Default: 0.0
577 radius -- (Real)
578 Default: 1.0
579 slices -- (UnsignedInteger)
580 Default: 30
581 spatial_freq_cpd -- (Real)
582 Default: 0.0277777777778
583 stacks -- (UnsignedInteger)
584 Default: 30
585 t0_time_sec_absolute -- (Real)
586 Default: (determined at runtime)
587 temporal_freq_hz -- (Real)
588 Default: 5.0
589 """
590
591 parameters_and_defaults = {
592 'on':(True,
593 ve_types.Boolean),
594 'contrast':(1.0,
595 ve_types.Real),
596 'spatial_freq_cpd':(1.0/36.0,
597 ve_types.Real),
598 'temporal_freq_hz':(5.0,
599 ve_types.Real),
600 't0_time_sec_absolute':(None,
601 ve_types.Real),
602 'ignore_time':(False,
603 ve_types.Boolean),
604 'phase_at_t0':(0.0,
605 ve_types.Real),
606 'orientation':(0.0,
607 ve_types.Real),
608 'grating_center_azimuth':(0.0,
609 ve_types.Real),
610 'grating_center_elevation':(0.0,
611 ve_types.Real),
612 'check_texture_size':(True,
613 ve_types.Boolean),
614 'lowpass_cutoff_cycles_per_texel':(0.5,
615 ve_types.Real,
616 'helps prevent spatial aliasing'),
617 'min_filter':(gl.GL_LINEAR,
618 ve_types.Integer,
619 "OpenGL filter enum",
620 VisionEgg.ParameterDefinition.OPENGL_ENUM),
621
622 'num_samples':(1024,
623 ve_types.UnsignedInteger),
624
625 'radius':(1.0,
626 ve_types.Real),
627 'slices':(30,
628 ve_types.UnsignedInteger),
629 'stacks':(30,
630 ve_types.UnsignedInteger),
631 }
632
633 __slots__ = (
634 'texture_object_id',
635 'cached_display_list_id',
636 '_cached_num_samples',
637 '_cached_radius',
638 '_cached_slices',
639 '_cached_stacks',
640 )
641
643 VisionEgg.Gratings.LuminanceGratingCommon.__init__(self,**kw)
644
645 if self.parameters.t0_time_sec_absolute is None:
646 self.parameters.t0_time_sec_absolute = VisionEgg.time_func()
647
648 self.texture_object_id = gl.glGenTextures(1)
649 self.__rebuild_texture_object()
650
651 self.cached_display_list_id = gl.glGenLists(1)
652 self.__rebuild_display_list()
653
655 gl.glBindTexture(gl.GL_TEXTURE_1D,self.texture_object_id)
656 p = self.parameters
657
658
659 max_dim = gl.glGetIntegerv(gl.GL_MAX_TEXTURE_SIZE)
660 if p.num_samples > max_dim:
661 raise VisionEgg.Gratings.NumSamplesTooLargeError("Grating num_samples too large for video system.\nOpenGL reports maximum size of %d"%(max_dim,))
662
663 self.calculate_bit_depth_dependencies()
664
665 l = 0.0
666 r = 360.0
667
668 mipmap_level = 0
669 this_mipmap_level_num_samples = p.num_samples
670 while this_mipmap_level_num_samples >= 1:
671 inc = 360.0/float(this_mipmap_level_num_samples)
672 cycles_per_texel = p.spatial_freq_cpd * inc
673 if cycles_per_texel < p.lowpass_cutoff_cycles_per_texel:
674
675 if p.ignore_time:
676 phase = p.phase_at_t0
677 else:
678 t_var = VisionEgg.time_func() - p.t0_time_sec_absolute
679 phase = t_var*p.temporal_freq_hz*360.0 + p.phase_at_t0
680 floating_point_sin = Numeric.sin(2.0*math.pi*p.spatial_freq_cpd*Numeric.arange(l,r,inc,'d')-(phase/180.0*math.pi))*0.5*p.contrast+0.5
681 floating_point_sin = Numeric.clip(floating_point_sin,0.0,1.0)
682 texel_data = (floating_point_sin*self.max_int_val).astype(self.numpy_dtype).tostring()
683 else:
684
685 texel_data = (self.max_int_val*0.5)*Numeric.ones((this_mipmap_level_num_samples,),self.numpy_dtype)
686
687 if p.check_texture_size:
688
689
690
691 gl.glTexImage1D(gl.GL_PROXY_TEXTURE_1D,
692 mipmap_level,
693 self.gl_internal_format,
694 this_mipmap_level_num_samples,
695 0,
696 self.format,
697 self.gl_type,
698 texel_data)
699 if gl.glGetTexLevelParameteriv(gl.GL_PROXY_TEXTURE_1D,0,gl.GL_TEXTURE_WIDTH) == 0:
700 raise NumSamplesTooLargeError("Grating num_samples is too wide for your video system!")
701
702
703 gl.glTexImage1D(gl.GL_TEXTURE_1D,
704 mipmap_level,
705 self.gl_internal_format,
706 this_mipmap_level_num_samples,
707 0,
708 self.format,
709 self.gl_type,
710 texel_data)
711
712
713 this_mipmap_level_num_samples = this_mipmap_level_num_samples/2
714 mipmap_level += 1
715
716
717 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_WRAP_S,gl.GL_REPEAT)
718 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_WRAP_T,gl.GL_REPEAT)
719 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_MAG_FILTER,gl.GL_LINEAR)
720 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_MIN_FILTER,p.min_filter)
721 self._cached_num_samples = p.num_samples
722
724 gl.glNewList(self.cached_display_list_id,gl.GL_COMPILE)
725
726 p = self.parameters
727 gl.glBegin(gl.GL_QUADS)
728
729 for stack in range(p.stacks):
730 stack_upper_frac = float(stack+1)/p.stacks
731 stack_lower_frac = float(stack)/p.stacks
732 theta_upper = stack_upper_frac * math.pi
733 theta_lower = stack_lower_frac * math.pi
734 y_upper = p.radius * math.cos( theta_upper )
735 w_upper = p.radius * math.sin( theta_upper )
736 y_lower = p.radius * math.cos( theta_lower )
737 w_lower = p.radius * math.sin( theta_lower )
738 for slice in range(p.slices):
739 slice_start_frac = float(slice)/p.slices
740 slice_stop_frac = float(slice+1)/p.slices
741 phi_start = slice_start_frac * 2 * math.pi
742 phi_stop = slice_stop_frac * 2 * math.pi
743 x_start_upper = w_upper * math.cos(phi_start)
744 x_start_lower = w_lower * math.cos(phi_start)
745 x_stop_upper = w_upper * math.cos(phi_stop)
746 x_stop_lower = w_lower * math.cos(phi_stop)
747 z_start_upper = w_upper * math.sin(phi_start)
748 z_start_lower = w_lower * math.sin(phi_start)
749 z_stop_upper = w_upper * math.sin(phi_stop)
750 z_stop_lower = w_lower * math.sin(phi_stop)
751
752 tex_l = slice_start_frac
753 tex_r = slice_stop_frac
754 tex_b = 0.0
755 tex_t = 1.0
756
757 gl.glTexCoord2f(tex_l,tex_t)
758 gl.glVertex3f(x_start_upper, y_upper, z_start_upper)
759
760 gl.glTexCoord2f(tex_r,tex_t)
761 gl.glVertex3f(x_stop_upper, y_upper, z_stop_upper)
762
763 gl.glTexCoord2f(tex_r,tex_b)
764 gl.glVertex3f(x_stop_lower, y_lower, z_stop_lower)
765
766 gl.glTexCoord2f(tex_l,tex_b)
767 gl.glVertex3f(x_start_lower, y_lower, z_start_lower)
768
769 gl.glEnd()
770 gl.glEndList()
771 self._cached_radius = p.radius
772 self._cached_slices = p.slices
773 self._cached_stacks = p.stacks
774
776 """Redraw the scene on every frame.
777 """
778 p = self.parameters
779
780 if self._cached_radius != p.radius or self._cached_slices != p.slices or self._cached_stacks != p.stacks:
781 self.__rebuild_display_list()
782
783 if self._cached_num_samples != p.num_samples:
784 self.__rebuild_texture_object()
785
786 if p.on:
787 if p.bit_depth != self.cached_bit_depth:
788 self.calculate_bit_depth_dependencies()
789
790 gl.glEnable( gl.GL_DEPTH_TEST )
791 gl.glEnable( gl.GL_TEXTURE_1D )
792 gl.glDisable( gl.GL_TEXTURE_2D )
793 gl.glDisable( gl.GL_BLEND )
794
795 gl.glBindTexture(gl.GL_TEXTURE_1D,self.texture_object_id)
796 gl.glTexParameteri(gl.GL_TEXTURE_1D,gl.GL_TEXTURE_MIN_FILTER,p.min_filter)
797
798 l = 0.0
799 r = 360.0
800
801 mipmap_level = 0
802 this_mipmap_level_num_samples = p.num_samples
803 while this_mipmap_level_num_samples >= 1:
804 inc = 360.0/float(this_mipmap_level_num_samples)
805 cycles_per_texel = p.spatial_freq_cpd * inc
806 if cycles_per_texel < p.lowpass_cutoff_cycles_per_texel:
807 if p.ignore_time:
808 phase = p.phase_at_t0
809 else:
810 t_var = VisionEgg.time_func() - p.t0_time_sec_absolute
811 phase = t_var*p.temporal_freq_hz*360.0 + p.phase_at_t0
812 floating_point_sin = Numeric.sin(2.0*math.pi*p.spatial_freq_cpd*Numeric.arange(l,r,inc,'d')-(phase/180.0*math.pi))*0.5*p.contrast+0.5
813 floating_point_sin = Numeric.clip(floating_point_sin,0.0,1.0)
814 texel_data = (floating_point_sin*self.max_int_val).astype(self.numpy_dtype).tostring()
815 else:
816 blank = 0.5*Numeric.ones((this_mipmap_level_num_samples,),'d')
817 texel_data = (blank*self.max_int_val).astype(self.numpy_dtype).tostring()
818
819 gl.glTexSubImage1D(gl.GL_TEXTURE_1D,
820 mipmap_level,
821 0,
822 this_mipmap_level_num_samples,
823 self.format,
824 self.gl_type,
825 texel_data)
826
827
828 this_mipmap_level_num_samples = this_mipmap_level_num_samples/2
829 mipmap_level += 1
830
831 gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_REPLACE)
832
833
834 gl.glMatrixMode(gl.GL_MODELVIEW)
835 gl.glPushMatrix()
836
837 gl.glRotatef(p.grating_center_azimuth,0.0,-1.0,0.0)
838 gl.glRotatef(p.grating_center_elevation,1.0,0.0,0.0)
839
840
841 gl.glRotatef(p.orientation,0.0,0.0,1.0)
842
843 gl.glCallList(self.cached_display_list_id)
844
845 gl.glDisable( gl.GL_TEXTURE_1D )
846 gl.glPopMatrix()
847
848 -class SphereWindow(VisionEgg.Gratings.LuminanceGratingCommon):
849 """This draws an opaque sphere with a single window in it.
850
851 This is useful when you need to have a viewport on a 3D scene.
852
853 Parameters
854 ==========
855 bit_depth -- precision with which grating is calculated and sent to OpenGL (UnsignedInteger)
856 Inherited from VisionEgg.Gratings.LuminanceGratingCommon
857 Default: 8
858 num_s_samples -- (UnsignedInteger)
859 Default: 512
860 num_t_samples -- (UnsignedInteger)
861 Default: 512
862 on -- (Boolean)
863 Default: True
864 opaque_color -- (Sequence4 of Real)
865 Default: (0.5, 0.5, 0.5, 0.0)
866 radius -- (Real)
867 Default: 1.0
868 slices -- (UnsignedInteger)
869 Default: 30
870 stacks -- (UnsignedInteger)
871 Default: 30
872 window_center_azimuth -- (Real)
873 Default: 0.0
874 window_center_elevation -- (Real)
875 Default: 0.0
876 window_shape -- can be 'circle', 'gaussian', or 'lat-long rectangle' (String)
877 Default: gaussian
878 window_shape_parameter2 -- (currently only used for) height of lat-long rectangle (in degrees) (Real)
879 Default: 30.0
880 window_shape_radius_parameter -- radius of circle, sigma of gaussian, width of lat-long rectangle (in degrees) (Real)
881 Default: 36.0
882 """
883
884 parameters_and_defaults = {
885 'on':(True,
886 ve_types.Boolean),
887 'window_center_elevation':(0.0,
888 ve_types.Real),
889 'window_center_azimuth':(0.0,
890 ve_types.Real),
891 'opaque_color':((0.5,0.5,0.5,0.0),
892 ve_types.Sequence4(ve_types.Real)),
893
894 'window_shape':('gaussian',
895 ve_types.String,
896 "can be 'circle', 'gaussian', or 'lat-long rectangle'",
897 ),
898 'window_shape_radius_parameter':(36.0,
899 ve_types.Real,
900 'radius of circle, sigma of gaussian, width of lat-long rectangle (in degrees)',
901 ),
902 'window_shape_parameter2':(30.0,
903 ve_types.Real,
904 '(currently only used for) height of lat-long rectangle (in degrees)',
905 ),
906 'num_s_samples':(512,
907 ve_types.UnsignedInteger),
908 'num_t_samples':(512,
909 ve_types.UnsignedInteger),
910
911 'radius':(1.0,
912 ve_types.Real),
913 'slices':(30,
914 ve_types.UnsignedInteger),
915 'stacks':(30,
916 ve_types.UnsignedInteger),
917 }
918
919 __slots__ = (
920 'texture_object_id',
921 'windowed_display_list_id',
922 'opaque_display_list_id',
923 '_cached_window_shape',
924 '_cached_shape_radius_parameter',
925 '_cached_shape_parameter2',
926 '_cached_num_s_samples',
927 '_cached_num_t_samples',
928 '_cached_radius',
929 '_cached_slices',
930 '_cached_stacks',
931 '_texture_s_is_azimuth',
932 )
933
935 VisionEgg.Gratings.LuminanceGratingCommon.__init__(self, **kw )
936
937 p = self.parameters
938
939
940 if p.window_shape == 'lat-long rectangle':
941 self._texture_s_is_azimuth = True
942 else:
943 self._texture_s_is_azimuth = False
944
945 self.texture_object_id = gl.glGenTextures(1)
946 self.__rebuild_texture_object()
947
948 self.windowed_display_list_id = gl.glGenLists(1)
949 self.opaque_display_list_id = gl.glGenLists(1)
950 self.__rebuild_display_lists()
951
953 gl.glBindTexture(gl.GL_TEXTURE_2D,self.texture_object_id)
954 p = self.parameters
955
956
957 max_dim = gl.glGetIntegerv(gl.GL_MAX_TEXTURE_SIZE)
958 if p.num_s_samples > max_dim:
959 raise VisionEgg.Gratings.NumSamplesTooLargeError("SphereWindow num_s_samples too large for video system.\nOpenGL reports maximum size of %d"%(max_dim,))
960 if p.num_t_samples > max_dim:
961 raise VisionEgg.Gratings.NumSamplesTooLargeError("SphereWindow num_t_samples too large for video system.\nOpenGL reports maximum size of %d"%(max_dim,))
962
963 self.calculate_bit_depth_dependencies()
964 self.gl_internal_format = gl.GL_ALPHA
965 self.format = gl.GL_ALPHA
966
967
968
969
970
971 if p.window_shape == 'circle':
972 if self._texture_s_is_azimuth:
973 self.__rebuild_display_lists()
974
975
976 s_axis = (Numeric.arange(p.num_s_samples)/float(p.num_s_samples)-0.5)**2
977 t_axis = (Numeric.arange(p.num_t_samples)/float(p.num_t_samples)-0.5)**2
978 mask = s_axis[Numeric.NewAxis,:] + t_axis[:,Numeric.NewAxis]
979 angle_deg = min(180,p.window_shape_radius_parameter)
980 cartesian_radius = 0.5*math.sin(p.window_shape_radius_parameter/180.0*math.pi)
981 floating_point_window = Numeric.less(mask,cartesian_radius**2)
982 elif p.window_shape == 'gaussian':
983 if self._texture_s_is_azimuth:
984 self.__rebuild_display_lists()
985
986 MIN_EXP = -745.0
987 MAX_EXP = 709.0
988
989 s = Numeric.arange(0.0,p.num_s_samples,1.0,'f')/p.num_s_samples
990 t = Numeric.arange(0.0,p.num_t_samples,1.0,'f')/p.num_t_samples
991 sigma_normalized = p.window_shape_radius_parameter / 90.0 * 0.5
992
993 check_s = -((s-0.5)**2/(2.0*sigma_normalized**2))
994 try:
995
996 val_s = Numeric.exp( check_s )
997 except OverflowError:
998 check_s = Numeric.clip(check_s,MIN_EXP,MAX_EXP)
999 val_s = Numeric.exp( check_s )
1000
1001 check_t = -((t-0.5)**2/(2.0*sigma_normalized**2))
1002 try:
1003 val_t = Numeric.exp( check_t )
1004 except OverflowError:
1005 check_t = Numeric.clip(check_t,MIN_EXP,MAX_EXP)
1006 val_t = Numeric.exp( check_t )
1007 floating_point_window = Numeric.outerproduct(val_t,val_s)
1008 elif p.window_shape == 'lat-long rectangle':
1009 if not self._texture_s_is_azimuth:
1010 self.__rebuild_display_lists()
1011
1012
1013 s_axis = (Numeric.arange(p.num_s_samples)/float(p.num_s_samples)-0.5)*180
1014 s_axis = Numeric.less( abs(s_axis), p.window_shape_radius_parameter*0.5 )
1015
1016
1017
1018 angle_deg = min(90,p.window_shape_parameter2*0.5)
1019 desired_height = math.sin(angle_deg/180.0*math.pi)*0.5
1020 t_axis = Numeric.arange(p.num_t_samples)/float(p.num_t_samples)-0.5
1021 t_axis = Numeric.less(abs(t_axis),desired_height)
1022 floating_point_window = Numeric.outerproduct(t_axis,s_axis)
1023 else:
1024 raise RuntimeError('Unknown window_shape "%s"'%(p.window_shape,))
1025 texel_data = (floating_point_window * self.max_int_val).astype(self.numpy_dtype).tostring()
1026
1027
1028
1029
1030 gl.glTexImage2D(gl.GL_PROXY_TEXTURE_2D,
1031 0,
1032 self.gl_internal_format,
1033 p.num_s_samples,
1034 p.num_t_samples,
1035 0,
1036 self.format,
1037 self.gl_type,
1038 texel_data)
1039 if (gl.glGetTexLevelParameteriv(gl.GL_PROXY_TEXTURE_2D,
1040 0,
1041 gl.GL_TEXTURE_WIDTH) == 0) or (
1042 gl.glGetTexLevelParameteriv(gl.GL_PROXY_TEXTURE_2D,
1043 0,
1044 gl.GL_TEXTURE_HEIGHT) == 0):
1045 raise VisionEgg.Gratings.NumSamplesTooLargeError("SphereWindow num_s_samples or num_t_samples is too large for your video system!")
1046
1047 gl.glTexImage2D(gl.GL_TEXTURE_2D,
1048 0,
1049 self.gl_internal_format,
1050 p.num_s_samples,
1051 p.num_t_samples,
1052 0,
1053 self.format,
1054 self.gl_type,
1055 texel_data)
1056
1057
1058 gl.glTexParameteri(gl.GL_TEXTURE_2D,gl.GL_TEXTURE_WRAP_S,gl.GL_CLAMP_TO_EDGE)
1059 gl.glTexParameteri(gl.GL_TEXTURE_2D,gl.GL_TEXTURE_WRAP_T,gl.GL_CLAMP_TO_EDGE)
1060 gl.glTexParameteri(gl.GL_TEXTURE_2D,gl.GL_TEXTURE_MAG_FILTER,gl.GL_LINEAR)
1061 gl.glTexParameteri(gl.GL_TEXTURE_2D,gl.GL_TEXTURE_MIN_FILTER,gl.GL_LINEAR)
1062
1063 self._cached_window_shape = p.window_shape
1064 self._cached_shape_radius_parameter = p.window_shape_radius_parameter
1065 self._cached_shape_parameter2 = p.window_shape_parameter2
1066 self._cached_num_s_samples = p.num_s_samples
1067 self._cached_num_t_samples = p.num_t_samples
1068
1070 gl.glMatrixMode(gl.GL_MODELVIEW)
1071 gl.glPushMatrix()
1072
1073 p = self.parameters
1074
1075 if p.window_shape == 'lat-long rectangle':
1076 self._texture_s_is_azimuth = True
1077 else:
1078 self._texture_s_is_azimuth = False
1079
1080 gl.glNewList(self.windowed_display_list_id,gl.GL_COMPILE)
1081
1082 gl.glBegin(gl.GL_QUADS)
1083
1084 for stack in range(p.stacks):
1085 stack_upper_frac = float(stack+1)/p.stacks
1086 stack_lower_frac = float(stack)/p.stacks
1087 theta_upper = stack_upper_frac * math.pi
1088 theta_lower = stack_lower_frac * math.pi
1089 y_upper = p.radius * math.cos( theta_upper )
1090 w_upper = p.radius * math.sin( theta_upper )
1091 y_lower = p.radius * math.cos( theta_lower )
1092 w_lower = p.radius * math.sin( theta_lower )
1093 for slice in range(p.slices/2,p.slices):
1094 slice_start_frac = float(slice)/p.slices
1095 slice_stop_frac = float(slice+1)/p.slices
1096 phi_start = slice_start_frac * 2 * math.pi
1097 phi_stop = slice_stop_frac * 2 * math.pi
1098 x_start_upper = w_upper * math.cos(phi_start)
1099 x_start_lower = w_lower * math.cos(phi_start)
1100 x_stop_upper = w_upper * math.cos(phi_stop)
1101 x_stop_lower = w_lower * math.cos(phi_stop)
1102 z_start_upper = w_upper * math.sin(phi_start)
1103 z_start_lower = w_lower * math.sin(phi_start)
1104 z_stop_upper = w_upper * math.sin(phi_stop)
1105 z_stop_lower = w_lower * math.sin(phi_stop)
1106
1107 o = 0.5
1108 g = 0.5 / p.radius
1109
1110 if self._texture_s_is_azimuth:
1111 tex_s_start = slice_start_frac*2-1
1112 tex_s_stop = slice_stop_frac*2-1
1113 else:
1114 tex_s_start = x_start_upper*g+o
1115 tex_s_stop = x_stop_upper*g+o
1116
1117 gl.glTexCoord2f(tex_s_start,y_upper*g+o)
1118 gl.glVertex3f(x_start_upper, y_upper, z_start_upper)
1119
1120 gl.glTexCoord2f(tex_s_stop,y_upper*g+o)
1121 gl.glVertex3f(x_stop_upper, y_upper, z_stop_upper)
1122
1123 gl.glTexCoord2f(tex_s_stop,y_lower*g+o)
1124 gl.glVertex3f(x_stop_lower, y_lower, z_stop_lower)
1125
1126 gl.glTexCoord2f(tex_s_start,y_lower*g+o)
1127 gl.glVertex3f(x_start_lower, y_lower, z_start_lower)
1128
1129 gl.glEnd()
1130 gl.glEndList()
1131
1132 gl.glNewList(self.opaque_display_list_id,gl.GL_COMPILE)
1133
1134 gl.glBegin(gl.GL_QUADS)
1135
1136 for stack in range(p.stacks):
1137 stack_upper_frac = float(stack+1)/p.stacks
1138 stack_lower_frac = float(stack)/p.stacks
1139 theta_upper = stack_upper_frac * math.pi
1140 theta_lower = stack_lower_frac * math.pi
1141 y_upper = p.radius * math.cos( theta_upper )
1142 w_upper = p.radius * math.sin( theta_upper )
1143 y_lower = p.radius * math.cos( theta_lower )
1144 w_lower = p.radius * math.sin( theta_lower )
1145 for slice in range(p.slices/2):
1146 slice_start_frac = float(slice)/p.slices
1147 slice_stop_frac = float(slice+1)/p.slices
1148 phi_start = slice_start_frac * 2 * math.pi
1149 phi_stop = slice_stop_frac * 2 * math.pi
1150 x_start_upper = w_upper * math.cos(phi_start)
1151 x_start_lower = w_lower * math.cos(phi_start)
1152 x_stop_upper = w_upper * math.cos(phi_stop)
1153 x_stop_lower = w_lower * math.cos(phi_stop)
1154 z_start_upper = w_upper * math.sin(phi_start)
1155 z_start_lower = w_lower * math.sin(phi_start)
1156 z_stop_upper = w_upper * math.sin(phi_stop)
1157 z_stop_lower = w_lower * math.sin(phi_stop)
1158
1159 gl.glVertex3f(x_start_upper, y_upper, z_start_upper)
1160
1161 gl.glVertex3f(x_stop_upper, y_upper, z_stop_upper)
1162
1163 gl.glVertex3f(x_stop_lower, y_lower, z_stop_lower)
1164
1165 gl.glVertex3f(x_start_lower, y_lower, z_start_lower)
1166
1167 gl.glEnd()
1168 gl.glEndList()
1169 self._cached_radius = p.radius
1170 self._cached_slices = p.slices
1171 self._cached_stacks = p.stacks
1172 gl.glPopMatrix()
1173
1175 """Redraw the scene on every frame.
1176 """
1177 p = self.parameters
1178
1179 if self._cached_radius != p.radius or self._cached_slices != p.slices or self._cached_stacks != p.stacks:
1180 self.__rebuild_display_lists()
1181
1182 if self._cached_window_shape != p.window_shape or self._cached_shape_radius_parameter != p.window_shape_radius_parameter:
1183 self.__rebuild_texture_object()
1184
1185 if p.window_shape == 'lat-long rectangle' and self._cached_shape_parameter2 != p.window_shape_parameter2:
1186 self.__rebuild_texture_object()
1187
1188 if self._cached_num_s_samples != p.num_s_samples or self._cached_num_t_samples != p.num_t_samples:
1189 self.__rebuild_texture_object()
1190
1191 if p.on:
1192
1193 if p.bit_depth != self.cached_bit_depth:
1194 self.calculate_bit_depth_dependencies()
1195 self.gl_internal_format = gl.GL_ALPHA
1196 self.format = gl.GL_ALPHA
1197
1198 gl.glEnable( gl.GL_DEPTH_TEST )
1199 gl.glEnable( gl.GL_TEXTURE_2D )
1200 gl.glEnable( gl.GL_BLEND )
1201
1202 gl.glBlendFunc( gl.GL_ONE_MINUS_SRC_ALPHA, gl.GL_SRC_ALPHA )
1203
1204 gl.glBindTexture(gl.GL_TEXTURE_2D,self.texture_object_id)
1205 gl.glColor4f( *p.opaque_color )
1206 gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_REPLACE)
1207
1208
1209 gl.glMatrixMode(gl.GL_MODELVIEW)
1210 gl.glPushMatrix()
1211
1212
1213 gl.glRotatef(p.window_center_azimuth,0.0,-1.0,0.0)
1214 gl.glRotatef(p.window_center_elevation,1.0,0.0,0.0)
1215
1216 gl.glCallList(self.windowed_display_list_id)
1217 gl.glCallList(self.opaque_display_list_id)
1218 gl.glPopMatrix()
1219