def setPicking(self, tf): """ Controls glnames-as-color drawing mode for mouseover picking. There seems to be no way to access the GL name stack in shaders. Instead, for mouseover, draw shader primitives with glnames as colors in glRenderMode(GL_RENDER), then read back the pixel color (glname) and depth value. @param tf: Boolean, draw glnames-as-color if True. """ # Shader needs to be active to set uniform variables. wasActive = self._active if not wasActive: self.setActive(True) pass glUniform1iARB(self._uniform("draw_for_mouseover"), int(tf)) if not wasActive: self.setActive(False) pass return
def setupTransforms(self, transforms): # note: this is only called from test_drawing.py (as of before 090302) """ Fill a block of transforms. Depending on the setting of TEXTURE_XFORMS and UNIFORM_XFORMS, the transforms are either in texture memory, or in a uniform array of mat4s ("constant memory"), or unsupported (error if we need any here). @param transforms: A list of transform matrices, where each transform is a flattened list (or Numpy array) of 16 numbers. """ self.n_transforms = nTransforms = len(transforms) if not self.supports_transforms(): assert not nTransforms, "%r doesn't support transforms" % self return self.setActive(True) # Must activate before setting uniforms. assert self._has_uniform("n_transforms") # redundant with following glUniform1iARB(self._uniform("n_transforms"), self.n_transforms) # The shader bypasses transform logic if n_transforms is 0. # (Then location coordinates are in global modeling coordinates.) if nTransforms > 0: if UNIFORM_XFORMS: # Load into constant memory. The GL_EXT_bindable_uniform # extension supports sharing this array of mat4s through a VBO. # XXX Need to bank-switch this data if more than N_CONST_XFORMS. C_transforms = numpy.array(transforms, dtype = numpy.float32) glUniformMatrix4fvARB(self._uniform("transforms"), # Don't over-run the array size. min(len(transforms), N_CONST_XFORMS), GL_TRUE, # Transpose. C_transforms) elif TEXTURE_XFORMS: # Generate a texture ID and bind the texture unit to it. self.transform_memory = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, self.transform_memory) ## These seem to have no effect with a vertex shader. ## glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) ## glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) # XXX Needed? glEnable(GL_TEXTURE_2D) # Load the transform data into the texture. # # Problem: SIGSEGV kills Python in gleTextureImagePut under # glTexImage2D with more than 250 transforms (16,000 bytes.) # Maybe there's a 16-bit signed size calculation underthere, that's # overflowing the sign bit... Work around by sending transforms to # the texture unit in batches with glTexSubImage2D.) glTexImage2D(GL_TEXTURE_2D, 0, # Level zero - base image, no mipmap. GL_RGBA32F_ARB, # Internal format is floating point. # Column major storage: width = N, height = 4 * RGBA. nTransforms, 4 * 4, 0, # No border. # Data format and type, null pointer to allocate space. GL_RGBA, GL_FLOAT, None) # XXX Split this off into a setTransforms method. batchSize = 250 nBatches = (nTransforms + batchSize-1) / batchSize for i in range(nBatches): xStart = batchSize * i xEnd = min(nTransforms, xStart + batchSize) xSize = xEnd - xStart glTexSubImage2D(GL_TEXTURE_2D, 0, # Subimage x and y offsets and sizes. xStart, 0, xSize, 4 * 4, # List of matrices is flattened into a sequence. GL_RGBA, GL_FLOAT, transforms[xStart:xEnd]) continue # Read back to check proper loading. if CHECK_TEXTURE_XFORM_LOADING: mats = glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT) nMats = len(mats) print "setupTransforms\n[[", for i in range(nMats): nElts = len(mats[i]) perLine = 8 nLines = (nElts + perLine-1) / perLine for line in range(nLines): jStart = perLine * line jEnd = min(nElts, jStart + perLine) for j in range(jStart, jEnd): print "%.2f" % mats[i][j], continue if line < nLines-1: print "\n ", pass if i < nMats-1: print "]\n [", pass continue print "]]" pass else: # should never happen if SUPPORTS_XFORMS is defined correctly assert 0, "can't setupTransforms unless UNIFORM_XFORMS or TEXTURE_XFORMS is set" pass self.setActive(False) # Deactivate again. return
def setupDraw(self, highlighted = False, selected = False, patterning = True, highlight_color = None, opacity = 1.0): """ Set up for hover-highlighting and selection drawing styles. There is similar code in CSDL.draw(), which has similar arguments. XXX Does Solid and halo now, need to implement patterned drawing too. """ # Shader needs to be active to set uniform variables. wasActive = self._active if not wasActive: self.setActive(True) pass patterned_highlighting = (False and # XXX patterning and isPatternedDrawing(highlight = highlighted)) # note: patterned_highlighting variable is not yet used here [bruce 090304 comment] halo_selection = (selected and env.prefs[selectionColorStyle_prefs_key] == SS_HALO) halo_highlighting = (highlighted and env.prefs[hoverHighlightingColorStyle_prefs_key] == HHS_HALO) # Halo drawing style is used for hover-highlighing and halo-selection. drawing_style = DS_NORMAL # Solid drawing by default. if halo_highlighting or halo_selection: drawing_style = DS_HALO # Halo drawing was first implemented with wide-line drawing, which # extends to both sides of the polygon edge. The halo is actually # half the wide-line width that is specified by the setting. # XXX The setting should be changed to give the halo width instead. halo_width = env.prefs[haloWidth_prefs_key] / 2.0 # The halo width is specified in viewport pixels, as is the window # width the viewport transform maps onto. In post-projection and # clipping normalized device coords (+-1), it's a fraction of the # window half-width of 1.0 . ndc_halo_width = halo_width / (self.window_width / 2.0) glUniform1fARB(self._uniform("ndc_halo_width"), ndc_halo_width) elif highlighted or selected: drawing_style = DS_NORMAL # Non-halo highlighting or selection. glUniform1iARB(self._uniform("drawing_style"), drawing_style) # Color for selection or highlighted drawing. override_color = None if highlighted: if highlight_color is None: # Default highlight color. override_color = env.prefs[hoverHighlightingColor_prefs_key] else: # Highlight color passed as an argument. override_color = highlight_color elif selected: override_color = env.prefs[selectionColor_prefs_key] pass if override_color: if len(override_color) == 3: override_color += (opacity,) pass glUniform4fvARB(self._uniform("override_color"), 1, override_color) pass if not wasActive: self.setActive(False) pass return
def configShader(self, glpane): """ Fill in uniform variables in the shader self, before using it to draw. @param glpane: The current glpane, containing NE1 graphics context information related to the drawing environment. This is used to find proper values for uniform variables we set in the shader. """ # Can't do anything good after an error loading the shader programs. if self.error: return # Shader needs to be active to set uniform variables. wasActive = self._active if not wasActive: self.setActive(True) pass # Debugging control. if self._has_uniform_debug_code: # review: use _has_uniform("debug_code") instead? glUniform1iARB( self._uniform("debug_code"), int(debug_pref("GLPane: shader debug graphics?", Choice_boolean_False, prefs_key = True))) # Default override_opacity, multiplies the normal color alpha component. glUniform1fARB(self._uniform("override_opacity"), 1.0) # Russ 081208: Consider caching the glpane pointer. GLPane_minimal # inherits from QGLWidget, which includes the OpenGL graphics context. # Currently we share 'display list context' and related information # across two kinds of OpenGL contexts, the main GLPane and the # ThumbViews used to select atom types, show clipboard parts, and maybe # more. In the future it may be more complicated. Then we may need to # be more specific about accounting for what's in particular contexts. # XXX Hook in full NE1 lighting scheme and material settings. # Material is [ambient, diffuse, specular, shininess]. glUniform4fvARB(self._uniform("material"), 1, [0.3, 0.6, 0.5, 20.0]) glUniform1iARB(self._uniform("perspective"), (1, 0)[glpane.ortho]) # See GLPane._setup_projection(). vdist = glpane.vdist # See GLPane_minimal.setDepthRange_Normal(). near = vdist * (glpane.near + glpane.DEPTH_TWEAK) far = vdist * glpane.far glUniform4fvARB(self._uniform("clip"), 1, [near, far, 0.5*(far + near), 1.0/(far - near)]) # The effect of setDepthRange_Highlighting() is done as the shaders # set the gl_FragDepth during a highlighted drawing style. glUniform1fARB(self._uniform("DEPTH_TWEAK"), glpane.DEPTH_TWEAK) # Pixel width of window for halo drawing calculations. self.window_width = glpane.width # Single light for now. # XXX Get NE1 lighting environment state. glUniform4fvARB(self._uniform("intensity"), 1, [1.0, 0.0, 0.0, 0.0]) light0 = A([-1.0, 1.0, 1.0]) glUniform3fvARB(self._uniform("light0"), 1, light0) # Blinn shading highlight vector, halfway between the light and the eye. eye = A([0.0, 0.0, 1.0]) halfway0 = norm((eye + light0) / 2.0) glUniform3fvARB(self._uniform("light0H"), 1, halfway0) if not wasActive: self.setActive(False) return