def drawbrick(color, center, axis, l, h, w, opacity=1.0): if len(color) == 3: color = (color[0], color[1], color[2], opacity) if opacity != 1.0: glDepthMask(GL_FALSE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) apply_material(color) glPushMatrix() glTranslatef(center[0], center[1], center[2]) ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes ## display problem on some platforms angle = -acos(axis[2]) * 180.0 / pi if (axis[2] * axis[2] >= 1.0): glRotate(angle, 0.0, 1.0, 0.0) else: glRotate(angle, axis[1], -axis[0], 0.0) glScale(h, w, l) #bruce 060302 revised the contents of solidCubeList while fixing bug 1595 glCallList(drawing_globals.solidCubeList) if opacity != 1.0: glDisable(GL_BLEND) glDepthMask(GL_TRUE) glPopMatrix() return
def draw_sorted(sorted_by_color): #russ 080320: factored out of finish(). """ Traverse color-sorted lists, invoking worker procedures. """ objects_drawn = 0 # Keep track and return. glEnable(GL_LIGHTING) for color, funcs in sorted_by_color.iteritems(): opacity = color[3] if opacity == -1: #piotr 080429: Opacity == -1 signals the "unshaded color". # Also, see my comment in "schedule". glDisable(GL_LIGHTING) # Don't forget to re-enable it! glColor3fv(color[:3]) else: apply_material(color) pass for func, params, name in funcs: objects_drawn += 1 if name != 0: glPushName(name) func(params) if name != 0: glPopName() pass continue if opacity == -1: glEnable(GL_LIGHTING) continue return objects_drawn
def drawbrick(color, center, axis, l, h, w, opacity = 1.0): if len(color) == 3: color = (color[0], color[1], color[2], opacity) if opacity != 1.0: glDepthMask(GL_FALSE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) apply_material(color) glPushMatrix() glTranslatef(center[0], center[1], center[2]) ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes ## display problem on some platforms angle = -acos(axis[2])*180.0/pi if (axis[2]*axis[2] >= 1.0): glRotate(angle, 0.0, 1.0, 0.0) else: glRotate(angle, axis[1], -axis[0], 0.0) glScale(h, w, l) #bruce 060302 revised the contents of solidCubeList while fixing bug 1595 glCallList(drawing_globals.solidCubeList) if opacity != 1.0: glDisable(GL_BLEND) glDepthMask(GL_TRUE) glPopMatrix() return
def use_color(color): if use_apply_material: # This makes the colors visible even when lighting is enabled. apply_material(color) else: # Old code did this. These colors are only visible when lighting is # not enabled. glColor3fv(color) pass return
def schedule(color, func, params): # staticmethod if ColorSorter.sorting: ColorSorter._add_to_sorter(color, func, params) else: ColorSorter._immediate += 1 # for benchmark/debug stats, mostly # 20060216 We know we can do this here because the stack is # only ever one element deep name = ColorSorter._gl_name_stack[-1] if name: glPushName(name) ## Don't check in immediate drawing, e.g. preDraw_glselect_dict. ## else: ## print "bug_1: attempt to push non-glname", name #Apply appropriate opacity for the object if it is specified #in the 'color' param. (Also do necessary things such as #call glBlendFunc it. -- Ninad 20071009 if len(color) == 4: opacity = color[3] else: opacity = 1.0 if opacity >= 0.0 and opacity != 1.0: glDepthMask(GL_FALSE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) elif opacity == -1: # piotr 080429: I replaced the " < 0" condition with " == -1" # The opacity flag is now used to signal either "unshaded # colors" (opacity == -1) or "multicolor object" (opacity == -2) glDisable(GL_LIGHTING) # Don't forget to re-enable it! glColor3fv(color[:3]) pass apply_material(color) func(params) # Call the draw worker function. if opacity > 0.0 and opacity != 1.0: glDisable(GL_BLEND) glDepthMask(GL_TRUE) elif opacity == -1: # piotr 080429: See my comment above. glEnable(GL_LIGHTING) if name: glPopName() return
def _draw_sorted(sorted_by_color): #russ 080320: factored out of finish(). """ Traverse color-sorted lists, invoking worker procedures. """ ### REVIEW: still needed? does this have some duplicated code with # parent_csdl.finish? If so, has this been maintained as that's been # modified? [bruce 090224 questions] glEnable(GL_LIGHTING) for color, funcs in sorted_by_color.iteritems(): opacity = color[3] if opacity == -1: #piotr 080429: Opacity == -1 signals the "unshaded color". # Also, see my comment in "schedule". glDisable(GL_LIGHTING) # reenabled below glColor3fv(color[:3]) else: apply_material(color) pass for func, params, name in funcs: if name: glPushName(name) else: pass ## print "bug_4: attempt to push non-glname", name func(params) # Call the draw worker function. if name: glPopName() pass continue if opacity == -1: glEnable(GL_LIGHTING) continue return
def draw_vane( bond, a1p, a2p, ord_pi, rad, col ): """ Draw a vane (extending on two opposite sides of the bond axis) [#doc more]; use ord_pi to determine how intense it is (not yet sure how, maybe by mixing in bgcolor??); a1p and a2p should be unit vectors perp to bond and no more than 90 degrees apart when seen along it; they should be in the bond's coordinate system. rad is inner radius of vanes, typically the cylinder radius for the sigma bond graphic. If col is not boolean false, use it as the vane color; otherwise, use a constant color which might be influenced by the pi orbital occupancy. """ from utilities.debug_prefs import debug_pref from utilities.debug_prefs import Choice_boolean_True, Choice_boolean_False ## twisted = debug_pref('pi vanes/ribbons', Choice_boolean_False) # one of ['multicyl','vane','ribbon'] pi_bond_style = env.prefs[ pibondStyle_prefs_key] twisted = (pi_bond_style == 'ribbon') poles = debug_pref('pi vanes/poles', Choice_boolean_True) draw_outer_edges = debug_pref('pi vanes/draw edges', Choice_boolean_True) #bruce 050730 new feature, so that edge-on vanes are still visible draw_normals = debug_pref('pi vanes/draw normals', Choice_boolean_False) print_vane_params = debug_pref('pi vanes/print params', Choice_boolean_False) if print_vane_params: print "draw vane",a1p,vlen(a1p),a2p,vlen(a2p),ord_pi if twisted: d12 = dot(a1p, a2p) ## assert d12 >= 0.0 if d12 < 0.0: d12 = 0.0 if d12 > 1.0: d12 = 1.0 twist = math.acos(d12) # in radians # this is numerically inaccurate (since d12 is) near d12 == 1.0, but # that's ok, since it's only compared to threshholds (by ceil()) # which correspond to d12 values not near 1.0. # (#e btw, we could optim the common case (ntwists == 1) by # inverting this comparison to get the equivalent threshhold for # d12.) maxtwist = MAXTWIST # debug_pref doesn't yet have a PrefsType for this # number of segments needed, to limit each segment's twist to MAXTWIST ntwists = max(1, int( math.ceil( twist / maxtwist ) )) pass if col: color = col else: #bruce 050804: initial test of bond color prefs; inadequate in several # ways ###@@@ from foundation.preferences import prefs_context prefs = prefs_context() from utilities.prefs_constants import bondVaneColor_prefs_key #k I hope this color tuple of floats is in the correct prefs format color = prefs.get(bondVaneColor_prefs_key) # protect following code from color being None (which causes bus error, # maybe in PyOpenGL) assert len(color) == 3 ###@@@ it would be much faster to update this pref (or almost any # graphics color pref) if the OpenGL command to set the color was in its # own display list, redefined when the redraw starts, and called from # inside every other display list that needs it. Then when you changed # it, gl_update would be enough -- the chunk display lists would not # need to be remade. ###@@@ problems include: # - being fast enough # + dflt should be specified in just one place, and earlier than in this # place, so it can show up in prefs ui before this runs (in fact, even # earlier than when this module is first imported, which might be only # when needed), # - existing prefs don't have all the color vars needed (eg no # toolong-highlighted color) # - being able to track them only when finally used, not when pulled # into convenience vars before final use -- this might even be an # issue if we precompute a formula from a color-pref, but only count # it as used if that result is used. (we could decide to track the # formula res as a separate thing, i suppose) ## a1pos = bond.atom1.posn() ## a2pos = bond.atom2.posn() a1pos, c1, center, c2, a2pos, toolong = bond.geom if not toolong: c1 = c2 = center # don't know if needed x_axis = a2pos - a1pos # from 1 to 2.5, with 1 moved out to shrink width according to ord_pi width = 1.5 * ord_pi inner, outer = 2.5 - width, 2.5 radius_pairs = [(outer, inner, outer), (-inner, -outer, -outer)] # the order within each pair matters, since it affects the polys drawn # below being CW or CCW! but for purposes of edges, we also have to # know which one is *really* outer... thus the third elt (edge_outer) # of the tuple. # OpenGL code #e could optim this to use Numeric calcs and OpenGL vertex array, with # vertex normals and smooth shading, maybe even color ramp of some kind... #e want polygon outlines? #e want a 1d texture to emphasize the vane's ribbonness & help show ord_pi? glDisable(GL_CULL_FACE) #bruce 051215 use apply_material(color) instead of glMaterialfv, partly to # prevent bug of passing 3-tuple to glMaterialfv, partly to make the vanes # appear specular, partly to thereby fix bug 1216 (which was probably caused # by not setting specular color here, thus letting it remain from whatever # happened to be drawn just before). If we decide vanes should *not* appear # specular, we have to actively turn off specular color here rather than # ignoring the issue. One way would be to create and use some new # functionality like apply_material(color, specular=False). apply_material(color) # gl args partly guessed #e should add specularity, shininess... ## glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color) glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) # For vane lighting to be correct, two-sided polygon lighting is # required, and every polygon's vertex winding order (CCW) has to match # its normal vector, as both are produced by the following code. This # means that any changes to the orders of lists of vertices or vectors # in this code have to be considered carefully. But it's ok if a1p and # a2p are negated (fortunately, since calling code arbitrarily negates # them), since this reverses the poly scan directions in two ways at # once (e.g. via pvec and perpvec in the quads case below). (For ribbon # option, it's only ok if they're negated together; for quads case, # independent negation is ok. I'm pretty sure calling code only negates # them together.) [bruce 050725] for outer, inner, edge_outer in radius_pairs: normals = [] edgeverts = [] if twisted: glBegin(GL_TRIANGLE_STRIP) for i in range(1+ntwists): t = float(i) / ntwists # 0.0 to 1.0 # one minus t (python syntax doesn't let me name it just 1mt) _1mt = 1.0 - t #e could optimize, not sure it matters axispos = _1mt * a1pos + t * a2pos # let it get smaller in the middle for large twist (rather than # using angles in calc) pvec = _1mt * a1p + t * a2p # (rationale: shows weakness of bond. real reason: programmer is # in a hurry.) #e btw, it might be better to show twist by mismatch of # larger rectangular vanes, in the middle; and it's faster # to draw. # Could also "* ord_pi" rather than using color, if we worked # out proper min radius. ## pvec *= (rad * 2.5) perpvec = norm(cross(x_axis, pvec)) # test shows this is needed not only for smoothness, but to make # the lighting work at all glNormal3fv( perpvec) outervert = axispos + pvec * rad * outer innervert = axispos + pvec * rad * inner glVertex3fv( outervert) ## not needed, since the same normal as above ## glNormal3fv( perpvec) glVertex3fv( innervert) #e color? want to smooth-shade it using atom colors, or the # blue/gray for bond order, gray in center? if draw_normals: normals.append(( axispos + pvec * rad * edge_outer, perpvec )) if draw_outer_edges: edgeverts.append( axispos + pvec * rad * edge_outer ) glEnd() else: glBegin(GL_QUADS) for axispos, axispos_c, pvec, normalfactor in \ [(a1pos,c1,a1p,-1), (a2pos,c2,a2p,1)]: perpvec = norm(cross(x_axis, pvec)) * normalfactor glNormal3fv( perpvec) glVertex3fv( axispos + pvec * rad * inner) glVertex3fv( axispos + pvec * rad * outer) glVertex3fv( axispos_c + pvec * rad * outer) # This (axispos_c + pvec * rad * outer) would be the corner # we connect by a line, even when not draw_outer_edges, if # outer == edge_outer -- but it might or might not be. glVertex3fv( axispos_c + pvec * rad * inner) if draw_normals: normals.append(( axispos/2.0 + axispos_c/2.0 + pvec * rad * edge_outer, perpvec )) if draw_outer_edges: # Kluge to reverse order of first loop body but not second. edgeverts.reverse() edgeverts.append( axispos_c + pvec * rad * edge_outer) edgeverts.append( axispos + pvec * rad * edge_outer) else: # At least connect the halves of each vane, so that twist # doesn't make them look like 2 vanes. edgeverts.append( axispos_c + pvec * rad * edge_outer) glEnd() ## glBegin(GL_LINES) ## glColor3fv(color) ## for axispos, axispos_c, pvec in [(a1pos,c1,a1p), (a2pos,c2,a2p)]: ## glVertex3fv( axispos_c + pvec * rad * outer) ## glEnd() glDisable(GL_LIGHTING) # for lines... don't know if this matters if poles: glBegin(GL_LINES) glColor3fv(color) for axispos, pvec in [(a1pos,a1p), (a2pos,a2p)]: glVertex3fv( axispos + pvec * rad * outer) glVertex3fv( axispos + pvec * rad * -outer) glEnd() if normals: glBegin(GL_LINES) glColor3fv(white) for base, vec in normals: glVertex3fv(base) glVertex3fv(base + vec) glEnd() if edgeverts: glBegin(GL_LINE_STRIP) glColor3fv(color) for vert in edgeverts: glVertex3fv(vert) glEnd() glEnable(GL_LIGHTING) glEnable(GL_CULL_FACE) glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE) return
def draw( self, highlighted=False, selected=False, patterning=True, highlight_color=None, draw_shader_primitives=True, # bruce 090312 renamed from draw_primitives transform_nonshaders=True, # bruce 090312 renamed from transform_DLs ): """ Simple all-in-one interface to CSDL drawing. Allocate a CSDL in the parent class and fill it with the ColorSorter: self.csdl = ColorSortedDisplayList() ColorSorter.start(glpane, self.csdl) drawsphere(...), drawcylinder(...), drawpolycone(...), and so on. ColorSorter.finish() Then when you want to draw the display lists call csdl.draw() with the desired options: @param highlighted: Whether to draw highlighted. @param selected: Whether to draw selected. @param patterning: Whether to apply patterned drawing styles for highlighting and selection, according to the prefs settings. If not set, it's as if the solid-color prefs are chosen. @param highlight_color: Option to over-ride the highlight color set in the color scheme preferences. @param draw_shader_primitives: Whether to draw our shader primitives. Defaults to True. @param transform_nonshaders: Whether to apply self.transformControl to our non-shader drawing (such as DLs). Defaults to True. """ patterned_highlighting = patterning and isPatternedDrawing(highlight=highlighted) halo_selection = selected and env.prefs[selectionColorStyle_prefs_key] == SS_HALO halo_highlighting = highlighted and env.prefs[hoverHighlightingColorStyle_prefs_key] == HHS_HALO # KLUGES which should be replaced by our having suitable new attrs, # such as glpane or glprefs or glresourcecontext (replacing drawing_globals): drawing_phase = drawing_globals.drawing_phase # kluge in CSDL.draw # (the other kluge is not having glpane.glprefs to pass to apply_material, # in draw; we do have glpane in finish but no point in using it there # until we have it in .draw too, preferably by attr rather than arg # (should review that opinion).) # Russ 081128 (clarified, bruce 090218): # # GLPrimitiveSet.draw() calls this method (CSDL.draw) on the CSDLs # in its _CSDLs_with_nonshader_drawing attribute (a list of CSDLs), # passing draw_shader_primitives = False to only draw the DLs, and # transform_nonshaders = False to avoid redundantly applying their # TransformControls. # # It gathers the shader primitives in a set of CSDLs into one big # drawIndex per primitive type, and draws each drawIndex in a big batch. # # This method (CSDL.draw) is also called to # draw *both* DLs and primitives in a CSDL, e.g. for hover-highlighting. # # Russ 081208: Skip drawing shader primitives while in GL_SELECT. # # Bruce 090218: support cylinders too. prims_to_do = drawing_phase != "glselect" and draw_shader_primitives and (self.spheres or self.cylinders) if prims_to_do: # Cache drawing indices for just the primitives in this CSDL, # in self.drawIndices, used in self.draw_shader_primitives below. if not self.drawIndices: for shader, primitives in self.shaders_and_primitive_lists(): self.drawIndices[shader] = shader.makeDrawIndex(primitives) continue pass pass if self._drawing_funcs and drawing_phase != "glselect_glname_color": # bruce 090312 # These ignore our drawing-style args; # they also are cleared independently of start/finish, # and changing them doesn't set our last-changed timestamp. # All this is intentional. (Though we might decide to add a kind # which does participate in patterned drawing; this might require # supplying more than one func, or a dict of colors and nocolor # funcs....) if self.transformControl and transform_nonshaders: glPushMatrix() self.transformControl.applyTransform() for func in self._drawing_funcs: try: func() except: msg = "bug: exception in drawing_func %r in %r, skipping it" % (func, self) print_compact_traceback(msg + ": ") pass continue if self.transformControl and transform_nonshaders: glPopMatrix() pass # Normal or selected drawing are done before a patterned highlight # overlay, and also when not highlighting at all. You'd think that when # we're drawing a solid highlight appearance, there'd be no need to draw # the normal appearance first, because it will be obscured by the # highlight. But halo selection extends beyond the object and is only # obscured by halo highlighting. [russ 080610] # Russ 081208: Skip DLs when drawing shader-prims with glnames-as-color. DLs_to_do = drawing_phase != "glselect_glname_color" and self.has_nonempty_DLs() # the following might be changed, then are used repeatedly below; # this simplifies the various ways we can handle transforms [bruce 090224] callList = glCallList # how to call a DL, perhaps inside our transform transform_once = False # whether to transform exactly once around the # following code (as opposed to not at all, or once per callList) if self.transformControl and transform_nonshaders: if prims_to_do and DLs_to_do: # shader primitives have transform built in, but DLs don't, # so we need to get in and out of local coords repeatedly # (once for each callList) during the following # (note similar code in DrawingSet.draw): [bruce 090224] callList = self._callList_inside_transformControl elif DLs_to_do: # we need to get into and out of local coords just once transform_once = True else: pass # nothing special needed for just shader prims (or nothing) pass if transform_once: glPushMatrix() self.transformControl.applyTransform() if patterned_highlighting or not highlighted or (halo_selection and not halo_highlighting): if selected: # Draw the selected appearance. if prims_to_do: # Shader primitives. self.draw_shader_primitives(highlighted, selected, patterning, highlight_color) pass if DLs_to_do: # Display lists. # If the selection mode is patterned, the selected_dl does # first normal drawing and then draws an overlay. callList(self.selected_dl) pass pass else: # Plain, old, solid drawing of the base object appearance. if prims_to_do: self.draw_shader_primitives() # Shader primitives. pass if DLs_to_do: callList(self.color_dl) # Display lists. pass pass pass if highlighted: if prims_to_do: # Shader primitives. self.draw_shader_primitives(highlighted, selected, patterning, highlight_color) pass if DLs_to_do: # Display lists. if patterned_highlighting: # Set up a patterned drawing mode for the following draw. startPatternedDrawing(highlight=highlighted) pass # Draw a highlight overlay (solid, or in an overlay pattern.) if highlight_color is not None: hcolor = highlight_color else: hcolor = env.prefs[hoverHighlightingColor_prefs_key] apply_material(hcolor) callList(self.nocolor_dl) if patterned_highlighting: # Reset from a patterned drawing mode set up above. endPatternedDrawing(highlight=highlighted) pass pass pass if transform_once: glPopMatrix() return
def draw(self, highlighted=False, selected=False, patterning=True, highlight_color=None): """ Simple all-in-one interface to CSDL drawing. Allocate a CSDL in the parent class and fill it with the ColorSorter: self.csdl = ColorSortedDisplayList() ColorSorter.start(self.csdl) drawsphere(...), drawcylinder(...), drawpolycone(...), and so on. ColorSorter.finish() Then when you want to draw the display lists call csdl.draw() with the desired options: @param highlighted: Whether to draw highlighted. @param selected: Whether to draw selected. @param patterning: Whether to apply patterned drawing styles for highlighting and selection, according to the prefs settings. If not set, it's as if the solid-color prefs are chosen. @param highlight_color: Option to over-ride the highlight color set in the color scheme preferences. """ patterned_highlighting = (patterning and isPatternedDrawing(highlight=highlighted)) halo_selection = (selected and env.prefs[selectionColorStyle_prefs_key] == SS_HALO) halo_highlighting = ( highlighted and env.prefs[hoverHighlightingColorStyle_prefs_key] == HHS_HALO) # Normal or selected drawing are done before a patterned highlight # overlay, and also when not highlighting at all. You'd think that when # we're drawing a solid highlight appearance, there'd be no need to draw # the normal appearance first, because it will be obscured by the # highlight. But halo selection extends beyond the object and is only # obscured by halo highlighting. [russ 080610] if (patterned_highlighting or not highlighted or (halo_selection and not halo_highlighting)): if selected: # Draw the selected appearance. If the selection mode is # patterned, the selected_dl does first normal drawing and then # draws an overlay. glCallList(self.selected_dl) else: # Plain, old, solid drawing of the base object appearance. glCallList(self.color_dl) pass if highlighted: if patterned_highlighting: # Set up a patterned drawing mode for the following draw. startPatternedDrawing(highlight=highlighted) pass # Draw a highlight overlay (solid, or in an overlay pattern.) apply_material(highlight_color is not None and highlight_color or env.prefs[hoverHighlightingColor_prefs_key]) glCallList(self.nocolor_dl) if patterned_highlighting: # Reset from a patterned drawing mode set up above. endPatternedDrawing(highlight=highlighted) pass pass return
def finish(self, sorted_by_color): # bruce 090224 split this out of caller """ Finish collecting new primitives for use in self, and store them all in self, ready to be drawn in various ways. [meant to be called only by ColorSorter.start, for now] """ ## self._reset() ## # (note: this deallocates any existing display lists) if self.transformControl and (self.spheres or self.cylinders): self.updateTransform() # needed to do the transform for the first time, # even if it didn't change. Review: refactor to # whereever we first compile these down? That # might be a different place in self.draw vs. # draw from DrawingSet. selColor = env.prefs[selectionColor_prefs_key] # Note: if sorted_by_color is empty, current code still builds all # toplevel display lists, though they are noops. This may be needed # by some client code which uses those dls directly. Client code # wanting to know if it needs to draw our dls should test # self.has_nonempty_DLs(), which tests self._per_color_dls, # or self.has_nonshader_drawing(), which reports on that or any # other kind of nonshader (immediate mode opengl) drawing we might # have. [bruce 090225/090312 comment] # First build the lower level per-color sublists of primitives. for color, funcs in sorted_by_color.iteritems(): sublists = [glGenLists(1), 0] # Remember the display list ID for this color. self._per_color_dls.append([color, sublists]) glNewList(sublists[0], GL_COMPILE) opacity = color[3] if opacity == -1: # russ 080306: "Unshaded colors" for lines are signaled # by an opacity of -1 (4th component of the color.) glDisable(GL_LIGHTING) # Don't forget to re-enable it! pass for func, params, name in funcs: if name: glPushName(name) else: pass ## print "bug_2: attempt to push non-glname", name func(params) # Call the draw worker function. if name: glPopName() pass continue if opacity == -1: # Enable lighting after drawing "unshaded" objects. glEnable(GL_LIGHTING) pass glEndList() if opacity == -2: # piotr 080419: Special case for drawpolycone_multicolor # create another display list that ignores # the contents of color_array. # Remember the display list ID for this color. sublists[1] = glGenLists(1) glNewList(sublists[1], GL_COMPILE) for func, params, name in funcs: if name: glPushName(name) else: pass ## print "bug_3: attempt to push non-glname", name if func == drawpolycone_multicolor_worker: # Just to be sure, check if the func # is drawpolycone_multicolor_worker # and call drawpolycone_worker instead. # I think in the future we can figure out # a more general way of handling the # GL_COLOR_MATERIAL objects. piotr 080420 pos_array, color_array_junk, rad_array = params drawpolycone_worker((pos_array, rad_array)) elif func == drawtriangle_strip_worker: # piotr 080710: Multi-color modification # for triangle_strip primitive (used by # reduced protein style). pos_array, normal_array, color_array_junk = params drawtriangle_strip_worker((pos_array, normal_array, None)) if name: glPopName() pass continue glEndList() continue # Now the upper-level lists call all of the per-color sublists. #### REVIEW: these are created even when empty. Is that necessary? # [bruce 090224 Q] # One with colors. color_dl = self.color_dl = glGenLists(1) glNewList(color_dl, GL_COMPILE) for color, dls in self._per_color_dls: opacity = color[3] if opacity < 0: # russ 080306: "Unshaded colors" for lines are signaled # by a negative alpha. glColor3fv(color[:3]) # piotr 080417: for opacity == -2, i.e. if # GL_COLOR_MATERIAL is enabled, the color is going # to be ignored, anyway, so it is not necessary # to be tested here else: apply_material(color) glCallList(dls[0]) continue glEndList() # A second one without any colors. nocolor_dl = self.nocolor_dl = glGenLists(1) glNewList(nocolor_dl, GL_COMPILE) for color, dls in self._per_color_dls: opacity = color[3] if opacity == -2 and dls[1] > 0: # piotr 080420: If GL_COLOR_MATERIAL is enabled, # use a regular, single color dl rather than the # multicolor one. Btw, dls[1] == 0 should never # happen. glCallList(dls[1]) else: glCallList(dls[0]) glEndList() # A third DL implements the selected appearance. selected_dl = self.selected_dl = glGenLists(1) glNewList(selected_dl, GL_COMPILE) # russ 080530: Support for patterned selection drawing modes. patterned = isPatternedDrawing(select=True) if patterned: # Patterned drawing needs the colored dl drawn first. glCallList(color_dl) startPatternedDrawing(select=True) pass # Draw solid color (unpatterned) or an overlay pattern, in the # selection color. apply_material(selColor) glCallList(nocolor_dl) if patterned: # Reset from patterning drawing mode. endPatternedDrawing(select=True) glEndList() pass
def draw_vane( bond, a1p, a2p, ord_pi, rad, col ): """ Draw a vane (extending on two opposite sides of the bond axis) [#doc more]; use ord_pi to determine how intense it is (not yet sure how, maybe by mixing in bgcolor??); a1p and a2p should be unit vectors perp to bond and no more than 90 degrees apart when seen along it; they should be in the bond's coordinate system. rad is inner radius of vanes, typically the cylinder radius for the sigma bond graphic. If col is not boolean false, use it as the vane color; otherwise, use a constant color which might be influenced by the pi orbital occupancy. """ from utilities.debug_prefs import debug_pref from utilities.debug_prefs import Choice_boolean_True, Choice_boolean_False ## twisted = debug_pref('pi vanes/ribbons', Choice_boolean_False) # one of ['multicyl','vane','ribbon'] pi_bond_style = env.prefs[ pibondStyle_prefs_key] twisted = (pi_bond_style == 'ribbon') poles = debug_pref('pi vanes/poles', Choice_boolean_True) draw_outer_edges = debug_pref('pi vanes/draw edges', Choice_boolean_True) #bruce 050730 new feature, so that edge-on vanes are still visible draw_normals = debug_pref('pi vanes/draw normals', Choice_boolean_False) print_vane_params = debug_pref('pi vanes/print params', Choice_boolean_False) if print_vane_params: print "draw vane",a1p,vlen(a1p),a2p,vlen(a2p),ord_pi if twisted: d12 = dot(a1p, a2p) ## assert d12 >= 0.0 if d12 < 0.0: d12 = 0.0 if d12 > 1.0: d12 = 1.0 twist = math.acos(d12) # in radians # this is numerically inaccurate (since d12 is) near d12 == 1.0, but # that's ok, since it's only compared to threshholds (by ceil()) # which correspond to d12 values not near 1.0. # (#e btw, we could optim the common case (ntwists == 1) by # inverting this comparison to get the equivalent threshhold for # d12.) maxtwist = MAXTWIST # debug_pref doesn't yet have a PrefsType for this # number of segments needed, to limit each segment's twist to MAXTWIST ntwists = max(1, int( math.ceil( twist / maxtwist ) )) pass if col: color = col else: #bruce 050804: initial test of bond color prefs; inadequate in several # ways #######@@@@@@@ from foundation.preferences import prefs_context prefs = prefs_context() from utilities.prefs_constants import bondVaneColor_prefs_key #k I hope this color tuple of floats is in the correct prefs format color = prefs.get(bondVaneColor_prefs_key) # protect following code from color being None (which causes bus error, # maybe in PyOpenGL) assert len(color) == 3 #####@@@@@ it would be much faster to update this pref (or almost any # graphics color pref) if the OpenGL command to set the color was in its # own display list, redefined when the redraw starts, and called from # inside every other display list that needs it. Then when you changed # it, gl_update would be enough -- the chunk display lists would not # need to be remade. ###@@@ problems include: # - being fast enough # + dflt should be specified in just one place, and earlier than in this # place, so it can show up in prefs ui before this runs (in fact, even # earlier than when this module is first imported, which might be only # when needed), # - existing prefs don't have all the color vars needed (eg no # toolong-highlighted color) # - being able to track them only when finally used, not when pulled # into convenience vars before final use -- this might even be an # issue if we precompute a formula from a color-pref, but only count # it as used if that result is used. (we could decide to track the # formula res as a separate thing, i suppose) ## a1pos = bond.atom1.posn() ## a2pos = bond.atom2.posn() a1pos, c1, center, c2, a2pos, toolong = bond.geom if not toolong: c1 = c2 = center # don't know if needed x_axis = a2pos - a1pos # from 1 to 2.5, with 1 moved out to shrink width according to ord_pi width = 1.5 * ord_pi inner, outer = 2.5 - width, 2.5 radius_pairs = [(outer, inner, outer), (-inner, -outer, -outer)] # the order within each pair matters, since it affects the polys drawn # below being CW or CCW! but for purposes of edges, we also have to # know which one is *really* outer... thus the third elt (edge_outer) # of the tuple. # OpenGL code #e could optim this to use Numeric calcs and OpenGL vertex array, with # vertex normals and smooth shading, maybe even color ramp of some kind... #e want polygon outlines? #e want a 1d texture to emphasize the vane's ribbonness & help show ord_pi? glDisable(GL_CULL_FACE) #bruce 051215 use apply_material(color) instead of glMaterialfv, partly to # prevent bug of passing 3-tuple to glMaterialfv, partly to make the vanes # appear specular, partly to thereby fix bug 1216 (which was probably caused # by not setting specular color here, thus letting it remain from whatever # happened to be drawn just before). If we decide vanes should *not* appear # specular, we have to actively turn off specular color here rather than # ignoring the issue. One way would be to create and use some new # functionality like apply_material(color, specular=False). apply_material(color) # gl args partly guessed #e should add specularity, shininess... ## glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color) glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) # For vane lighting to be correct, two-sided polygon lighting is # required, and every polygon's vertex winding order (CCW) has to match # its normal vector, as both are produced by the following code. This # means that any changes to the orders of lists of vertices or vectors # in this code have to be considered carefully. But it's ok if a1p and # a2p are negated (fortunately, since calling code arbitrarily negates # them), since this reverses the poly scan directions in two ways at # once (e.g. via pvec and perpvec in the quads case below). (For ribbon # option, it's only ok if they're negated together; for quads case, # independent negation is ok. I'm pretty sure calling code only negates # them together.) [bruce 050725] for outer, inner, edge_outer in radius_pairs: normals = [] edgeverts = [] if twisted: glBegin(GL_TRIANGLE_STRIP) for i in range(1+ntwists): t = float(i) / ntwists # 0.0 to 1.0 # one minus t (python syntax doesn't let me name it just 1mt) _1mt = 1.0 - t #e could optimize, not sure it matters axispos = _1mt * a1pos + t * a2pos # let it get smaller in the middle for large twist (rather than # using angles in calc) pvec = _1mt * a1p + t * a2p # (rationale: shows weakness of bond. real reason: programmer is # in a hurry.) #e btw, it might be better to show twist by mismatch of # larger rectangular vanes, in the middle; and it's faster # to draw. # Could also "* ord_pi" rather than using color, if we worked # out proper min radius. ## pvec *= (rad * 2.5) perpvec = norm(cross(x_axis, pvec)) # test shows this is needed not only for smoothness, but to make # the lighting work at all glNormal3fv( perpvec) outervert = axispos + pvec * rad * outer innervert = axispos + pvec * rad * inner glVertex3fv( outervert) ## not needed, since the same normal as above ## glNormal3fv( perpvec) glVertex3fv( innervert) #e color? want to smooth-shade it using atom colors, or the # blue/gray for bond order, gray in center? if draw_normals: normals.append(( axispos + pvec * rad * edge_outer, perpvec )) if draw_outer_edges: edgeverts.append( axispos + pvec * rad * edge_outer ) glEnd() else: glBegin(GL_QUADS) for axispos, axispos_c, pvec, normalfactor in \ [(a1pos,c1,a1p,-1), (a2pos,c2,a2p,1)]: perpvec = norm(cross(x_axis, pvec)) * normalfactor glNormal3fv( perpvec) glVertex3fv( axispos + pvec * rad * inner) glVertex3fv( axispos + pvec * rad * outer) glVertex3fv( axispos_c + pvec * rad * outer) # This (axispos_c + pvec * rad * outer) would be the corner # we connect by a line, even when not draw_outer_edges, if # outer == edge_outer -- but it might or might not be. glVertex3fv( axispos_c + pvec * rad * inner) if draw_normals: normals.append(( axispos/2.0 + axispos_c/2.0 + pvec * rad * edge_outer, perpvec )) if draw_outer_edges: # Kluge to reverse order of first loop body but not second. edgeverts.reverse() edgeverts.append( axispos_c + pvec * rad * edge_outer) edgeverts.append( axispos + pvec * rad * edge_outer) else: # At least connect the halves of each vane, so that twist # doesn't make them look like 2 vanes. edgeverts.append( axispos_c + pvec * rad * edge_outer) glEnd() ## glBegin(GL_LINES) ## glColor3fv(color) ## for axispos, axispos_c, pvec in [(a1pos,c1,a1p), (a2pos,c2,a2p)]: ## glVertex3fv( axispos_c + pvec * rad * outer) ## glEnd() glDisable(GL_LIGHTING) # for lines... don't know if this matters if poles: glBegin(GL_LINES) glColor3fv(color) for axispos, pvec in [(a1pos,a1p), (a2pos,a2p)]: glVertex3fv( axispos + pvec * rad * outer) glVertex3fv( axispos + pvec * rad * -outer) glEnd() if normals: glBegin(GL_LINES) glColor3fv(white) for base, vec in normals: glVertex3fv(base) glVertex3fv(base + vec) glEnd() if edgeverts: glBegin(GL_LINE_STRIP) glColor3fv(color) for vert in edgeverts: glVertex3fv(vert) glEnd() glEnable(GL_LIGHTING) glEnable(GL_CULL_FACE) glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE) return
def finish(): """ Finish sorting - objects recorded since "start" will be sorted and invoked now. """ from utilities.debug_prefs import debug_pref, Choice_boolean_False debug_which_renderer = debug_pref( "debug print which renderer", Choice_boolean_False) #bruce 060314, imperfect but tolerable parent_csdl = ColorSorter.parent_csdl if drawing_globals.use_c_renderer: quux.shapeRendererInit() if debug_which_renderer: #bruce 060314 uncommented/revised the next line; it might have # to come after shapeRendererInit (not sure); it definitely has # to come after a graphics context is created and initialized. # 20060314 grantham - yes, has to come after # quux.shapeRendererInit . enabled = quux.shapeRendererGetInteger(quux.IS_VBO_ENABLED) print("using C renderer: VBO %s enabled" % (('is NOT', 'is')[enabled])) quux.shapeRendererSetUseDynamicLOD(0) if ColorSorter.sphereLevel != -1: quux.shapeRendererSetStaticLODLevels(ColorSorter.sphereLevel, 1) quux.shapeRendererStartDrawing() ColorSorter._cur_shapelist.draw() quux.shapeRendererFinishDrawing() ColorSorter.sorting = False # So chunks can actually record their shapelist # at some point if they want to # ColorSorter._cur_shapelist.petrify() # return ColorSorter._cur_shapelist else: if debug_which_renderer: print( "using Python renderer: use_color_sorted_dls %s enabled" % (drawing_globals.use_color_sorted_dls and 'IS' or 'is NOT')) print( "using Python renderer: use_color_sorted_vbos %s enabled" % (drawing_globals.use_color_sorted_vbos and 'IS' or 'is NOT')) color_groups = len(ColorSorter.sorted_by_color) objects_drawn = 0 if (not (drawing_globals.allow_color_sorting and drawing_globals.use_color_sorted_dls) or (ColorSortedDisplayList.cache_ColorSorter and drawing_globals.allow_color_sorting and drawing_globals.use_color_sorted_vbos) #russ 080225 Added, 080320 VBO experiment. or parent_csdl is None): # Either all in one display list, or immediate-mode drawing. objects_drawn += ColorSorter.draw_sorted( ColorSorter.sorted_by_color) #russ 080225: Moved glEndList here for displist re-org. if parent_csdl is not None: #russ 080320: Experiment with VBO drawing from cached #ColorSorter lists. if (ColorSortedDisplayList.cache_ColorSorter and drawing_globals.allow_color_sorting and drawing_globals.use_color_sorted_vbos): # Remember the ColorSorter lists for use as a # pseudo-display-list. parent_csdl.sorted_by_color = \ ColorSorter.sorted_by_color else: # Terminate a single display list, created when color # sorting is turned off. Started in ColorSorter.start . glEndList() pass pass else: #russ 080225 parent_csdl.reset() selColor = env.prefs[selectionColor_prefs_key] # First build the lower level per-color sublists of primitives. for color, funcs in ColorSorter.sorted_by_color.iteritems(): sublists = [glGenLists(1), 0] # Remember the display list ID for this color. parent_csdl.per_color_dls.append([color, sublists]) glNewList(sublists[0], GL_COMPILE) opacity = color[3] if opacity == -1: #russ 080306: "Unshaded colors" for lines are signaled # by an opacity of -1 (4th component of the color.) glDisable(GL_LIGHTING) # Don't forget to re-enable it! pass for func, params, name in funcs: objects_drawn += 1 if name != 0: glPushName(name) func(params) if name != 0: glPopName() pass continue if opacity == -1: # Enable lighting after drawing "unshaded" objects. glEnable(GL_LIGHTING) pass glEndList() if opacity == -2: # piotr 080419: Special case for drawpolycone_multicolor # create another display list that ignores # the contents of color_array. # Remember the display list ID for this color. sublists[1] = glGenLists(1) glNewList(sublists[1], GL_COMPILE) for func, params, name in funcs: objects_drawn += 1 if name != 0: glPushName(name) if func == drawpolycone_multicolor_worker: # Just to be sure, check if the func # is drawpolycone_multicolor_worker # and call drawpolycone_worker instead. # I think in the future we can figure out # a more general way of handling the # GL_COLOR_MATERIAL objects. piotr 080420 pos_array, color_array, rad_array = params drawpolycone_worker((pos_array, rad_array)) elif func == drawtriangle_strip_worker: # piotr 080710: Multi-color modification # for triangle_strip primitive (used by # reduced protein style). pos_array, normal_array, color_array = params drawtriangle_strip_worker( (pos_array, normal_array, None)) if name != 0: glPopName() pass continue glEndList() continue # Now the upper-level lists call all of the per-color sublists. # One with colors. color_dl = parent_csdl.color_dl = glGenLists(1) glNewList(color_dl, GL_COMPILE) for color, dls in parent_csdl.per_color_dls: opacity = color[3] if opacity < 0: #russ 080306: "Unshaded colors" for lines are signaled # by a negative alpha. glColor3fv(color[:3]) # piotr 080417: for opacity == -2, i.e. if # GL_COLOR_MATERIAL is enabled, the color is going # to be ignored, anyway, so it is not necessary # to be tested here else: apply_material(color) glCallList(dls[0]) continue glEndList() # A second one without any colors. nocolor_dl = parent_csdl.nocolor_dl = glGenLists(1) glNewList(nocolor_dl, GL_COMPILE) for color, dls in parent_csdl.per_color_dls: opacity = color[3] if opacity == -2 \ and dls[1] > 0: # piotr 080420: If GL_COLOR_MATERIAL is enabled, # use a regular, single color dl rather than the # multicolor one. Btw, dls[1] == 0 should never # happen. glCallList(dls[1]) else: glCallList(dls[0]) glEndList() # A third DL implements the selected appearance. selected_dl = parent_csdl.selected_dl = glGenLists(1) glNewList(selected_dl, GL_COMPILE) # russ 080530: Support for patterned selection drawing modes. patterned = isPatternedDrawing(select=True) if patterned: # Patterned drawing needs the colored dl drawn first. glCallList(color_dl) startPatternedDrawing(select=True) pass # Draw solid color (unpatterned) or an overlay pattern, in the # selection color. apply_material(selColor) glCallList(nocolor_dl) if patterned: # Reset from patterning drawing mode. endPatternedDrawing(select=True) glEndList() # Use either the normal-color display list or the selected one. parent_csdl.selectDl() # Draw the newly-built display list. parent_csdl.draw_dl() pass ColorSorter.sorted_by_color = None pass ColorSorter.sorting = False return
def finish(self, sorted_by_color): #bruce 090224 split this out of caller """ Finish collecting new primitives for use in self, and store them all in self, ready to be drawn in various ways. [meant to be called only by ColorSorter.start, for now] """ ## self._reset() ## # (note: this deallocates any existing display lists) if self.transformControl and (self.spheres or self.cylinders): self.updateTransform() # needed to do the transform for the first time, # even if it didn't change. Review: refactor to # whereever we first compile these down? That # might be a different place in self.draw vs. # draw from DrawingSet. selColor = env.prefs[selectionColor_prefs_key] # Note: if sorted_by_color is empty, current code still builds all # toplevel display lists, though they are noops. This may be needed # by some client code which uses those dls directly. Client code # wanting to know if it needs to draw our dls should test # self.has_nonempty_DLs(), which tests self._per_color_dls, # or self.has_nonshader_drawing(), which reports on that or any # other kind of nonshader (immediate mode opengl) drawing we might # have. [bruce 090225/090312 comment] # First build the lower level per-color sublists of primitives. for color, funcs in sorted_by_color.iteritems(): sublists = [glGenLists(1), 0] # Remember the display list ID for this color. self._per_color_dls.append([color, sublists]) glNewList(sublists[0], GL_COMPILE) opacity = color[3] if opacity == -1: #russ 080306: "Unshaded colors" for lines are signaled # by an opacity of -1 (4th component of the color.) glDisable(GL_LIGHTING) # Don't forget to re-enable it! pass for func, params, name in funcs: if name: glPushName(name) else: pass ## print "bug_2: attempt to push non-glname", name func(params) # Call the draw worker function. if name: glPopName() pass continue if opacity == -1: # Enable lighting after drawing "unshaded" objects. glEnable(GL_LIGHTING) pass glEndList() if opacity == -2: # piotr 080419: Special case for drawpolycone_multicolor # create another display list that ignores # the contents of color_array. # Remember the display list ID for this color. sublists[1] = glGenLists(1) glNewList(sublists[1], GL_COMPILE) for func, params, name in funcs: if name: glPushName(name) else: pass ## print "bug_3: attempt to push non-glname", name if func == drawpolycone_multicolor_worker: # Just to be sure, check if the func # is drawpolycone_multicolor_worker # and call drawpolycone_worker instead. # I think in the future we can figure out # a more general way of handling the # GL_COLOR_MATERIAL objects. piotr 080420 pos_array, color_array_junk, rad_array = params drawpolycone_worker((pos_array, rad_array)) elif func == drawtriangle_strip_worker: # piotr 080710: Multi-color modification # for triangle_strip primitive (used by # reduced protein style). pos_array, normal_array, color_array_junk = params drawtriangle_strip_worker( (pos_array, normal_array, None)) if name: glPopName() pass continue glEndList() continue # Now the upper-level lists call all of the per-color sublists. #### REVIEW: these are created even when empty. Is that necessary? # [bruce 090224 Q] # One with colors. color_dl = self.color_dl = glGenLists(1) glNewList(color_dl, GL_COMPILE) for color, dls in self._per_color_dls: opacity = color[3] if opacity < 0: #russ 080306: "Unshaded colors" for lines are signaled # by a negative alpha. glColor3fv(color[:3]) # piotr 080417: for opacity == -2, i.e. if # GL_COLOR_MATERIAL is enabled, the color is going # to be ignored, anyway, so it is not necessary # to be tested here else: apply_material(color) glCallList(dls[0]) continue glEndList() # A second one without any colors. nocolor_dl = self.nocolor_dl = glGenLists(1) glNewList(nocolor_dl, GL_COMPILE) for color, dls in self._per_color_dls: opacity = color[3] if opacity == -2 \ and dls[1] > 0: # piotr 080420: If GL_COLOR_MATERIAL is enabled, # use a regular, single color dl rather than the # multicolor one. Btw, dls[1] == 0 should never # happen. glCallList(dls[1]) else: glCallList(dls[0]) glEndList() # A third DL implements the selected appearance. selected_dl = self.selected_dl = glGenLists(1) glNewList(selected_dl, GL_COMPILE) # russ 080530: Support for patterned selection drawing modes. patterned = isPatternedDrawing(select=True) if patterned: # Patterned drawing needs the colored dl drawn first. glCallList(color_dl) startPatternedDrawing(select=True) pass # Draw solid color (unpatterned) or an overlay pattern, in the # selection color. apply_material(selColor) glCallList(nocolor_dl) if patterned: # Reset from patterning drawing mode. endPatternedDrawing(select=True) glEndList() pass
def finish(): """ Finish sorting - objects recorded since "start" will be sorted and invoked now. """ from utilities.debug_prefs import debug_pref, Choice_boolean_False debug_which_renderer = debug_pref( "debug print which renderer", Choice_boolean_False) #bruce 060314, imperfect but tolerable parent_csdl = ColorSorter.parent_csdl if drawing_globals.use_c_renderer: quux.shapeRendererInit() if debug_which_renderer: #bruce 060314 uncommented/revised the next line; it might have # to come after shapeRendererInit (not sure); it definitely has # to come after a graphics context is created and initialized. # 20060314 grantham - yes, has to come after # quux.shapeRendererInit . enabled = quux.shapeRendererGetInteger(quux.IS_VBO_ENABLED) print ("using C renderer: VBO %s enabled" % (('is NOT', 'is')[enabled])) quux.shapeRendererSetUseDynamicLOD(0) if ColorSorter.sphereLevel != -1: quux.shapeRendererSetStaticLODLevels(ColorSorter.sphereLevel, 1) quux.shapeRendererStartDrawing() ColorSorter._cur_shapelist.draw() quux.shapeRendererFinishDrawing() ColorSorter.sorting = False # So chunks can actually record their shapelist # at some point if they want to # ColorSorter._cur_shapelist.petrify() # return ColorSorter._cur_shapelist else: if debug_which_renderer: print ("using Python renderer: use_color_sorted_dls %s enabled" % (drawing_globals.use_color_sorted_dls and 'IS' or 'is NOT')) print ("using Python renderer: use_color_sorted_vbos %s enabled" % (drawing_globals.use_color_sorted_vbos and 'IS' or 'is NOT')) color_groups = len(ColorSorter.sorted_by_color) objects_drawn = 0 if (not (drawing_globals.allow_color_sorting and drawing_globals.use_color_sorted_dls) or (ColorSortedDisplayList.cache_ColorSorter and drawing_globals.allow_color_sorting and drawing_globals.use_color_sorted_vbos) #russ 080225 Added, 080320 VBO experiment. or parent_csdl is None): # Either all in one display list, or immediate-mode drawing. objects_drawn += ColorSorter.draw_sorted( ColorSorter.sorted_by_color) #russ 080225: Moved glEndList here for displist re-org. if parent_csdl is not None: #russ 080320: Experiment with VBO drawing from cached #ColorSorter lists. if (ColorSortedDisplayList.cache_ColorSorter and drawing_globals.allow_color_sorting and drawing_globals.use_color_sorted_vbos): # Remember the ColorSorter lists for use as a # pseudo-display-list. parent_csdl.sorted_by_color = \ ColorSorter.sorted_by_color else: # Terminate a single display list, created when color # sorting is turned off. Started in ColorSorter.start . glEndList() pass pass else: #russ 080225 parent_csdl.reset() selColor = env.prefs[selectionColor_prefs_key] # First build the lower level per-color sublists of primitives. for color, funcs in ColorSorter.sorted_by_color.iteritems(): sublists = [glGenLists(1), 0] # Remember the display list ID for this color. parent_csdl.per_color_dls.append([color, sublists]) glNewList(sublists[0], GL_COMPILE) opacity = color[3] if opacity == -1: #russ 080306: "Unshaded colors" for lines are signaled # by an opacity of -1 (4th component of the color.) glDisable(GL_LIGHTING) # Don't forget to re-enable it! pass for func, params, name in funcs: objects_drawn += 1 if name != 0: glPushName(name) func(params) if name != 0: glPopName() pass continue if opacity == -1: # Enable lighting after drawing "unshaded" objects. glEnable(GL_LIGHTING) pass glEndList() if opacity == -2: # piotr 080419: Special case for drawpolycone_multicolor # create another display list that ignores # the contents of color_array. # Remember the display list ID for this color. sublists[1] = glGenLists(1) glNewList(sublists[1], GL_COMPILE) for func, params, name in funcs: objects_drawn += 1 if name != 0: glPushName(name) if func == drawpolycone_multicolor_worker: # Just to be sure, check if the func # is drawpolycone_multicolor_worker # and call drawpolycone_worker instead. # I think in the future we can figure out # a more general way of handling the # GL_COLOR_MATERIAL objects. piotr 080420 pos_array, color_array, rad_array = params drawpolycone_worker((pos_array, rad_array)) elif func == drawtriangle_strip_worker: # piotr 080710: Multi-color modification # for triangle_strip primitive (used by # reduced protein style). pos_array, normal_array, color_array = params drawtriangle_strip_worker((pos_array, normal_array, None)) if name != 0: glPopName() pass continue glEndList() continue # Now the upper-level lists call all of the per-color sublists. # One with colors. color_dl = parent_csdl.color_dl = glGenLists(1) glNewList(color_dl, GL_COMPILE) for color, dls in parent_csdl.per_color_dls: opacity = color[3] if opacity < 0: #russ 080306: "Unshaded colors" for lines are signaled # by a negative alpha. glColor3fv(color[:3]) # piotr 080417: for opacity == -2, i.e. if # GL_COLOR_MATERIAL is enabled, the color is going # to be ignored, anyway, so it is not necessary # to be tested here else: apply_material(color) glCallList(dls[0]) continue glEndList() # A second one without any colors. nocolor_dl = parent_csdl.nocolor_dl = glGenLists(1) glNewList(nocolor_dl, GL_COMPILE) for color, dls in parent_csdl.per_color_dls: opacity = color[3] if opacity == -2 \ and dls[1] > 0: # piotr 080420: If GL_COLOR_MATERIAL is enabled, # use a regular, single color dl rather than the # multicolor one. Btw, dls[1] == 0 should never # happen. glCallList(dls[1]) else: glCallList(dls[0]) glEndList() # A third DL implements the selected appearance. selected_dl = parent_csdl.selected_dl = glGenLists(1) glNewList(selected_dl, GL_COMPILE) # russ 080530: Support for patterned selection drawing modes. patterned = isPatternedDrawing(select = True) if patterned: # Patterned drawing needs the colored dl drawn first. glCallList(color_dl) startPatternedDrawing(select = True) pass # Draw solid color (unpatterned) or an overlay pattern, in the # selection color. apply_material(selColor) glCallList(nocolor_dl) if patterned: # Reset from patterning drawing mode. endPatternedDrawing(select = True) glEndList() # Use either the normal-color display list or the selected one. parent_csdl.selectDl() # Draw the newly-built display list. parent_csdl.draw_dl() pass ColorSorter.sorted_by_color = None pass ColorSorter.sorting = False return
def draw( self, highlighted=False, selected=False, patterning=True, highlight_color=None, draw_shader_primitives=True, #bruce 090312 renamed from draw_primitives transform_nonshaders=True, #bruce 090312 renamed from transform_DLs ): """ Simple all-in-one interface to CSDL drawing. Allocate a CSDL in the parent class and fill it with the ColorSorter: self.csdl = ColorSortedDisplayList() ColorSorter.start(glpane, self.csdl) drawsphere(...), drawcylinder(...), drawpolycone(...), and so on. ColorSorter.finish() Then when you want to draw the display lists call csdl.draw() with the desired options: @param highlighted: Whether to draw highlighted. @param selected: Whether to draw selected. @param patterning: Whether to apply patterned drawing styles for highlighting and selection, according to the prefs settings. If not set, it's as if the solid-color prefs are chosen. @param highlight_color: Option to over-ride the highlight color set in the color scheme preferences. @param draw_shader_primitives: Whether to draw our shader primitives. Defaults to True. @param transform_nonshaders: Whether to apply self.transformControl to our non-shader drawing (such as DLs). Defaults to True. """ patterned_highlighting = (patterning and isPatternedDrawing(highlight=highlighted)) halo_selection = (selected and env.prefs[selectionColorStyle_prefs_key] == SS_HALO) halo_highlighting = ( highlighted and env.prefs[hoverHighlightingColorStyle_prefs_key] == HHS_HALO) # KLUGES which should be replaced by our having suitable new attrs, # such as glpane or glprefs or glresourcecontext (replacing drawing_globals): drawing_phase = drawing_globals.drawing_phase # kluge in CSDL.draw # (the other kluge is not having glpane.glprefs to pass to apply_material, # in draw; we do have glpane in finish but no point in using it there # until we have it in .draw too, preferably by attr rather than arg # (should review that opinion).) # Russ 081128 (clarified, bruce 090218): # # GLPrimitiveSet.draw() calls this method (CSDL.draw) on the CSDLs # in its _CSDLs_with_nonshader_drawing attribute (a list of CSDLs), # passing draw_shader_primitives = False to only draw the DLs, and # transform_nonshaders = False to avoid redundantly applying their # TransformControls. # # It gathers the shader primitives in a set of CSDLs into one big # drawIndex per primitive type, and draws each drawIndex in a big batch. # # This method (CSDL.draw) is also called to # draw *both* DLs and primitives in a CSDL, e.g. for hover-highlighting. # # Russ 081208: Skip drawing shader primitives while in GL_SELECT. # # Bruce 090218: support cylinders too. prims_to_do = (drawing_phase != "glselect" and draw_shader_primitives and (self.spheres or self.cylinders)) if prims_to_do: # Cache drawing indices for just the primitives in this CSDL, # in self.drawIndices, used in self.draw_shader_primitives below. if not self.drawIndices: for shader, primitives in self.shaders_and_primitive_lists(): self.drawIndices[shader] = shader.makeDrawIndex(primitives) continue pass pass if self._drawing_funcs and drawing_phase != "glselect_glname_color": #bruce 090312 # These ignore our drawing-style args; # they also are cleared independently of start/finish, # and changing them doesn't set our last-changed timestamp. # All this is intentional. (Though we might decide to add a kind # which does participate in patterned drawing; this might require # supplying more than one func, or a dict of colors and nocolor # funcs....) if self.transformControl and transform_nonshaders: glPushMatrix() self.transformControl.applyTransform() for func in self._drawing_funcs: try: func() except: msg = "bug: exception in drawing_func %r in %r, skipping it" % ( func, self) print_compact_traceback(msg + ": ") pass continue if self.transformControl and transform_nonshaders: glPopMatrix() pass # Normal or selected drawing are done before a patterned highlight # overlay, and also when not highlighting at all. You'd think that when # we're drawing a solid highlight appearance, there'd be no need to draw # the normal appearance first, because it will be obscured by the # highlight. But halo selection extends beyond the object and is only # obscured by halo highlighting. [russ 080610] # Russ 081208: Skip DLs when drawing shader-prims with glnames-as-color. DLs_to_do = (drawing_phase != "glselect_glname_color" and self.has_nonempty_DLs()) # the following might be changed, then are used repeatedly below; # this simplifies the various ways we can handle transforms [bruce 090224] callList = glCallList # how to call a DL, perhaps inside our transform transform_once = False # whether to transform exactly once around the # following code (as opposed to not at all, or once per callList) if self.transformControl and transform_nonshaders: if prims_to_do and DLs_to_do: # shader primitives have transform built in, but DLs don't, # so we need to get in and out of local coords repeatedly # (once for each callList) during the following # (note similar code in DrawingSet.draw): [bruce 090224] callList = self._callList_inside_transformControl elif DLs_to_do: # we need to get into and out of local coords just once transform_once = True else: pass # nothing special needed for just shader prims (or nothing) pass if transform_once: glPushMatrix() self.transformControl.applyTransform() if (patterned_highlighting or not highlighted or (halo_selection and not halo_highlighting)): if selected: # Draw the selected appearance. if prims_to_do: # Shader primitives. self.draw_shader_primitives(highlighted, selected, patterning, highlight_color) pass if DLs_to_do: # Display lists. # If the selection mode is patterned, the selected_dl does # first normal drawing and then draws an overlay. callList(self.selected_dl) pass pass else: # Plain, old, solid drawing of the base object appearance. if prims_to_do: self.draw_shader_primitives() # Shader primitives. pass if DLs_to_do: callList(self.color_dl) # Display lists. pass pass pass if highlighted: if prims_to_do: # Shader primitives. self.draw_shader_primitives(highlighted, selected, patterning, highlight_color) pass if DLs_to_do: # Display lists. if patterned_highlighting: # Set up a patterned drawing mode for the following draw. startPatternedDrawing(highlight=highlighted) pass # Draw a highlight overlay (solid, or in an overlay pattern.) if highlight_color is not None: hcolor = highlight_color else: hcolor = env.prefs[hoverHighlightingColor_prefs_key] apply_material(hcolor) callList(self.nocolor_dl) if patterned_highlighting: # Reset from a patterned drawing mode set up above. endPatternedDrawing(highlight=highlighted) pass pass pass if transform_once: glPopMatrix() return
def draw(self, highlighted = False, selected = False, patterning = True, highlight_color = None): """ Simple all-in-one interface to CSDL drawing. Allocate a CSDL in the parent class and fill it with the ColorSorter: self.csdl = ColorSortedDisplayList() ColorSorter.start(self.csdl) drawsphere(...), drawcylinder(...), drawpolycone(...), and so on. ColorSorter.finish() Then when you want to draw the display lists call csdl.draw() with the desired options: @param highlighted: Whether to draw highlighted. @param selected: Whether to draw selected. @param patterning: Whether to apply patterned drawing styles for highlighting and selection, according to the prefs settings. If not set, it's as if the solid-color prefs are chosen. @param highlight_color: Option to over-ride the highlight color set in the color scheme preferences. """ patterned_highlighting = (patterning and isPatternedDrawing(highlight = highlighted)) halo_selection = (selected and env.prefs[selectionColorStyle_prefs_key] == SS_HALO) halo_highlighting = (highlighted and env.prefs[hoverHighlightingColorStyle_prefs_key] == HHS_HALO) # Normal or selected drawing are done before a patterned highlight # overlay, and also when not highlighting at all. You'd think that when # we're drawing a solid highlight appearance, there'd be no need to draw # the normal appearance first, because it will be obscured by the # highlight. But halo selection extends beyond the object and is only # obscured by halo highlighting. [russ 080610] if (patterned_highlighting or not highlighted or (halo_selection and not halo_highlighting)) : if selected: # Draw the selected appearance. If the selection mode is # patterned, the selected_dl does first normal drawing and then # draws an overlay. glCallList(self.selected_dl) else: # Plain, old, solid drawing of the base object appearance. glCallList(self.color_dl) pass if highlighted: if patterned_highlighting: # Set up a patterned drawing mode for the following draw. startPatternedDrawing(highlight = highlighted) pass # Draw a highlight overlay (solid, or in an overlay pattern.) apply_material(highlight_color is not None and highlight_color or env.prefs[hoverHighlightingColor_prefs_key]) glCallList(self.nocolor_dl) if patterned_highlighting: # Reset from a patterned drawing mode set up above. endPatternedDrawing(highlight = highlighted) pass pass return