def draw(self, glpane, offset = V(0,0,0), color = None, info = {}): # modified copy of superclass draw method "draw our spheres (in practice we'll need to extend this for different sets...)" ## self.radius_multiplier = 1.0 # this might be changed by certain subclass's process_optional_info method ## self.process_optional_info(info) # might reset instvars that affect following code... (kluge?) color = color or self.color ##detailLevel = 0 # just an icosahedron detailLevel = 1 # easier to click on this way ##radius = 0.33 # the one we store might be too large? no, i guess it's ok. #e (i might prefer an octahedron, or a miniature-convex-hull-of-extrude-unit) offset = offset + self.origin radius_multiplier = self.radius_multiplier special_pos = self.special_pos # patched in ###nim? special_pos = special_pos + offset #k?? or just self.origin?? special_color = self.special_color # default is used ## count = 0 for (pos,radius,info) in self.handles: radius *= radius_multiplier pos = pos + offset dist = vlen(special_pos - pos) if dist <= radius: color2 = ave_colors( 1.0 - dist/radius, special_color, color ) ## count += 1 else: color2 = color ## experiment 050218: add alpha factor to color color2 = tuple(color2) + (0.25,) drawsphere(color2, pos, radius, detailLevel) ## self.color2_count = count # kluge, probably not used since should equal nbonds return
def _drawSpecialIndicators(self): final_crossover_atoms_dict = self._crossoverSite_marker.get_final_crossover_atoms_dict() for atm in final_crossover_atoms_dict.values(): sphere_radius = max(1.20*atm.drawing_radius(), SPHERE_RADIUS) drawsphere(darkgreen, atm.posn(), sphere_radius, SPHERE_DRAWLEVEL, opacity = SPHERE_OPACITY) if self.DEBUG_DRAW_ALL_POTENTIAL_CROSSOVER_SITES: atom_dict = self._crossoverSite_marker.get_base_orientation_indicator_dict() for atm in atom_dict.values(): drawsphere(darkred, atm.posn(), 1.5, SPHERE_DRAWLEVEL, opacity = SPHERE_OPACITY) if self.DEBUG_DRAW_PLANE_NORMALS: self._DEBUG_drawPlaneNormals() if self.DEBUG_DRAW_AVERAGE_CENTER_PAIRS_OF_POTENTIAL_CROSSOVERS: self._DEBUG_draw_avg_centerpairs_of_potential_crossovers()
def Draw(self): # TODO: also super draw, for model, axes, etc? color = self.command.cylinderColor length = cylinder_height() ## if self.command.cylinderVertical: ## direction = DY ## else: ## direction = DX direction = self.command.direction end1 = ORIGIN - direction * length/2.0 end2 = ORIGIN + direction * length/2.0 radius = self.command.cylinderWidth / 2.0 capped = True drawcylinder(color, end1, end2, radius, capped) if cylinder_round_caps(): detailLevel = 2 drawsphere( color, end1, radius, detailLevel) drawsphere( color, end2, radius, detailLevel) if self.command.widthHandleEnabled: self.command.widthHandle.draw() super(_test_connectWithState_GM, self).Draw() # added this, bruce 071022 return
def drawPeptideTrace(alphaCarbonProteinChunk): """ Draws a protein backbone trace using atoms stored in I{alphaCarbonProteinChunk}. @param alphaCarbonProteinChunk: a special (temporary) chunk that contains only the alpha carbon atoms in the peptide backbone @param alphaCarbonProteinChunk: Chunk @see PeptideLine_GraphicsMode.Draw_other(), PeptideGenerator.make_aligned() """ if alphaCarbonProteinChunk and alphaCarbonProteinChunk.atoms: last_pos = None atomitems = alphaCarbonProteinChunk.atoms.items() atomitems.sort() alphaCarbonAtomsList = [atom for (key, atom) in atomitems] for atom in alphaCarbonAtomsList: drawsphere(blue, atom.posn(), 0.2, 1) if last_pos: drawline(gray, last_pos, atom.posn(), width=2) last_pos = atom.posn() pass pass return
def Draw_other(self): """ """ _superclass_for_GM.Draw_other(self) #This fixes NFR bug 2803 #Don't draw the Dna rubberband line if the cursor is over the confirmation #corner. But make sure to call superclass.Draw_other method before doing this #check because we need to draw the rest of the model in the graphics #mode!. @see: DnaLineMode_GM.Draw_other() which does similar thing to not #draw the rubberband line when the cursor is on the confirmation corner handler = self.o.mouse_event_handler if handler is not None and handler is self._ccinstance: ##### REVIEW: # # 1. This is probably incorrect in principle, as a way of # deciding what to draw. The mouse event handling methods # should set an attribute which directly specifies whether # the next call of Draw_other (or other Draw methods) # should draw the rubberband line or not. # (Or which affects the value of an access method, e.g. # something like self.should_draw_rubberband_lines().) # # 2. Why is update_cursor called here? Any call of update_cursor # inside a specific Draw method seems suspicious. # # 3. This needs refactoring to merge with common code in its # subclass DnaLineMode_GM, and to consider doing the same # thing in its other 3 subclasses. # # [bruce 090310 comments] self.update_cursor() return if self.endPoint2 is not None: if self.endPoint1: drawsphere(self.endPoint1_sphereColor, self.endPoint1, STARTPOINT_SPHERE_RADIUS, STARTPOINT_SPHERE_DRAWLEVEL, opacity = self.endPoint1_sphereOpacity ) drawline(env.prefs[DarkBackgroundContrastColor_prefs_key], self.endPoint1, self.endPoint2, width = self.rubberband_line_width, dashEnabled = True) self._drawSnapReferenceLines() if self._ok_to_render_cursor_text: self._drawCursorText()
def drawchunk_realtime(self, glpane, chunk, highlighted=False): if chunk.protein: for aa in chunk.protein.get_amino_acids(): if chunk.protein.is_expanded(aa): for atom in aa.get_atom_list(): pos1 = chunk.abs_to_base(atom.posn()) color = atom.drawing_color() drawsphere(color, pos1, 0.25, 1) for bond in atom.bonds: if atom == bond.atom1: pos2 = chunk.abs_to_base(bond.atom2.posn()) drawcylinder(color, pos1, pos1 + 0.5*(pos2 - pos1), 0.2, 1) else: pos2 = chunk.abs_to_base(bond.atom1.posn()) drawcylinder(color, pos1 + 0.5*(pos2 - pos1), pos1, 0.2, 1) return
def _drawTags(self): """ Overrides _superClass._drawTags() for self._tagPositions. @see: self.drawTag() @see: GraphicsMode._drawTags() @see: class PM_SelectionWidget """ if self._tagPositions: for point in self._tagPositions: drawsphere(banana, point, SPHERE_RADIUS_FOR_TAGS , SPHERE_DRAWLEVEL, opacity = SPHERE_OPACITY)
def draw(self, glpane, offset = V(0,0,0), color = None, info = {}): # this code is copied/modified into a subclass, sorry """ draw our spheres (in practice we'll need to extend this for different sets...) """ ## self.radius_multiplier = 1.0 # this might be changed by certain subclass's process_optional_info method ## self.process_optional_info(info) # might reset instvars that affect following code... (kluge?) color = color or self.color ##detailLevel = 0 # just an icosahedron detailLevel = 1 # easier to click on this way ##radius = 0.33 # the one we store might be too large? no, i guess it's ok. #e (i might prefer an octahedron, or a miniature-convex-hull-of-extrude-unit) offset = offset + self.origin radius_multiplier = self.radius_multiplier color = tuple(color) + (1.0,) ## experiment 050218: alpha factor #bruce 051230 moved outside of loop to fix bug 1250 for (pos,radius,info) in self.handles: drawsphere(color, pos + offset, radius * radius_multiplier, detailLevel)
def primCSDL(centers, radii, colors): if not doTransforms: csdl = ColorSortedDisplayList() # Transformless. else: # Test pattern for TransformControl usage - vertical columns # of TC domains, separated by X coord of first center point. # Chunking will be visible when transforms are changed. xCoord = centers[0][0] - start_pos[0] # Negate centering X. xPercent = (xCoord / (nSpheres + nSpheres/10 + nSpheres/100 - 1 + (nSpheres <= 1))) xTenth = int(xPercent * 10 + .5) csdl = ColorSortedDisplayList(TCs[xTenth % numTCs]) pass # Test selection using the CSDL glname. ColorSorter.pushName(csdl.glname) ColorSorter.start(glpane, csdl) for (color, center, radius) in zip(colors, centers, radii): if not doCylinders: # Through ColorSorter to the sphere primitive buffer... drawsphere(color, center, radius, DRAWSPHERE_DETAIL_LEVEL) else: # Through ColorSorter to cylinder primitive buffer... if not drawing_globals.cylinderShader_available(): print "warning: not cylinderShader_available(), error is likely:" if (True and # Whether to do tapered shader-cylinders. # Display List cylinders don't support taper. glpane.glprefs.cylinderShader_desired()): ###cylRad = (radius/2.0, (.75-radius)/2.0) cylRad = (radius/1.5 - .167, .3 - radius/1.5) else: cylRad = radius/2.0 pass endPt2 = center + V(0.5, 0.0, 0.0) # 0.5, -0.5) drawcylinder(color, center, endPt2, cylRad) global test_endpoints test_endpoints += [(center, endPt2)] pass continue ColorSorter.popName() ColorSorter.finish(draw_now = True) test_DrawingSet.addCSDL(csdl) return csdl
def __init__(self, x, y, n): self.csdl = ColorSortedDisplayList() # draw into it, based on x, y, n ColorSorter.start(None, self.csdl) for i in range(n): z = i - (_NUM_SPHERES_PER_CSDL - 1) / 2.0 color = (random.uniform(0.2, 0.8), 0, random.uniform(0.2, 0.8)) pos = (x, y, z) radius = 0.25 # 0.5 would be touching the next ones drawsphere(color, pos, radius, 2 ## DRAWSPHERE_DETAIL_LEVEL ) ColorSorter.finish(draw_now = False) return
def _drawTags(self): """ Overrides _superClass._drawTags() for self._tagPositions. @see: self.drawTag() @see: GraphicsMode._drawTags() @see: class PM_SelectionWidget """ if 0: #see method for details. Used for debugging only self._DEBUG_Flag_EndPoint1_ofDnaSegments() if self._tagPositions: for point in self._tagPositions: drawsphere(silver, point, SPHERE_RADIUS, SPHERE_DRAWLEVEL, opacity = SPHERE_OPACITY)
def _DEBUG_Flag_EndPoint1_ofDnaSegments(self): """ Temporary method that draws a sphere to indicate the endPoint1 of each segment being resized. Used for debugging a bug in computing average end points for the resize handles. """ if not self.command: return endPoints_1 = [] for segment in self.command.getResizeSegmentList(): e1, e2 = segment.getAxisEndPoints() if e1 is not None: endPoints_1.append(e1) for end1 in endPoints_1: drawsphere(lighterblue, end1, SPHERE_RADIUS, SPHERE_DRAWLEVEL, opacity = 1.0)
def Draw(self): """ Draw method for this temporary mode. """ _superclass_for_GM.Draw(self) #This fixes NFR bug 2803 #Don't draw the Dna rubberband line if the cursor is over the confirmation #corner. But make sure to call superclass.Draw method before doing this #check because we need to draw the rest of the model in the graphics #mode!. @see: DnaLineMode_GM.Draw() which does similar thing to not #draw the rubberband line when the cursor is on the confirmation corner handler = self.o.mouse_event_handler if handler is not None and handler is self._ccinstance: self.update_cursor() return if self.endPoint2 is not None: if self.endPoint1: drawsphere(self.endPoint1_sphereColor, self.endPoint1, STARTPOINT_SPHERE_RADIUS, STARTPOINT_SPHERE_DRAWLEVEL, opacity = self.endPoint1_sphereOpacity ) drawline(self.rubberband_line_color, self.endPoint1, self.endPoint2, width = self.rubberband_line_width, dashEnabled = True) self._drawSnapReferenceLines() if self._ok_to_render_cursor_text: self._drawCursorText()
def _cellDraw(self, color, p0, p1): hasSinglet = False if type(p1) == type((1,)): v1 = p1[0] hasSinglet = True else: v1 = p1 if self.dispMode == "Tubes": drawcylinder(color, p0, v1, 0.2) else: drawsphere(color, p0, 0.5, 1) if hasSinglet: drawsphere(color, v1, 0.2, 1) else: drawsphere(color, v1, 0.5, 1) drawline(white, p0, v1)
def _bondDraw(self, color, p0, p1, carbonAt): if self.dispMode == "Tubes": drawcylinder(color, p0, p1, 0.2) else: if carbonAt < 0: drawsphere(color, p0, 0.5, 1) drawsphere(color, p1, 0.5, 1) elif carbonAt == 0: drawsphere(color, p0, 0.5, 1) drawsphere(color, p1, 0.2, 1) elif carbonAt == 1: drawsphere(color, p0, 0.2, 1) drawsphere(color, p1, 0.5, 1) drawline(white, p0, p1)
def drawDnaSingleRibbon(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = None, ribbon1_direction = None, peakDeviationFromCenter = 9.5, ribbonThickness = 2.0, ribbon1Color = None, stepColor = None): """ @see: drawDnaRibbons (method in this file) @see: DnaStrand_GraphicsMode._drawHandles() """ if 0: # debug code, useful to see where the argument points are located # [bruce 080422] draw_debug_text(glpane, endCenter1, "endCenter1") draw_debug_text(glpane, endCenter2, "endCenter2") draw_debug_text(glpane, ribbon1_start_point, "ribbon1_start_point") #Try to match the rubberband display style as closely as possible to #either the glpane's current display or the chunk display of the segment #being edited. The caller should do the job of specifying the display style #it desires. As of 2008-02-20, this method only supports following display #styles --Tubes, Ball and Stick, CPK and lines. the sphere radius #for ball and stick or CPK is calculated approximately. if displayStyle == diTrueCPK: SPHERE_RADIUS = 3.5 ribbonThickness = 2.0 elif displayStyle == diTUBES: SPHERE_RADIUS = 0.01 ribbonThickness = 5.0 elif displayStyle == diLINES: #Lines display and all other unsupported display styles SPHERE_RADIUS = 0.01 ribbonThickness = 1.0 else: #ball and stick display style. All other unsupported displays #will be rendered in ball and stick display style SPHERE_RADIUS = 1.0 ribbonThickness = 3.0 if stepColor is None: stepColor = env.prefs[DarkBackgroundContrastColor_prefs_key] ribbonLength = vlen(endCenter1 - endCenter2) #Don't draw the vertical line (step) passing through the startpoint unless #the ribbonLength is at least equal to the duplexRise. # i.e. do the drawing only when there are at least two ladder steps. # This prevents a 'revolving line' effect due to the single ladder step at # the first endpoint. It also means the dna duplex axis can be determined # below from the two endpoints. if ribbonLength < duplexRise: return unitVectorAlongLength = norm(endCenter2 - endCenter1) glDisable(GL_LIGHTING) ##glPushMatrix() ##glTranslatef(endCenter1[0], endCenter1[1], endCenter1[2]) ##pointOnAxis = V(0, 0, 0) pointOnAxis = endCenter1 axial_shift = V(0.0, 0.0, 0.0) # might be changed below # [these might be discarded and recomputed just below; # the case where they aren't is (and I think was) untested. # -- bruce 080422 comment] vectorAlongLadderStep = cross(-lineOfSightVector, unitVectorAlongLength) unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 if ribbon1_start_point is not None: # [revise the meaning of these values to give the coordinate system # with the right phase in which to draw the ribbon. # bruce 080422 bugfix] vectorAlongLadderStep0 = ribbon1_start_point - endCenter1 # note: this might not be perpendicular to duplex axis. # fix by subtracting off the parallel component. # but add the difference back to every point below. vectorAlongLadderStep = vectorAlongLadderStep0 - \ dot( unitVectorAlongLength, vectorAlongLadderStep0 ) * unitVectorAlongLength axial_shift = (vectorAlongLadderStep0 - vectorAlongLadderStep) # note: even using this, there is still a small glitch in the # location of the first drawn sphere vs. the ribbon point... don't # know why. [bruce 080422] unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 pass del vectorAlongLadderStep ###=== #Following limits the arrowHead Size to the given value. When you zoom out, #the rest of ladder drawing becomes smaller (expected) and the following #check ensures that the arrowheads are drawn proportionately. # (Not using a 'constant' to do this as using glpaneScale gives better #results) if glpaneScale > 40: arrowDrawingScale = 40 else: arrowDrawingScale = glpaneScale #Formula .. Its a Sine Wave. # y(x) = A.sin(2*pi*f*x + phase_angle) ------[1] # where -- # f = 1/T # A = Amplitude of the sine wave (or 'peak deviation from center') # y = y coordinate of the sine wave -- distance is in Angstroms # x = the x coordinate # phase_angle is computed for each wave. We know y at x =0. For example, # for ribbon_1, , at x = 0, y = A. Putting these values in equation [1] # we get the phase_angle. x = 0.0 T = duplexRise * basesPerTurn # The 'Period' of the sine wave # (i.e. peak to peak distance between consecutive crests) numberOfBasesDrawn = 0 theta_offset = 0 ## phase_angle_ribbon_1 = HALF_PI ## theta_ribbon_1 = (TWICE_PI * x / T) + phase_angle_ribbon_1 #Initialize ribbon1_point # [note: might not be needed, since identical to first point # computed during loop, but present code uses it to initialize # previous_ribbon1_point during loop [bruce 080422 comment]] ribbon1_point = _compute_ribbon_point(pointOnAxis + axial_shift, basesPerTurn, duplexRise, unitVectorAlongLength, unitVectorAlongLadderStep, unitDepthVector, peakDeviationFromCenter, numberOfBasesDrawn, theta_offset ) while x < ribbonLength: #Draw the axis point. drawPoint(stepColor, pointOnAxis) previousPointOnAxis = pointOnAxis previous_ribbon1_point = ribbon1_point ribbon1_point = _compute_ribbon_point(pointOnAxis + axial_shift, basesPerTurn, duplexRise, unitVectorAlongLength, unitVectorAlongLadderStep, unitDepthVector, peakDeviationFromCenter, numberOfBasesDrawn, theta_offset ) if x == duplexRise and ribbon1_direction == -1: # For ribbon_2 we need to draw an arrow head for y at x = 0. # To do this, we need the 'next ribbon_2' point in order to # compute the appropriate vectors. So when x = duplexRise, the # previous_ribbon2_point is nothing but y at x = 0. arrowLengthVector2 = norm(ribbon1_point - previous_ribbon1_point ) arrowHeightVector2 = cross(-lineOfSightVector, arrowLengthVector2) drawArrowHead( ribbon1Color, previous_ribbon1_point, arrowDrawingScale, -arrowHeightVector2, -arrowLengthVector2) # Draw sphere over previous_ribbon1_point and not ribbon1_point. # This is so we don't draw a sphere over the last point on ribbon1 # (instead, it is drawn as an arrowhead after the while loop). drawsphere(ribbon1Color, previous_ribbon1_point, SPHERE_RADIUS, SPHERE_DRAWLEVEL, opacity = SPHERE_OPACITY) drawline(stepColor, pointOnAxis, ribbon1_point) #Increment the pointOnAxis and x pointOnAxis = pointOnAxis + unitVectorAlongLength * duplexRise x += duplexRise numberOfBasesDrawn += 1 if previous_ribbon1_point: drawline(ribbon1Color, previous_ribbon1_point, ribbon1_point, width = ribbonThickness, isSmooth = True ) arrowLengthVector1 = norm(ribbon1_point - previous_ribbon1_point) arrowHeightVector1 = cross(-lineOfSightVector, arrowLengthVector1) pass continue # while x < ribbonLength if ribbon1_direction == 1: #Arrow head for endpoint of ribbon_1. drawArrowHead(ribbon1Color, ribbon1_point, arrowDrawingScale, arrowHeightVector1, arrowLengthVector1) #The second axis endpoint of the dna is drawn as a transparent sphere. #Note that the second axis endpoint is NOT NECESSARILY endCenter2 . In fact # those two are equal only at the ladder steps. In other case (when the # ladder step is not completed), the endCenter1 is ahead of the #'second axis endpoint of the dna' drawsphere(AXIS_ENDPOINT_SPHERE_COLOR, previousPointOnAxis, AXIS_ENDPOINT_SPHERE_RADIUS, AXIS_ENDPOINT_SPHERE_DRAWLEVEL, opacity = AXIS_ENDPOINT_SPHERE_OPACITY) ##glPopMatrix() glEnable(GL_LIGHTING) return # from drawDnaSingleRibbon
def test_drawing(glpane, initOnly=False): """ When TEST_DRAWING is enabled at the start of graphics/widgets/GLPane_rendering_methods.py, and when TestGraphics_Command is run (see its documentation for various ways to do that), this file is loaded and GLPane.paintGL() calls the test_drawing() function instead of the usual body of paintGL(). """ # WARNING: this duplicates some code with test_Draw_model(). # Load the sphere shaders if needed. global _USE_SHADERS if _USE_SHADERS: if not drawing_globals.test_sphereShader: print "test_drawing: Loading sphere shaders." try: from graphics.drawing.gl_shaders import GLSphereShaderObject drawing_globals.test_sphereShader = GLSphereShaderObject() ##### REVIEW: is this compatible with my refactoring in drawing_globals? # If not, use of Test Graphics Performance command might cause subsequent # bugs in other code. Ideally we'd call the new methods that encapsulate # this, to setup shaders. [bruce 090304 comment] print "test_drawing: Sphere-shader initialization is complete.\n" except: _USE_SHADERS = False print "test_drawing: Exception while loading sphere shaders, will reraise and not try again" raise pass global start_pos, first_time if first_time: # Set up the viewing scale, but then let interactive zooming work. glpane.scale = nSpheres * .6 pass # This same function gets called to set up for drawing, and to draw. if not initOnly: glpane._setup_modelview() glpane._setup_projection() ##glpane._compute_frustum_planes() glClearColor(64.0, 64.0, 64.0, 1.0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) ##glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) glMatrixMode(GL_MODELVIEW) pass global test_csdl, test_dl, test_dls, test_ibo, test_vbo, test_spheres global test_DrawingSet, test_endpoints, test_Object # See below for test case descriptions and timings on a MacBook Pro. # The Qt event toploop in NE1 tops out at about 60 frames-per-second. # NE1 with test toploop, single CSDL per draw (test case 1) # . 17,424 spheres (132x132, through the color sorter) 4.8 FPS # Russ 080919: More recently, 12.2 FPS. # . Level 2 spheres have 9 triangles x 20 faces, 162 distinct vertices, # visited on the average 2.3 times, giving 384 tri-strip vertices. # . 17,424 spheres is 6.7 million tri-strip vertices. (6,690,816) if testCase == 1: if test_csdl is None: print("Test case 1, %d^2 spheres\n %s." % (nSpheres, "ColorSorter")) test_csdl = ColorSortedDisplayList() ColorSorter.start(None, test_csdl) drawsphere( [0.5, 0.5, 0.5], # color [0.0, 0.0, 0.0], # pos .5, # radius DRAWSPHERE_DETAIL_LEVEL, testloop=nSpheres) ColorSorter.finish(draw_now=True) pass else: test_csdl.draw() pass # NE1 with test toploop, single display list per draw (test case 2) # . 10,000 spheres (all drawing modes) 17.5 FPS # . 17,424 spheres (132x132, manual display list) 11.1 FPS # . 40,000 spheres (mode 5 - VBO/IBO spheres from DL's) 2.2 FPS # . 40,000 spheres (mode 6 - Sphere shaders from DL's) 2.5 FPS # . 90,000 spheres (all drawing modes) 1.1 FPS elif testCase == 2: if test_dl is None: print("Test case 2, %d^2 spheres\n %s." % (nSpheres, "One display list calling primitive dl's")) test_dl = glGenLists(1) glNewList(test_dl, GL_COMPILE_AND_EXECUTE) drawsphere_worker_loop(( [0.0, 0.0, 0.0], # pos .5, # radius DRAWSPHERE_DETAIL_LEVEL, nSpheres)) glEndList() pass else: glColor3i(127, 127, 127) glCallList(test_dl) pass # NE1 with test toploop, one big chunk VBO/IBO of box quads (test case 3) # . 17,424 spheres (1 box/shader draw call) 43.7 FPS # . 17,424 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 57.7 FPS # . 40,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 56.7 FPS # . 90,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 52.7 FPS # . 160,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 41.4 FPS # . 250,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 27.0 FPS elif int(testCase) == 3: doTransforms = False if test_spheres is None: print("Test case 3, %d^2 spheres\n %s." % (nSpheres, "One big VBO/IBO chunk buffer")) if testCase == 3.1: print("Sub-test 3.1, animate partial updates.") elif testCase == 3.2: print("Sub-test 3.2, animate partial updates" + " w/ C per-chunk array buffering.") elif testCase == 3.3: print("Sub-test 3.3, animate partial updates" + " w/ Python array buffering.") # . 3.4 - Big batch draw, with transforms indexed by IDs added. # (Second FPS number with debug colors in the vertex shader off.) # - 90,000 (300x300) spheres, TEXTURE_XFORMS = True, 26(29) FPS # - 90,000 (300x300) spheres, N_CONST_XFORMS = 250, 26(29) FPS # - 90,000 (300x300) spheres, N_CONST_XFORMS = 275, 0.3(0.6) FPS # (What happens after 250? CPU usage goes from 40% to 94%.) # -160,000 (400x400) spheres, TEXTURE_XFORMS = True, 26 FPS # -250,000 (500x500) spheres, TEXTURE_XFORMS = True, 26 FPS elif testCase == 3.4: print("Sub-test 3.4, add transforms indexed by IDs.") from graphics.drawing.gl_shaders import TEXTURE_XFORMS from graphics.drawing.gl_shaders import N_CONST_XFORMS from graphics.drawing.gl_shaders import UNIFORM_XFORMS if TEXTURE_XFORMS: print "Transforms in texture memory." elif UNIFORM_XFORMS: print "%d transforms in uniform memory." % N_CONST_XFORMS pass else: print "transforms not supported, error is likely" doTransforms = True pass centers = [] radius = .5 radii = [] colors = [] if not doTransforms: transformIDs = None else: transformIDs = [] transformChunkID = -1 # Allocate IDs sequentially from 0. # For this test, allow arbitrarily chunking the primitives. primCounter = transformChunkLength transforms = [] # Accumulate transforms as a list of lists. # Initialize transforms with an identity matrix. # Transforms here are lists (or Numpy arrays) of 16 numbers. identity = ([1.0] + 4 * [0.0]) * 3 + [1.0] pass for x in range(nSpheres): for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. thisRad = radius * (.75 + t * .25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] # Transforms go into a texture memory image if needed. # Per-primitive Transform IDs go into an attribute VBO. if doTransforms: primCounter = primCounter + 1 if primCounter >= transformChunkLength: # Start a new chunk, allocating a transform matrix. primCounter = 0 transformChunkID += 1 if 0: # 1 # Debug hack: Label mat[0,0] with the chunk ID. # Vertex shader debug code shows these in blue. # If viewed as geometry, it will be a slight # stretch of the array in the X direction. transforms += [ [1.0 + transformChunkID / 100.0] + identity[1:] ] elif 0: # 1 # Debug hack: Fill mat with mat.element pattern. transforms += [[ transformChunkID + i / 100.0 for i in range(16) ]] else: transforms += [identity] pass pass # All of the primitives in a chunk have the same ID. transformIDs += [transformChunkID] pass continue continue test_spheres = GLSphereBuffer() test_spheres.addSpheres(centers, radii, colors, transformIDs, None) if doTransforms: print("%d primitives in %d transform chunks of size <= %d" % (nSpheres * nSpheres, len(transforms), transformChunkLength)) shader = drawing_globals.test_sphereShader shader.setupTransforms(transforms) pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) # Update portions for animation. pulse = time.time() pulse -= floor(pulse) # 0 to 1 in each second # Test animating updates on 80% of the radii in 45% of the columns. # . 3.1 - Update radii Python array per-column, send to graphics RAM. # - 2,500 (50x50) spheres 55 FPS # - 10,000 (100x100) spheres 35 FPS # - 17,424 (132x132) spheres 22.2 FPS # - 40,000 (200x200) spheres 12.4 FPS # - 90,000 (300x300) spheres 6.0 FPS if testCase == 3.1: # Not buffered, send each column change. radius = .5 margin = nSpheres / 10 for x in range(margin, nSpheres, 2): radii = [] for y in range(margin, nSpheres - margin): t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t * .25) phase = pulse + float(x + y) / nSpheres radii += 8 * [thisRad - .1 + .1 * sin(phase * 2 * pi)] continue C_radii = numpy.array(radii, dtype=numpy.float32) offset = x * nSpheres + margin test_spheres.radii_vbo.update(offset * 8, C_radii) continue pass # . 3.2 - Numpy buffered in C array, subscript assignments to C. # - 2,500 (50x50) spheres 48 FPS # - 10,000 (100x100) spheres 17.4 FPS # - 17,424 (132x132) spheres 11.2 FPS # - 40,000 (200x200) spheres 5.5 FPS # - 90,000 (300x300) spheres 2.5 FPS elif testCase == 3.2: # Buffered per-chunk at the C array level. radius = .5 margin = nSpheres / 10 global C_array if C_array is None: # Replicate. C_array = numpy.zeros((8 * (nSpheres - (2 * margin)), ), dtype=numpy.float32) pass for x in range(margin, nSpheres, 2): count = 0 for y in range(margin, nSpheres - margin): t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t * .25) phase = pulse + float(x + y) / nSpheres C_array[count*8:(count+1)*8] = \ thisRad-.1 + .1*sin(phase * 2*pi) count += 1 continue offset = x * nSpheres + margin test_spheres.radii_vbo.update(offset * 8, C_array) continue pass # . 3.3 - updateRadii in Python array, copy via C to graphics RAM. # - 2,500 (50x50) spheres 57 FPS # - 10,000 (100x100) spheres 32 FPS # - 17,424 (132x132) spheres 20 FPS # - 40,000 (200x200) spheres 10.6 FPS # - 90,000 (300x300) spheres 4.9 FPS elif testCase == 3.3: # Buffered at the Python level, batch the whole-array update. radius = .5 margin = nSpheres / 10 for x in range(margin, nSpheres, 2): radii = [] for y in range(margin, nSpheres - margin): t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t * .25) phase = pulse + float(x + y) / nSpheres radii += [thisRad - .1 + .1 * sin(phase * 2 * pi)] continue test_spheres.updateRadii( # Update, but don't send yet. x * nSpheres + margin, radii, send=False) continue test_spheres.sendRadii() pass # Options: color = [0.0, 1.0, 0.0], transform_id = 1, radius = 1.0 test_spheres.draw() pass # NE1 with test toploop, separate sphere VBO/IBO box/shader draws (test case 4) # . 17,424 spheres (132x132 box/shader draw quads calls) 0.7 FPS elif testCase == 4: if test_ibo is None: print("Test case 4, %d^2 spheres\n %s." % (nSpheres, "Separate VBO/IBO shader/box buffer sphere calls, no DL")) # Collect transformed bounding box vertices and offset indices. # Start at the lower-left corner, offset so the whole pattern comes # up centered on the origin. cubeVerts = drawing_globals.shaderCubeVerts cubeIndices = drawing_globals.shaderCubeIndices C_indices = numpy.array(cubeIndices, dtype=numpy.uint32) test_ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices, GL_STATIC_DRAW) test_ibo.unbind() C_verts = numpy.array(cubeVerts, dtype=numpy.float32) test_vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, C_verts, GL_STATIC_DRAW) test_vbo.unbind() pass else: drawing_globals.test_sphereShader.configShader(glpane) glEnableClientState(GL_VERTEX_ARRAY) test_vbo.bind() # Vertex data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) drawing_globals.test_sphereShader.setActive(True) glDisable(GL_CULL_FACE) glColor3i(127, 127, 127) test_ibo.bind() # Index data comes from the ibo. for x in range(nSpheres): for y in range(nSpheres): # From drawsphere_worker_loop(). pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \ (y+y/10+y/100) * V(0, 1, 0) radius = .5 glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius, radius, radius) glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None) glPopMatrix() continue continue drawing_globals.test_sphereShader.setActive(False) glEnable(GL_CULL_FACE) test_ibo.unbind() test_vbo.unbind() glDisableClientState(GL_VERTEX_ARRAY) pass # NE1 with test toploop, # One DL around separate VBO/IBO shader/box buffer sphere calls (test case 5) # . 17,424 spheres (1 box/shader DL draw call) 9.2 FPS elif testCase == 5: if test_dl is None: print("Test case 5, %d^2 spheres\n %s." % ( nSpheres, "One DL around separate VBO/IBO shader/box buffer sphere calls" )) # Collect transformed bounding box vertices and offset indices. # Start at the lower-left corner, offset so the whole pattern comes # up centered on the origin. cubeVerts = drawing_globals.shaderCubeVerts cubeIndices = drawing_globals.shaderCubeIndices C_indices = numpy.array(cubeIndices, dtype=numpy.uint32) test_ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices, GL_STATIC_DRAW) test_ibo.unbind() C_verts = numpy.array(cubeVerts, dtype=numpy.float32) test_vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, C_verts, GL_STATIC_DRAW) test_vbo.unbind() # Wrap a display list around the draws. test_dl = glGenLists(1) glNewList(test_dl, GL_COMPILE_AND_EXECUTE) glEnableClientState(GL_VERTEX_ARRAY) test_vbo.bind() # Vertex data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) drawing_globals.test_sphereShader.setActive(True) glDisable(GL_CULL_FACE) glColor3i(127, 127, 127) test_ibo.bind() # Index data comes from the ibo. for x in range(nSpheres): for y in range(nSpheres): # From drawsphere_worker_loop(). pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \ (y+y/10+y/100) * V(0, 1, 0) radius = .5 glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius, radius, radius) glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None) glPopMatrix() continue continue drawing_globals.test_sphereShader.setActive(False) glEnable(GL_CULL_FACE) test_ibo.unbind() test_vbo.unbind() glDisableClientState(GL_VERTEX_ARRAY) glEndList() else: glColor3i(127, 127, 127) glCallList(test_dl) pass pass # NE1 with test toploop, # N column DL's around VBO/IBO shader/box buffer sphere calls (test case 6) # . 2,500 (50x50) spheres 58 FPS # . 10,000 (100x100) spheres 57 FPS # . 17,424 (132x132) spheres 56 FPS # . 40,000 (200x200) spheres 50 FPS # . 90,000 (300x300) spheres 28 FPS # . 160,000 (400x400) spheres 16.5 FPS # . 250,000 (500x500) spheres 3.2 FPS elif testCase == 6: if test_dls is None: print("Test case 6, %d^2 spheres\n %s." % (nSpheres, "N col DL's around VBO/IBO shader/box buffer sphere calls")) # Wrap n display lists around the draws (one per column.) test_dls = glGenLists( nSpheres) # Returns ID of first DL in the set. test_spheres = [] for x in range(nSpheres): centers = [] radius = .5 radii = [] colors = [] # Each column is relative to its bottom sphere location. Start # at the lower-left corner, offset so the whole pattern comes up # centered on the origin. start_pos = V(0, 0, 0) # So it doesn't get subtracted twice. pos = sphereLoc(x, 0) - V(nSpheres / 2.0, nSpheres / 2.0, 0) for y in range(nSpheres): centers += [sphereLoc(0, y)] # Sphere radii progress from 3/4 to full size. t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. thisRad = radius * (.75 + t * .25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] continue test_sphere = GLSphereBuffer() test_sphere.addSpheres(centers, radii, colors, None, None) test_spheres += [test_sphere] glNewList(test_dls + x, GL_COMPILE_AND_EXECUTE) glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) test_sphere.draw() glPopMatrix() glEndList() continue pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) # Turn the lights on. for x in range(nSpheres): glCallList(test_dls + x) continue pass pass # NE1 with test toploop, # N column VBO sets of shader/box buffer sphere calls (test case 7) # . 2,500 (50x50) spheres 50 FPS # . 10,000 (100x100) spheres 30.5 FPS # . 17,424 (132x132) spheres 23.5 FPS # . 40,000 (200x200) spheres 16.8 FPS # . 90,000 (300x300) spheres 10.8 FPS # . 160,000 (400x400) spheres 9.1 FPS # . 250,000 (500x500) spheres 7.3 FPS elif testCase == 7: if test_spheres is None: print("Test case 7, %d^2 spheres\n %s." % (nSpheres, "Per-column VBO/IBO chunk buffers")) test_spheres = [] for x in range(nSpheres): centers = [] radius = .5 radii = [] colors = [] for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. thisRad = radius * (.75 + t * .25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] continue _spheres1 = GLSphereBuffer() _spheres1.addSpheres(centers, radii, colors, None, None) test_spheres += [_spheres1] continue pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) for chunk in test_spheres: chunk.draw() pass # NE1 with test toploop, # Short chunk VBO sets of shader/box buffer sphere calls (test case 8) # . 625 (25x25) spheres 30 FPS, 79 chunk buffers of length 8. # . 2,500 (50x50) spheres 13.6 FPS, 313 chunk buffers of length 8. # . 10,000 (100x100) spheres 6.4 FPS, 704 chunk buffers of length 8. # . 10,000 (100x100) spheres 3.3 FPS, 1250 chunk buffers of length 8. # . 17,424 (132x132) spheres 2.1 FPS, 2178 chunk buffers of length 8. # . 2,500 (50x50) spheres 33.5 FPS, 105 chunk buffers of length 24. # . 17,424 (132x132) spheres 5.5 FPS, 726 chunk buffers of length 24. # # Subcase 8.1: CSDLs in a DrawingSet. (Initial pass-through version.) # . 2,500 (50x50) spheres 36.5 FPS, 105 chunk buffers of length 24. # . 5,625 (75x75) spheres 16.1 FPS, 235 chunk buffers of length 24. # . 10,000 (100x100) spheres 0.5 FPS?!, 414 chunk buffers of length 24. # Has to be <= 250 chunks for constant memory transforms? # . 10,000 (100x100) spheres 11.8 FPS, 50 chunk buffers of length 200. # After a minute of startup. # . 10,000 (100x100) spheres 9.3 FPS, 200 chunk buffers of length 50. # After a few minutes of startup. # Subcase 8.2: CSDLs in a DrawingSet with transforms. (Pass-through.) # . 10,000 (100x100) spheres 11.5 FPS, 50 chunk buffers of length 200. # # Subcase 8.1: CSDLs in a DrawingSet. (First HunkBuffer version.) # Measured with auto-rotate on, ignoring startup and occasional outliers. # As before, on a 2 core, 2.4 GHz Intel MacBook Pro with GeForce 8600M GT. # HUNK_SIZE = 10000 # . 2,500 (50x50) spheres 140-200 FPS, 105 chunks of length 24. # . 5,625 (75x75) spheres 155-175 FPS, 235 chunks of length 24. # . 10,000 (100x100) spheres 134-145 FPS, 50 chunks of length 200. # . 10,000 (100x100) spheres 130-143 FPS, 200 chunks of length 50. # . 10,000 (100x100) spheres 131-140 FPS, 1,250 chunks of length 8. # Chunks are gathered into hunk buffers, so no chunk size speed diff. # . 17,424 (132x132) spheres 134-140 FPS, 88 chunks of length 200. # . 17,424 (132x132) spheres 131-140 FPS, 2,178 chunks of length 8. # HUNK_SIZE = 20000 # . 17,424 (132x132) spheres 131-140 FPS, 88 chunks of length 200. # . 17,424 (132x132) spheres 130-141 FPS, 2,178 chunks of length 8. # HUNK_SIZE = 10000 # . 40,000 (200x200) spheres 77.5-82.8 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 34.9-42.6 FPS, 11,2500 chunks of length 8. # Spheres are getting down to pixel size, causing moire patterns. # Rotate the sphere-array off-axis 45 degrees to minimize. # (Try adding multi-sampled anti-aliasing, to the drawing test...) # . 160,000 (400x400) spheres 26.4-27.1 FPS, 20,000 chunks of length 8. # . 250,000 (500x500) spheres 16.8-17.1 FPS, 31,250 chunks of length 8. # The pattern is getting too large, far-clipping is setting in. # . 360,000 (600x600) spheres 11.6-11.8 FPS, 45,000 chunks of length 8. # Extreme far-clipping in the drawing test pattern. # HUNK_SIZE = 20000; no significant speed-up. # . 40,000 (200x200) spheres 75.9-81.5 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 41.2-42.4 FPS, 11,250 chunks of length 8. # Spheres are getting down to pixel size, causing moire patterns. # . 160,000 (400x400) spheres 26.5-26.9 FPS, 20,000 chunks of length 8. # . 250,000 (500x500) spheres 16.5-17.1 FPS, 31,250 chunks of length 8. # . 360,000 (600x600) spheres 11.8-12.1 FPS, 45,000 chunks of length 8. # HUNK_SIZE = 5000; no significant slowdown or CPU load difference. # . 40,000 (200x200) spheres 81.0-83.8 FPS, 5,000 chunks of length 8. # . 160,000 (400x400) spheres 27.3-29.4 FPS, 20,000 chunks of length 8. # . 360,000 (600x600) spheres 11.7-12.1 FPS, 45,000 chunks of length 8. # # Retest after updating MacOS to 10.5.5, with TestGraphics, HUNK_SIZE = 5000 # . 40,000 (200x200) spheres 68.7-74.4 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 39.4-42.0 FPS, 11,250 chunks of length 8. # . 160,000 (400x400) spheres 24.4-25.2 FPS, 20,000 chunks of length 8. # Retest with glMultiDrawElements drawing indexes in use, HUNK_SIZE = 5000 # . 40,000 (200x200) spheres 52.8-54.4 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 22.8-23.3 FPS, 11,250 chunks of length 8. # . 160,000 (400x400) spheres 13.5-15.2 FPS, 20,000 chunks of length 8. # # Retest with reworked halo/sphere shader, HUNK_SIZE = 5000 [setup time] # . 17,424 (132x132) spheres 52.8-53.7 FPS, 2,178 chunks of length 8. [60] # . 40,000 (200x200) spheres 29.3-30.4 FPS, 5,000 chunks of length 8.[156] # . 90,000 (300x300) spheres 18.2-19.2 FPS, 11,250 chunks of length 8.[381] # . 160,000 (400x400) spheres 10.2-11.6 FPS, 20,000 chunks of length 8.[747] # Billboard drawing patterns instead of cubes, HUNK_SIZE = 5000 [setup time] # . 17,424 (132x132) spheres 49.7-55.7 FPS, 2,178 chunks of length 8. [35] # . 40,000 (200x200) spheres 39.6-40.8 FPS, 5,000 chunks of length 8. [88] # . 90,000 (300x300) spheres 18.9-19.5 FPS, 11,250 chunks of length 8.[225] # . 160,000 (400x400) spheres 11.2-11.7 FPS, 20,000 chunks of length 8.[476] # elif int(testCase) == 8: doTransforms = False doCylinders = False if test_spheres is None: # Setup. print("Test case 8, %d^2 primitives\n %s, length %d." % (nSpheres, "Short VBO/IBO chunk buffers", chunkLength)) if testCase == 8.1: print( "Sub-test 8.1, sphere chunks are in CSDL's in a DrawingSet." ) test_DrawingSet = DrawingSet() elif testCase == 8.2: print("Sub-test 8.2, spheres, rotate with TransformControls.") test_DrawingSet = DrawingSet() doTransforms = True elif testCase == 8.3: print( "Sub-test 8.3, cylinder chunks are in CSDL's in a DrawingSet." ) test_DrawingSet = DrawingSet() doCylinders = True pass if test_DrawingSet: # note: doesn't happen in test 8.0, which causes a bug then. [bruce 090223 comment] print "constructed test_DrawingSet =", test_DrawingSet if USE_GRAPHICSMODE_DRAW: print("Use graphicsMode.Draw_model for DrawingSet in paintGL.") pass t1 = time.time() if doTransforms: # Provide several TransformControls to test separate action. global numTCs, TCs numTCs = 3 TCs = [TransformControl() for i in range(numTCs)] pass def primCSDL(centers, radii, colors): if not doTransforms: csdl = ColorSortedDisplayList() # Transformless. else: # Test pattern for TransformControl usage - vertical columns # of TC domains, separated by X coord of first center point. # Chunking will be visible when transforms are changed. xCoord = centers[0][0] - start_pos[ 0] # Negate centering X. xPercent = ( xCoord / (nSpheres + nSpheres / 10 + nSpheres / 100 - 1 + (nSpheres <= 1))) xTenth = int(xPercent * 10 + .5) csdl = ColorSortedDisplayList(TCs[xTenth % numTCs]) pass # Test selection using the CSDL glname. ColorSorter.pushName(csdl.glname) ColorSorter.start(glpane, csdl) for (color, center, radius) in zip(colors, centers, radii): if not doCylinders: # Through ColorSorter to the sphere primitive buffer... drawsphere(color, center, radius, DRAWSPHERE_DETAIL_LEVEL) else: # Through ColorSorter to cylinder primitive buffer... if not drawing_globals.cylinderShader_available(): print "warning: not cylinderShader_available(), error is likely:" if (True and # Whether to do tapered shader-cylinders. # Display List cylinders don't support taper. glpane.glprefs.cylinderShader_desired()): ###cylRad = (radius/2.0, (.75-radius)/2.0) cylRad = (radius / 1.5 - .167, .3 - radius / 1.5) else: cylRad = radius / 2.0 pass endPt2 = center + V(0.5, 0.0, 0.0) # 0.5, -0.5) drawcylinder(color, center, endPt2, cylRad) global test_endpoints test_endpoints += [(center, endPt2)] pass continue ColorSorter.popName() ColorSorter.finish(draw_now=True) test_DrawingSet.addCSDL(csdl) return csdl if testCase == 8: #bruce 090223 revised to try to avoid traceback def chunkFn(centers, radii, colors): res = GLSphereBuffer() res.addSpheres(centers, radii, colors, None, None) return res pass else: chunkFn = primCSDL pass test_spheres = [] radius = .5 centers = [] radii = [] colors = [] global test_endpoints test_endpoints = [] for x in range(nSpheres): for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. thisRad = radius * (.5 + t * .5) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] # Put out short chunk buffers. if len(centers) >= chunkLength: test_spheres += [chunkFn(centers, radii, colors)] centers = [] radii = [] colors = [] continue continue # Remainder fraction buffer. if len(centers): test_spheres += [chunkFn(centers, radii, colors)] pass print "Setup time", time.time() - t1, "seconds." print "%d chunk buffers" % len(test_spheres) pass elif not initOnly: # Run. test_Draw_8x(glpane) pass elif testCase == 100: #bruce 090102 # before making more of these, modularize it somehow from commands.TestGraphics.test_selection_redraw import test_selection_redraw test_class = test_selection_redraw params = (nSpheres, ) # note: test size is not directly comparable to other tests with same value of nSpheres if test_Object is None \ or not isinstance(test_Object, test_class) \ or test_Object.current_params() != params: # review: same_vals? # Setup. if test_Object: test_Object.destroy() test_Object = test_class(*params) test_Object.activate() print test_Object pass # review: safe to change elif to if? not sure, GL state is only initialized below elif not initOnly: # Run. test_Object.draw_complete() pass pass if not initOnly: glMatrixMode(GL_MODELVIEW) glFlush() pass first_time = False return
def _bondDraw(self, color, p0, p1, carbonAt): if self.dispMode == 'Tubes': drawcylinder(color, p0, p1, 0.2) else: if carbonAt < 0: drawsphere(color, p0, 0.5, 1) drawsphere(color, p1, 0.5, 1) elif carbonAt == 0: drawsphere(color, p0, 0.5, 1) drawsphere(color, p1, 0.2, 1) elif carbonAt == 1: drawsphere(color, p0, 0.2, 1) drawsphere(color, p1, 0.5, 1) drawline(white, p0, p1)
def draw(self): drawsphere(self.fix_color(self.color), self.center, self.radius, self.detailLevel)
def _drawDnaRubberbandLine(self): """ Overrides superclass method. It loops through the segments being resized and draws the rubberband lines for all. NOT this could be SLOW @see: MultipleDnaSegmentResize_EditCommand.getDnaRibbonParams() for comments. @TODO: needs more cleanup """ handleType = '' if self.command.grabbedHandle is not None: if self.command.grabbedHandle in [ self.command.rotationHandle1, self.command.rotationHandle2 ]: handleType = 'ROTATION_HANDLE' else: handleType = 'RESIZE_HANDLE' if handleType and handleType == 'RESIZE_HANDLE': # textColor is not used. I'm going to ask Ninad if this should # stay in or should be removed. --Mark #textColor = env.prefs[cursorTextColor_prefs_key] # Mark 2008-08-28 for segment in self.command.getResizeSegmentList(): self.command.currentStruct = segment params_when_adding_bases, params_when_removing_bases = \ self.command.getDnaRibbonParams() if params_when_adding_bases: end1, \ end2, \ basesPerTurn,\ duplexRise, \ ribbon1_start_point, \ ribbon2_start_point, \ ribbon1_direction, \ ribbon2_direction, \ ribbon1Color, \ ribbon2Color = params_when_adding_bases #Note: The displayStyle argument for the rubberband line should #really be obtained from self.command.struct. But the struct #is a DnaSegment (a Group) and doesn't have attr 'display' #Should we then obtain this information from one of its strandChunks? #but what if two strand chunks and axis chunk are rendered #in different display styles? since situation may vary, lets #use self.glpane.displayMode for rubberbandline displayMode drawDnaRibbons( self.glpane, end1, end2, basesPerTurn, duplexRise, self.glpane.scale, self.glpane.lineOfSight, self.glpane.displayMode, ribbonThickness=4.0, ribbon1_start_point=ribbon1_start_point, ribbon2_start_point=ribbon2_start_point, ribbon1_direction=ribbon1_direction, ribbon2_direction=ribbon2_direction, ribbon1Color=ribbon1Color, ribbon2Color=ribbon2Color, ) #Draw a sphere that indicates the current position of #the resize end of each segment . drawsphere(env.prefs[selectionColor_prefs_key], end2, SPHERE_RADIUS_2, SPHERE_DRAWLEVEL, opacity=SPHERE_OPACITY) #Draw the text next to the cursor that gives info about #number of base pairs etc self._drawCursorText(position=end2) elif params_when_removing_bases: end2 = params_when_removing_bases #Draw a sphere that indicates the current position of #the resize end of each segment. drawsphere(darkred, end2, SPHERE_RADIUS_2, SPHERE_DRAWLEVEL, opacity=SPHERE_OPACITY) #Draw the text next to the cursor that gives info about #number of base pairs etc self._drawCursorText(position=end2) #Reset the command.currentStruct to None. (it is set to 'segment' #at the beginning of the for loop. self.command.currentStruct = None
def test_drawing(glpane, initOnly = False): """ When TEST_DRAWING is enabled at the start of graphics/widgets/GLPane_rendering_methods.py, and when TestGraphics_Command is run (see its documentation for various ways to do that), this file is loaded and GLPane.paintGL() calls the test_drawing() function instead of the usual body of paintGL(). """ # WARNING: this duplicates some code with test_Draw_model(). # Load the sphere shaders if needed. global _USE_SHADERS if _USE_SHADERS: if not drawing_globals.test_sphereShader: print "test_drawing: Loading sphere shaders." try: from graphics.drawing.gl_shaders import GLSphereShaderObject drawing_globals.test_sphereShader = GLSphereShaderObject() ##### REVIEW: is this compatible with my refactoring in drawing_globals? # If not, use of Test Graphics Performance command might cause subsequent # bugs in other code. Ideally we'd call the new methods that encapsulate # this, to setup shaders. [bruce 090304 comment] print "test_drawing: Sphere-shader initialization is complete.\n" except: _USE_SHADERS = False print "test_drawing: Exception while loading sphere shaders, will reraise and not try again" raise pass global start_pos, first_time if first_time: # Set up the viewing scale, but then let interactive zooming work. glpane.scale = nSpheres * .6 pass # This same function gets called to set up for drawing, and to draw. if not initOnly: glpane._setup_modelview() glpane._setup_projection() ##glpane._compute_frustum_planes() glClearColor(64.0, 64.0, 64.0, 1.0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ##glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) glMatrixMode(GL_MODELVIEW) pass global test_csdl, test_dl, test_dls, test_ibo, test_vbo, test_spheres global test_DrawingSet, test_endpoints, test_Object # See below for test case descriptions and timings on a MacBook Pro. # The Qt event toploop in NE1 tops out at about 60 frames-per-second. # NE1 with test toploop, single CSDL per draw (test case 1) # . 17,424 spheres (132x132, through the color sorter) 4.8 FPS # Russ 080919: More recently, 12.2 FPS. # . Level 2 spheres have 9 triangles x 20 faces, 162 distinct vertices, # visited on the average 2.3 times, giving 384 tri-strip vertices. # . 17,424 spheres is 6.7 million tri-strip vertices. (6,690,816) if testCase == 1: if test_csdl is None: print ("Test case 1, %d^2 spheres\n %s." % (nSpheres, "ColorSorter")) test_csdl = ColorSortedDisplayList() ColorSorter.start(None, test_csdl) drawsphere([0.5, 0.5, 0.5], # color [0.0, 0.0, 0.0], # pos .5, # radius DRAWSPHERE_DETAIL_LEVEL, testloop = nSpheres ) ColorSorter.finish(draw_now = True) pass else: test_csdl.draw() pass # NE1 with test toploop, single display list per draw (test case 2) # . 10,000 spheres (all drawing modes) 17.5 FPS # . 17,424 spheres (132x132, manual display list) 11.1 FPS # . 40,000 spheres (mode 5 - VBO/IBO spheres from DL's) 2.2 FPS # . 40,000 spheres (mode 6 - Sphere shaders from DL's) 2.5 FPS # . 90,000 spheres (all drawing modes) 1.1 FPS elif testCase == 2: if test_dl is None: print ("Test case 2, %d^2 spheres\n %s." % (nSpheres, "One display list calling primitive dl's")) test_dl = glGenLists(1) glNewList(test_dl, GL_COMPILE_AND_EXECUTE) drawsphere_worker_loop(([0.0, 0.0, 0.0], # pos .5, # radius DRAWSPHERE_DETAIL_LEVEL, nSpheres )) glEndList() pass else: glColor3i(127, 127, 127) glCallList(test_dl) pass # NE1 with test toploop, one big chunk VBO/IBO of box quads (test case 3) # . 17,424 spheres (1 box/shader draw call) 43.7 FPS # . 17,424 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 57.7 FPS # . 40,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 56.7 FPS # . 90,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 52.7 FPS # . 160,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 41.4 FPS # . 250,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 27.0 FPS elif int(testCase) == 3: doTransforms = False if test_spheres is None: print ("Test case 3, %d^2 spheres\n %s." % (nSpheres, "One big VBO/IBO chunk buffer")) if testCase == 3.1: print ("Sub-test 3.1, animate partial updates.") elif testCase == 3.2: print ("Sub-test 3.2, animate partial updates" + " w/ C per-chunk array buffering.") elif testCase == 3.3: print ("Sub-test 3.3, animate partial updates" + " w/ Python array buffering.") # . 3.4 - Big batch draw, with transforms indexed by IDs added. # (Second FPS number with debug colors in the vertex shader off.) # - 90,000 (300x300) spheres, TEXTURE_XFORMS = True, 26(29) FPS # - 90,000 (300x300) spheres, N_CONST_XFORMS = 250, 26(29) FPS # - 90,000 (300x300) spheres, N_CONST_XFORMS = 275, 0.3(0.6) FPS # (What happens after 250? CPU usage goes from 40% to 94%.) # -160,000 (400x400) spheres, TEXTURE_XFORMS = True, 26 FPS # -250,000 (500x500) spheres, TEXTURE_XFORMS = True, 26 FPS elif testCase == 3.4: print ("Sub-test 3.4, add transforms indexed by IDs.") from graphics.drawing.gl_shaders import TEXTURE_XFORMS from graphics.drawing.gl_shaders import N_CONST_XFORMS from graphics.drawing.gl_shaders import UNIFORM_XFORMS if TEXTURE_XFORMS: print "Transforms in texture memory." elif UNIFORM_XFORMS: print "%d transforms in uniform memory." % N_CONST_XFORMS pass else: print "transforms not supported, error is likely" doTransforms = True pass centers = [] radius = .5 radii = [] colors = [] if not doTransforms: transformIDs = None else: transformIDs = [] transformChunkID = -1 # Allocate IDs sequentially from 0. # For this test, allow arbitrarily chunking the primitives. primCounter = transformChunkLength transforms = [] # Accumulate transforms as a list of lists. # Initialize transforms with an identity matrix. # Transforms here are lists (or Numpy arrays) of 16 numbers. identity = ([1.0] + 4*[0.0]) * 3 + [1.0] pass for x in range(nSpheres): for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. thisRad = radius * (.75 + t*.25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] # Transforms go into a texture memory image if needed. # Per-primitive Transform IDs go into an attribute VBO. if doTransforms: primCounter = primCounter + 1 if primCounter >= transformChunkLength: # Start a new chunk, allocating a transform matrix. primCounter = 0 transformChunkID += 1 if 0: # 1 # Debug hack: Label mat[0,0] with the chunk ID. # Vertex shader debug code shows these in blue. # If viewed as geometry, it will be a slight # stretch of the array in the X direction. transforms += [ [1.0+transformChunkID/100.0] + identity[1:]] elif 0: # 1 # Debug hack: Fill mat with mat.element pattern. transforms += [ [transformChunkID + i/100.0 for i in range(16)]] else: transforms += [identity] pass pass # All of the primitives in a chunk have the same ID. transformIDs += [transformChunkID] pass continue continue test_spheres = GLSphereBuffer() test_spheres.addSpheres(centers, radii, colors, transformIDs, None) if doTransforms: print ("%d primitives in %d transform chunks of size <= %d" % (nSpheres * nSpheres, len(transforms), transformChunkLength)) shader = drawing_globals.test_sphereShader shader.setupTransforms(transforms) pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) # Update portions for animation. pulse = time.time() pulse -= floor(pulse) # 0 to 1 in each second # Test animating updates on 80% of the radii in 45% of the columns. # . 3.1 - Update radii Python array per-column, send to graphics RAM. # - 2,500 (50x50) spheres 55 FPS # - 10,000 (100x100) spheres 35 FPS # - 17,424 (132x132) spheres 22.2 FPS # - 40,000 (200x200) spheres 12.4 FPS # - 90,000 (300x300) spheres 6.0 FPS if testCase == 3.1: # Not buffered, send each column change. radius = .5 margin = nSpheres/10 for x in range(margin, nSpheres, 2): radii = [] for y in range(margin, nSpheres-margin): t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t*.25) phase = pulse + float(x+y)/nSpheres radii += 8 * [thisRad-.1 + .1*sin(phase * 2*pi)] continue C_radii = numpy.array(radii, dtype=numpy.float32) offset = x*nSpheres + margin test_spheres.radii_vbo.update(offset * 8, C_radii) continue pass # . 3.2 - Numpy buffered in C array, subscript assignments to C. # - 2,500 (50x50) spheres 48 FPS # - 10,000 (100x100) spheres 17.4 FPS # - 17,424 (132x132) spheres 11.2 FPS # - 40,000 (200x200) spheres 5.5 FPS # - 90,000 (300x300) spheres 2.5 FPS elif testCase == 3.2: # Buffered per-chunk at the C array level. radius = .5 margin = nSpheres/10 global C_array if C_array is None: # Replicate. C_array = numpy.zeros((8 * (nSpheres-(2*margin)),), dtype=numpy.float32) pass for x in range(margin, nSpheres, 2): count = 0 for y in range(margin, nSpheres-margin): t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t*.25) phase = pulse + float(x+y)/nSpheres C_array[count*8:(count+1)*8] = \ thisRad-.1 + .1*sin(phase * 2*pi) count += 1 continue offset = x*nSpheres + margin test_spheres.radii_vbo.update(offset * 8, C_array) continue pass # . 3.3 - updateRadii in Python array, copy via C to graphics RAM. # - 2,500 (50x50) spheres 57 FPS # - 10,000 (100x100) spheres 32 FPS # - 17,424 (132x132) spheres 20 FPS # - 40,000 (200x200) spheres 10.6 FPS # - 90,000 (300x300) spheres 4.9 FPS elif testCase == 3.3: # Buffered at the Python level, batch the whole-array update. radius = .5 margin = nSpheres/10 for x in range(margin, nSpheres, 2): radii = [] for y in range(margin, nSpheres-margin): t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t*.25) phase = pulse + float(x+y)/nSpheres radii += [thisRad-.1 + .1*sin(phase * 2*pi)] continue test_spheres.updateRadii( # Update, but don't send yet. x*nSpheres + margin, radii, send = False) continue test_spheres.sendRadii() pass # Options: color = [0.0, 1.0, 0.0], transform_id = 1, radius = 1.0 test_spheres.draw() pass # NE1 with test toploop, separate sphere VBO/IBO box/shader draws (test case 4) # . 17,424 spheres (132x132 box/shader draw quads calls) 0.7 FPS elif testCase == 4: if test_ibo is None: print ("Test case 4, %d^2 spheres\n %s." % (nSpheres, "Separate VBO/IBO shader/box buffer sphere calls, no DL")) # Collect transformed bounding box vertices and offset indices. # Start at the lower-left corner, offset so the whole pattern comes # up centered on the origin. cubeVerts = drawing_globals.shaderCubeVerts cubeIndices = drawing_globals.shaderCubeIndices C_indices = numpy.array(cubeIndices, dtype=numpy.uint32) test_ibo = GLBufferObject( GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices, GL_STATIC_DRAW) test_ibo.unbind() C_verts = numpy.array(cubeVerts, dtype=numpy.float32) test_vbo = GLBufferObject( GL_ARRAY_BUFFER_ARB, C_verts, GL_STATIC_DRAW) test_vbo.unbind() pass else: drawing_globals.test_sphereShader.configShader(glpane) glEnableClientState(GL_VERTEX_ARRAY) test_vbo.bind() # Vertex data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) drawing_globals.test_sphereShader.setActive(True) glDisable(GL_CULL_FACE) glColor3i(127, 127, 127) test_ibo.bind() # Index data comes from the ibo. for x in range(nSpheres): for y in range(nSpheres): # From drawsphere_worker_loop(). pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \ (y+y/10+y/100) * V(0, 1, 0) radius = .5 glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius,radius,radius) glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None) glPopMatrix() continue continue drawing_globals.test_sphereShader.setActive(False) glEnable(GL_CULL_FACE) test_ibo.unbind() test_vbo.unbind() glDisableClientState(GL_VERTEX_ARRAY) pass # NE1 with test toploop, # One DL around separate VBO/IBO shader/box buffer sphere calls (test case 5) # . 17,424 spheres (1 box/shader DL draw call) 9.2 FPS elif testCase == 5: if test_dl is None: print ("Test case 5, %d^2 spheres\n %s." % (nSpheres, "One DL around separate VBO/IBO shader/box buffer sphere calls")) # Collect transformed bounding box vertices and offset indices. # Start at the lower-left corner, offset so the whole pattern comes # up centered on the origin. cubeVerts = drawing_globals.shaderCubeVerts cubeIndices = drawing_globals.shaderCubeIndices C_indices = numpy.array(cubeIndices, dtype=numpy.uint32) test_ibo = GLBufferObject( GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices, GL_STATIC_DRAW) test_ibo.unbind() C_verts = numpy.array(cubeVerts, dtype=numpy.float32) test_vbo = GLBufferObject( GL_ARRAY_BUFFER_ARB, C_verts, GL_STATIC_DRAW) test_vbo.unbind() # Wrap a display list around the draws. test_dl = glGenLists(1) glNewList(test_dl, GL_COMPILE_AND_EXECUTE) glEnableClientState(GL_VERTEX_ARRAY) test_vbo.bind() # Vertex data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) drawing_globals.test_sphereShader.setActive(True) glDisable(GL_CULL_FACE) glColor3i(127, 127, 127) test_ibo.bind() # Index data comes from the ibo. for x in range(nSpheres): for y in range(nSpheres): # From drawsphere_worker_loop(). pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \ (y+y/10+y/100) * V(0, 1, 0) radius = .5 glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius,radius,radius) glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None) glPopMatrix() continue continue drawing_globals.test_sphereShader.setActive(False) glEnable(GL_CULL_FACE) test_ibo.unbind() test_vbo.unbind() glDisableClientState(GL_VERTEX_ARRAY) glEndList() else: glColor3i(127, 127, 127) glCallList(test_dl) pass pass # NE1 with test toploop, # N column DL's around VBO/IBO shader/box buffer sphere calls (test case 6) # . 2,500 (50x50) spheres 58 FPS # . 10,000 (100x100) spheres 57 FPS # . 17,424 (132x132) spheres 56 FPS # . 40,000 (200x200) spheres 50 FPS # . 90,000 (300x300) spheres 28 FPS # . 160,000 (400x400) spheres 16.5 FPS # . 250,000 (500x500) spheres 3.2 FPS elif testCase == 6: if test_dls is None: print ("Test case 6, %d^2 spheres\n %s." % (nSpheres, "N col DL's around VBO/IBO shader/box buffer sphere calls")) # Wrap n display lists around the draws (one per column.) test_dls = glGenLists(nSpheres) # Returns ID of first DL in the set. test_spheres = [] for x in range(nSpheres): centers = [] radius = .5 radii = [] colors = [] # Each column is relative to its bottom sphere location. Start # at the lower-left corner, offset so the whole pattern comes up # centered on the origin. start_pos = V(0, 0, 0) # So it doesn't get subtracted twice. pos = sphereLoc(x, 0) - V(nSpheres/2.0, nSpheres/2.0, 0) for y in range(nSpheres): centers += [sphereLoc(0, y)] # Sphere radii progress from 3/4 to full size. t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. thisRad = radius * (.75 + t*.25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] continue test_sphere = GLSphereBuffer() test_sphere.addSpheres(centers, radii, colors, None, None) test_spheres += [test_sphere] glNewList(test_dls + x, GL_COMPILE_AND_EXECUTE) glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) test_sphere.draw() glPopMatrix() glEndList() continue pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) # Turn the lights on. for x in range(nSpheres): glCallList(test_dls + x) continue pass pass # NE1 with test toploop, # N column VBO sets of shader/box buffer sphere calls (test case 7) # . 2,500 (50x50) spheres 50 FPS # . 10,000 (100x100) spheres 30.5 FPS # . 17,424 (132x132) spheres 23.5 FPS # . 40,000 (200x200) spheres 16.8 FPS # . 90,000 (300x300) spheres 10.8 FPS # . 160,000 (400x400) spheres 9.1 FPS # . 250,000 (500x500) spheres 7.3 FPS elif testCase == 7: if test_spheres is None: print ("Test case 7, %d^2 spheres\n %s." % (nSpheres, "Per-column VBO/IBO chunk buffers")) test_spheres = [] for x in range(nSpheres): centers = [] radius = .5 radii = [] colors = [] for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. thisRad = radius * (.75 + t*.25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] continue _spheres1 = GLSphereBuffer() _spheres1.addSpheres(centers, radii, colors, None, None) test_spheres += [_spheres1] continue pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) for chunk in test_spheres: chunk.draw() pass # NE1 with test toploop, # Short chunk VBO sets of shader/box buffer sphere calls (test case 8) # . 625 (25x25) spheres 30 FPS, 79 chunk buffers of length 8. # . 2,500 (50x50) spheres 13.6 FPS, 313 chunk buffers of length 8. # . 10,000 (100x100) spheres 6.4 FPS, 704 chunk buffers of length 8. # . 10,000 (100x100) spheres 3.3 FPS, 1250 chunk buffers of length 8. # . 17,424 (132x132) spheres 2.1 FPS, 2178 chunk buffers of length 8. # . 2,500 (50x50) spheres 33.5 FPS, 105 chunk buffers of length 24. # . 17,424 (132x132) spheres 5.5 FPS, 726 chunk buffers of length 24. # # Subcase 8.1: CSDLs in a DrawingSet. (Initial pass-through version.) # . 2,500 (50x50) spheres 36.5 FPS, 105 chunk buffers of length 24. # . 5,625 (75x75) spheres 16.1 FPS, 235 chunk buffers of length 24. # . 10,000 (100x100) spheres 0.5 FPS?!, 414 chunk buffers of length 24. # Has to be <= 250 chunks for constant memory transforms? # . 10,000 (100x100) spheres 11.8 FPS, 50 chunk buffers of length 200. # After a minute of startup. # . 10,000 (100x100) spheres 9.3 FPS, 200 chunk buffers of length 50. # After a few minutes of startup. # Subcase 8.2: CSDLs in a DrawingSet with transforms. (Pass-through.) # . 10,000 (100x100) spheres 11.5 FPS, 50 chunk buffers of length 200. # # Subcase 8.1: CSDLs in a DrawingSet. (First HunkBuffer version.) # Measured with auto-rotate on, ignoring startup and occasional outliers. # As before, on a 2 core, 2.4 GHz Intel MacBook Pro with GeForce 8600M GT. # HUNK_SIZE = 10000 # . 2,500 (50x50) spheres 140-200 FPS, 105 chunks of length 24. # . 5,625 (75x75) spheres 155-175 FPS, 235 chunks of length 24. # . 10,000 (100x100) spheres 134-145 FPS, 50 chunks of length 200. # . 10,000 (100x100) spheres 130-143 FPS, 200 chunks of length 50. # . 10,000 (100x100) spheres 131-140 FPS, 1,250 chunks of length 8. # Chunks are gathered into hunk buffers, so no chunk size speed diff. # . 17,424 (132x132) spheres 134-140 FPS, 88 chunks of length 200. # . 17,424 (132x132) spheres 131-140 FPS, 2,178 chunks of length 8. # HUNK_SIZE = 20000 # . 17,424 (132x132) spheres 131-140 FPS, 88 chunks of length 200. # . 17,424 (132x132) spheres 130-141 FPS, 2,178 chunks of length 8. # HUNK_SIZE = 10000 # . 40,000 (200x200) spheres 77.5-82.8 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 34.9-42.6 FPS, 11,2500 chunks of length 8. # Spheres are getting down to pixel size, causing moire patterns. # Rotate the sphere-array off-axis 45 degrees to minimize. # (Try adding multi-sampled anti-aliasing, to the drawing test...) # . 160,000 (400x400) spheres 26.4-27.1 FPS, 20,000 chunks of length 8. # . 250,000 (500x500) spheres 16.8-17.1 FPS, 31,250 chunks of length 8. # The pattern is getting too large, far-clipping is setting in. # . 360,000 (600x600) spheres 11.6-11.8 FPS, 45,000 chunks of length 8. # Extreme far-clipping in the drawing test pattern. # HUNK_SIZE = 20000; no significant speed-up. # . 40,000 (200x200) spheres 75.9-81.5 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 41.2-42.4 FPS, 11,250 chunks of length 8. # Spheres are getting down to pixel size, causing moire patterns. # . 160,000 (400x400) spheres 26.5-26.9 FPS, 20,000 chunks of length 8. # . 250,000 (500x500) spheres 16.5-17.1 FPS, 31,250 chunks of length 8. # . 360,000 (600x600) spheres 11.8-12.1 FPS, 45,000 chunks of length 8. # HUNK_SIZE = 5000; no significant slowdown or CPU load difference. # . 40,000 (200x200) spheres 81.0-83.8 FPS, 5,000 chunks of length 8. # . 160,000 (400x400) spheres 27.3-29.4 FPS, 20,000 chunks of length 8. # . 360,000 (600x600) spheres 11.7-12.1 FPS, 45,000 chunks of length 8. # # Retest after updating MacOS to 10.5.5, with TestGraphics, HUNK_SIZE = 5000 # . 40,000 (200x200) spheres 68.7-74.4 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 39.4-42.0 FPS, 11,250 chunks of length 8. # . 160,000 (400x400) spheres 24.4-25.2 FPS, 20,000 chunks of length 8. # Retest with glMultiDrawElements drawing indexes in use, HUNK_SIZE = 5000 # . 40,000 (200x200) spheres 52.8-54.4 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 22.8-23.3 FPS, 11,250 chunks of length 8. # . 160,000 (400x400) spheres 13.5-15.2 FPS, 20,000 chunks of length 8. # # Retest with reworked halo/sphere shader, HUNK_SIZE = 5000 [setup time] # . 17,424 (132x132) spheres 52.8-53.7 FPS, 2,178 chunks of length 8. [60] # . 40,000 (200x200) spheres 29.3-30.4 FPS, 5,000 chunks of length 8.[156] # . 90,000 (300x300) spheres 18.2-19.2 FPS, 11,250 chunks of length 8.[381] # . 160,000 (400x400) spheres 10.2-11.6 FPS, 20,000 chunks of length 8.[747] # Billboard drawing patterns instead of cubes, HUNK_SIZE = 5000 [setup time] # . 17,424 (132x132) spheres 49.7-55.7 FPS, 2,178 chunks of length 8. [35] # . 40,000 (200x200) spheres 39.6-40.8 FPS, 5,000 chunks of length 8. [88] # . 90,000 (300x300) spheres 18.9-19.5 FPS, 11,250 chunks of length 8.[225] # . 160,000 (400x400) spheres 11.2-11.7 FPS, 20,000 chunks of length 8.[476] # elif int(testCase) == 8: doTransforms = False doCylinders = False if test_spheres is None: # Setup. print ("Test case 8, %d^2 primitives\n %s, length %d." % (nSpheres, "Short VBO/IBO chunk buffers", chunkLength)) if testCase == 8.1: print ("Sub-test 8.1, sphere chunks are in CSDL's in a DrawingSet.") test_DrawingSet = DrawingSet() elif testCase == 8.2: print ("Sub-test 8.2, spheres, rotate with TransformControls.") test_DrawingSet = DrawingSet() doTransforms = True elif testCase == 8.3: print ("Sub-test 8.3, cylinder chunks are in CSDL's in a DrawingSet.") test_DrawingSet = DrawingSet() doCylinders = True pass if test_DrawingSet: # note: doesn't happen in test 8.0, which causes a bug then. [bruce 090223 comment] print "constructed test_DrawingSet =", test_DrawingSet if USE_GRAPHICSMODE_DRAW: print ("Use graphicsMode.Draw_model for DrawingSet in paintGL.") pass t1 = time.time() if doTransforms: # Provide several TransformControls to test separate action. global numTCs, TCs numTCs = 3 TCs = [TransformControl() for i in range(numTCs)] pass def primCSDL(centers, radii, colors): if not doTransforms: csdl = ColorSortedDisplayList() # Transformless. else: # Test pattern for TransformControl usage - vertical columns # of TC domains, separated by X coord of first center point. # Chunking will be visible when transforms are changed. xCoord = centers[0][0] - start_pos[0] # Negate centering X. xPercent = (xCoord / (nSpheres + nSpheres/10 + nSpheres/100 - 1 + (nSpheres <= 1))) xTenth = int(xPercent * 10 + .5) csdl = ColorSortedDisplayList(TCs[xTenth % numTCs]) pass # Test selection using the CSDL glname. ColorSorter.pushName(csdl.glname) ColorSorter.start(glpane, csdl) for (color, center, radius) in zip(colors, centers, radii): if not doCylinders: # Through ColorSorter to the sphere primitive buffer... drawsphere(color, center, radius, DRAWSPHERE_DETAIL_LEVEL) else: # Through ColorSorter to cylinder primitive buffer... if not drawing_globals.cylinderShader_available(): print "warning: not cylinderShader_available(), error is likely:" if (True and # Whether to do tapered shader-cylinders. # Display List cylinders don't support taper. glpane.glprefs.cylinderShader_desired()): ###cylRad = (radius/2.0, (.75-radius)/2.0) cylRad = (radius/1.5 - .167, .3 - radius/1.5) else: cylRad = radius/2.0 pass endPt2 = center + V(0.5, 0.0, 0.0) # 0.5, -0.5) drawcylinder(color, center, endPt2, cylRad) global test_endpoints test_endpoints += [(center, endPt2)] pass continue ColorSorter.popName() ColorSorter.finish(draw_now = True) test_DrawingSet.addCSDL(csdl) return csdl if testCase == 8: #bruce 090223 revised to try to avoid traceback def chunkFn(centers, radii, colors): res = GLSphereBuffer() res.addSpheres(centers, radii, colors, None, None) return res pass else: chunkFn = primCSDL pass test_spheres = [] radius = .5 centers = [] radii = [] colors = [] global test_endpoints test_endpoints = [] for x in range(nSpheres): for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. thisRad = radius * (.5 + t*.5) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] # Put out short chunk buffers. if len(centers) >= chunkLength: test_spheres += [ chunkFn(centers, radii, colors) ] centers = [] radii = [] colors = [] continue continue # Remainder fraction buffer. if len(centers): test_spheres += [chunkFn(centers, radii, colors)] pass print "Setup time", time.time() - t1, "seconds." print "%d chunk buffers" % len(test_spheres) pass elif not initOnly: # Run. test_Draw_8x(glpane) pass elif testCase == 100: #bruce 090102 # before making more of these, modularize it somehow from commands.TestGraphics.test_selection_redraw import test_selection_redraw test_class = test_selection_redraw params = ( nSpheres, ) # note: test size is not directly comparable to other tests with same value of nSpheres if test_Object is None \ or not isinstance(test_Object, test_class) \ or test_Object.current_params() != params: # review: same_vals? # Setup. if test_Object: test_Object.destroy() test_Object = test_class(*params) test_Object.activate() print test_Object pass # review: safe to change elif to if? not sure, GL state is only initialized below elif not initOnly: # Run. test_Object.draw_complete() pass pass if not initOnly: glMatrixMode(GL_MODELVIEW) glFlush() pass first_time = False return
def drawDnaSingleRibbon(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = None, ribbon1_direction = None, peakDeviationFromCenter = 9.5, ribbonThickness = 2.0, ribbon1Color = None, stepColor = None): """ @see: drawDnaRibbons (method in this file) @see: DnaStrand_GraphicsMode._drawHandles() """ if 0: # debug code, useful to see where the argument points are located # [bruce 080422] draw_debug_text(glpane, endCenter1, "endCenter1") draw_debug_text(glpane, endCenter2, "endCenter2") draw_debug_text(glpane, ribbon1_start_point, "ribbon1_start_point") #Try to match the rubberband display style as closely as possible to #either the glpane's current display or the chunk display of the segment #being edited. The caller should do the job of specifying the display style #it desires. As of 2008-02-20, this method only supports following display #styles --Tubes, Ball and Stick, CPK and lines. the sphere radius #for ball and stick or CPK is calculated approximately. if displayStyle == diTrueCPK: SPHERE_RADIUS = 3.5 ribbonThickness = 2.0 elif displayStyle == diTUBES: SPHERE_RADIUS = 0.01 ribbonThickness = 5.0 elif displayStyle == diLINES: #Lines display and all other unsupported display styles SPHERE_RADIUS = 0.01 ribbonThickness = 1.0 else: #ball and stick display style. All other unsupported displays #will be rendered in ball and stick display style SPHERE_RADIUS = 1.0 ribbonThickness = 3.0 if stepColor is None: stepColor = env.prefs[DarkBackgroundContrastColor_prefs_key] ribbonLength = vlen(endCenter1 - endCenter2) #Don't draw the vertical line (step) passing through the startpoint unless #the ribbonLength is at least equal to the duplexRise. # i.e. do the drawing only when there are at least two ladder steps. # This prevents a 'revolving line' effect due to the single ladder step at # the first endpoint. It also means the dna duplex axis can be determined # below from the two endpoints. if ribbonLength < duplexRise: return unitVectorAlongLength = norm(endCenter2 - endCenter1) glDisable(GL_LIGHTING) ##glPushMatrix() ##glTranslatef(endCenter1[0], endCenter1[1], endCenter1[2]) ##pointOnAxis = V(0, 0, 0) pointOnAxis = endCenter1 axial_shift = V(0.0, 0.0, 0.0) # might be changed below # [these might be discarded and recomputed just below; # the case where they aren't is (and I think was) untested. # -- bruce 080422 comment] vectorAlongLadderStep = cross(-lineOfSightVector, unitVectorAlongLength) unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 if ribbon1_start_point is not None: # [revise the meaning of these values to give the coordinate system # with the right phase in which to draw the ribbon. # bruce 080422 bugfix] vectorAlongLadderStep0 = ribbon1_start_point - endCenter1 # note: this might not be perpendicular to duplex axis. # fix by subtracting off the parallel component. # but add the difference back to every point below. vectorAlongLadderStep = vectorAlongLadderStep0 - \ dot( unitVectorAlongLength, vectorAlongLadderStep0 ) * unitVectorAlongLength axial_shift = (vectorAlongLadderStep0 - vectorAlongLadderStep) # note: even using this, there is still a small glitch in the # location of the first drawn sphere vs. the ribbon point... don't # know why. [bruce 080422] unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 pass del vectorAlongLadderStep ###=== #Following limits the arrowHead Size to the given value. When you zoom out, #the rest of ladder drawing becomes smaller (expected) and the following #check ensures that the arrowheads are drawn proportionately. # (Not using a 'constant' to do this as using glpaneScale gives better #results) if glpaneScale > 40: arrowDrawingScale = 40 else: arrowDrawingScale = glpaneScale #Formula .. Its a Sine Wave. # y(x) = A.sin(2*pi*f*x + phase_angle) ------[1] # where -- # f = 1/T # A = Amplitude of the sine wave (or 'peak deviation from center') # y = y coordinate of the sine wave -- distance is in Angstroms # x = the x coordinate # phase_angle is computed for each wave. We know y at x =0. For example, # for ribbon_1, , at x = 0, y = A. Putting these values in equation [1] # we get the phase_angle. x = 0.0 T = duplexRise * basesPerTurn # The 'Period' of the sine wave # (i.e. peak to peak distance between consecutive crests) numberOfBasesDrawn = 0 theta_offset = 0 ## phase_angle_ribbon_1 = HALF_PI ## theta_ribbon_1 = (TWICE_PI * x / T) + phase_angle_ribbon_1 #Initialize ribbon1_point # [note: might not be needed, since identical to first point # computed during loop, but present code uses it to initialize # previous_ribbon1_point during loop [bruce 080422 comment]] ribbon1_point = _compute_ribbon_point(pointOnAxis + axial_shift, basesPerTurn, duplexRise, unitVectorAlongLength, unitVectorAlongLadderStep, unitDepthVector, peakDeviationFromCenter, numberOfBasesDrawn, theta_offset ) while x < ribbonLength: #Draw the axis point. drawPoint(stepColor, pointOnAxis) previousPointOnAxis = pointOnAxis previous_ribbon1_point = ribbon1_point ribbon1_point = _compute_ribbon_point(pointOnAxis + axial_shift, basesPerTurn, duplexRise, unitVectorAlongLength, unitVectorAlongLadderStep, unitDepthVector, peakDeviationFromCenter, numberOfBasesDrawn, theta_offset ) if x == duplexRise and ribbon1_direction == -1: # For ribbon_2 we need to draw an arrow head for y at x = 0. # To do this, we need the 'next ribbon_2' point in order to # compute the appropriate vectors. So when x = duplexRise, the # previous_ribbon2_point is nothing but y at x = 0. arrowLengthVector2 = norm(ribbon1_point - previous_ribbon1_point ) arrowHeightVector2 = cross(-lineOfSightVector, arrowLengthVector2) drawArrowHead( ribbon1Color, previous_ribbon1_point, arrowDrawingScale, -arrowHeightVector2, -arrowLengthVector2) # Draw sphere over previous_ribbon1_point and not ribbon1_point. # This is so we don't draw a sphere over the last point on ribbon1 # (instead, it is drawn as an arrowhead after the while loop). drawsphere(ribbon1Color, previous_ribbon1_point, SPHERE_RADIUS, SPHERE_DRAWLEVEL, opacity = SPHERE_OPACITY) drawline(stepColor, pointOnAxis, ribbon1_point) #Increment the pointOnAxis and x pointOnAxis = pointOnAxis + unitVectorAlongLength * duplexRise x += duplexRise numberOfBasesDrawn += 1 if previous_ribbon1_point: drawline(ribbon1Color, previous_ribbon1_point, ribbon1_point, width = ribbonThickness, isSmooth = True ) arrowLengthVector1 = norm(ribbon1_point - previous_ribbon1_point) arrowHeightVector1 = cross(-lineOfSightVector, arrowLengthVector1) pass continue # while x < ribbonLength if ribbon1_direction == 1: #Arrow head for endpoint of ribbon_1. drawArrowHead(ribbon1Color, ribbon1_point, arrowDrawingScale, arrowHeightVector1, arrowLengthVector1) #The second axis endpoint of the dna is drawn as a transparent sphere. #Note that the second axis endpoint is NOT NECESSARILY endCenter2 . In fact # those two are equal only at the ladder steps. In other case (when the # ladder step is not completed), the endCenter1 is ahead of the #'second axis endpoint of the dna' drawsphere(AXIS_ENDPOINT_SPHERE_COLOR, previousPointOnAxis, AXIS_ENDPOINT_SPHERE_RADIUS, AXIS_ENDPOINT_SPHERE_DRAWLEVEL, opacity = AXIS_ENDPOINT_SPHERE_OPACITY) ##glPopMatrix() glEnable(GL_LIGHTING) return # from drawDnaSingleRibbon
def draw(self): drawsphere(self.fix_color(self.color), self.center, self.radius, self.detailLevel)
def _drawSpecialIndicators(self): """ Overrides superclass method. This draws a transparent cylinder around the segments being resized, to easily distinguish them from other model. @see: basicGraphicsmode._drawSpecialIndicators() """ if self.command: if DEBUG_DRAW_SPHERES_AROUND_ATOMS_AT_BREAK_SITES: breakSitesDict = self._breakSite_marker.getBreakSitesDict() atmList = breakSitesDict.values() for atm in atmList: sphere_radius = max(1.2*atm.drawing_radius(), SPHERE_RADIUS) drawsphere(darkgreen, atm.posn(), sphere_radius, SPHERE_DRAWLEVEL, opacity = SPHERE_OPACITY) breakSites_atomPairs_dict = self._breakSite_marker.getBreakSites_atomPairsDict() for aDict in breakSites_atomPairs_dict.values(): #DEBUG======== for atm1, atm2 in aDict.values(): #Its okay to do this check for only atm1 (for speed reason) #lets assume that atm2 drawing radius will be the same (it won't #be the same in very rare cases....) cyl_radius = max(1.3*atm1.drawing_radius(), CYL_RADIUS) drawcylinder(red, atm1.posn(), atm2.posn(), cyl_radius, capped = True, opacity = CYL_OPACITY ) startAtomsDict = self._breakSite_marker.getStartAtomsDict() for atm in startAtomsDict.values(): sphere_radius = max(1.2*atm.drawing_radius(), SPHERE_RADIUS_2) color = atm.molecule.color if color is None: color = banana atom_radius = atm.drawing_radius() cyl_radius = 0.5*atom_radius cyl_height = 2.5*atom_radius axis_atm = atm.axis_neighbor() direction = None if axis_atm: #Direction will be opposite of direction = norm( atm.posn() - axis_atm.posn()) draw3DFlag(self.glpane, color, atm.posn(), cyl_radius, cyl_height, direction = direction, opacity = 0.8)
def _drawDnaRubberbandLine(self): """ Overrides superclass method. It loops through the segments being resized and draws the rubberband lines for all. NOT this could be SLOW @see: MultipleDnaSegmentResize_EditCommand.getDnaRibbonParams() for comments. @TODO: needs more cleanup """ handleType = '' if self.command.grabbedHandle is not None: if self.command.grabbedHandle in [self.command.rotationHandle1, self.command.rotationHandle2]: handleType = 'ROTATION_HANDLE' else: handleType = 'RESIZE_HANDLE' if handleType and handleType == 'RESIZE_HANDLE': for segment in self.command.getResizeSegmentList(): self.command.currentStruct = segment params_when_adding_bases, params_when_removing_bases = \ self.command.getDnaRibbonParams() self.command.currentStruct = None if params_when_adding_bases: numberOfBasePairs,\ end1, \ end2, \ basesPerTurn,\ duplexRise, \ ribbon1_start_point, \ ribbon2_start_point, \ ribbon1_direction, \ ribbon2_direction, \ ribbon1Color, \ ribbon2Color = params_when_adding_bases #Note: The displayStyle argument for the rubberband line should #really be obtained from self.command.struct. But the struct #is a DnaSegment (a Group) and doesn't have attr 'display' #Should we then obtain this information from one of its strandChunks? #but what if two strand chunks and axis chunk are rendered #in different display styles? since situation may vary, lets #use self.glpane.displayMode for rubberbandline displayMode drawDnaRibbons(self.glpane, end1, end2, basesPerTurn, duplexRise, self.glpane.scale, self.glpane.lineOfSight, self.glpane.displayMode, ribbonThickness = 4.0, ribbon1_start_point = ribbon1_start_point, ribbon2_start_point = ribbon2_start_point, ribbon1_direction = ribbon1_direction, ribbon2_direction = ribbon2_direction, ribbon1Color = ribbon1Color, ribbon2Color = ribbon2Color, stepColor = black ) #Draw a sphere that indicates the current position of #the resize end of each segment . drawsphere(env.prefs[selectionColor_prefs_key], end2, SPHERE_RADIUS_2, SPHERE_DRAWLEVEL, opacity = SPHERE_OPACITY) numberOfBasePairsString = "+" + str(numberOfBasePairs) self.glpane.renderTextAtPosition( end2, numberOfBasePairsString) elif params_when_removing_bases: numberOfBasePairs , end2 = params_when_removing_bases #Draw a sphere that indicates the current position of #the resize end of each segment. drawsphere(darkred, end2, SPHERE_RADIUS_2, SPHERE_DRAWLEVEL, opacity = SPHERE_OPACITY) numberOfBasePairsString = str(numberOfBasePairs) self.glpane.renderTextAtPosition( end2, textString = numberOfBasePairsString, ) #Draw the text next to the cursor that gives info about #number of base pairs etc self._drawCursorText()
def drawchunk(self, glpane, chunk, memo, highlighted): """ Draws reduced representation of a protein chunk. """ structure, total_length, ca_list, n_sec = memo style = self.proteinStyle scaleFactor = self.proteinStyleScaleFactor resolution = self.proteinStyleQuality scaling = self.proteinStyleScaling smooth = self.proteinStyleSmooth gleSetJoinStyle(TUBE_JN_ANGLE | TUBE_NORM_PATH_EDGE | TUBE_JN_CAP | TUBE_CONTOUR_CLOSED ) current_sec = 0 for sec, secondary in structure: # Number of atoms in SS element including dummy atoms. n_atoms = len(sec) # The length should be at least 3. if n_atoms >= 3: # Alpha carbon trace styles. Simple but fast. if style == PROTEIN_STYLE_CA_WIRE or \ style == PROTEIN_STYLE_CA_CYLINDER or \ style == PROTEIN_STYLE_CA_BALL_STICK: for n in range( 1, n_atoms-2 ): pos0, ss0, aa0, idx0, dpos0, cbpos0 = sec[n - 1] pos1, ss1, aa1, idx1, dpos1, cbpos1 = sec[n] pos2, ss2, aa2, idx2, dpos2, cbpos2 = sec[n + 1] color = self._get_aa_color(chunk, idx1, total_length, ss1, aa1, current_sec, n_sec) if style == PROTEIN_STYLE_CA_WIRE: if pos0: drawline(color, pos1 + 0.5 * (pos0 - pos1), pos1, width=5, isSmooth=True) if pos2: drawline(color, pos1, pos1 + 0.5 * (pos2 - pos1), width=5, isSmooth=True) else: if pos0: drawcylinder(color, pos1 + 0.5 * (pos0 - pos1), pos1, 0.25 * scaleFactor, capped=1) if style == PROTEIN_STYLE_CA_BALL_STICK: drawsphere(color, pos1, 0.5 * scaleFactor, 2) else: drawsphere(color, pos1, 0.25 * scaleFactor, 2) if pos2: drawcylinder(color, pos1, pos1 + 0.5 * (pos2 - pos1), 0.25 * scaleFactor, capped=1) elif style == PROTEIN_STYLE_PEPTIDE_TILES: for n in range( 1, n_atoms-2 ): pos0, ss0, aa0, idx0, dpos0, cbpos0 = sec[n - 1] pos1, ss1, aa1, idx1, dpos1, cbpos1 = sec[n] color = self._get_aa_color(chunk, idx1, total_length, ss1, aa1, current_sec, n_sec) tri = [] nor = [] col = [] elif style == PROTEIN_STYLE_TUBE or \ style == PROTEIN_STYLE_LADDER or \ style == PROTEIN_STYLE_ZIGZAG or \ style == PROTEIN_STYLE_FLAT_RIBBON or \ style == PROTEIN_STYLE_SOLID_RIBBON or \ style == PROTEIN_STYLE_SIMPLE_CARTOONS or \ style == PROTEIN_STYLE_FANCY_CARTOONS: tube_pos = [] tube_col = [] tube_rad = [] tube_dpos = [] for n in range( 2, n_atoms-2 ): pos00, ss00, a00, idx00, dpos00, cbpos00 = sec[n - 2] pos0, ss0, aa0, idx0, dpos0, cbpos0 = sec[n - 1] pos1, ss1, aa1, idx1, dpos1, cbpos1 = sec[n] pos2, ss2, aa2, idx2, dpos2, cbpos2 = sec[n + 1] pos22, ss22, aa22, idx22, dpos22, cbpos22 = sec[n + 2] color = self._get_aa_color(chunk, idx1, total_length, ss1, aa1, current_sec, n_sec) rad = 0.25 * scaleFactor if style == PROTEIN_STYLE_TUBE and \ scaling == 1: if secondary > 0: rad *= 2.0 if n == 2: if pos0: tube_pos.append(pos00) tube_col.append(V(color)) tube_rad.append(rad) tube_dpos.append(dpos1) tube_pos.append(pos0) tube_col.append(V(color)) tube_rad.append(rad) tube_dpos.append(dpos1) if style == PROTEIN_STYLE_LADDER: drawcylinder(color, pos1, cbpos1, rad * 0.75) drawsphere(color, cbpos1, rad * 1.5, 2) if pos1: tube_pos.append(pos1) tube_col.append(V(color)) tube_rad.append(rad) tube_dpos.append(dpos1) if n == n_atoms - 3: if pos2: tube_pos.append(pos2) tube_col.append(V(color)) tube_rad.append(rad) tube_dpos.append(dpos1) tube_pos.append(pos22) tube_col.append(V(color)) tube_rad.append(rad) tube_dpos.append(dpos1) # For smoothed helices we need to add virtual atoms # located approximately at the centers of peptide bonds # but slightly moved away from the helix axis. new_tube_pos = [] new_tube_col = [] new_tube_rad = [] new_tube_dpos = [] if smooth and \ secondary == 1: for p in range(len(tube_pos)): new_tube_pos.append(tube_pos[p]) new_tube_col.append(tube_col[p]) new_tube_rad.append(tube_rad[p]) new_tube_dpos.append(tube_dpos[p]) if p > 1 and p < len(tube_pos) - 3: pv = tube_pos[p-1] - tube_pos[p] nv = tube_pos[p+2] - tube_pos[p+1] mi = 0.5 * (tube_pos[p+1] + tube_pos[p]) # The coefficient below was handpicked to make # the helices approximately round. mi -= 0.75 * norm(nv+pv) new_tube_pos.append(mi) new_tube_col.append(0.5*(tube_col[p]+tube_col[p+1])) new_tube_rad.append(0.5*(tube_rad[p]+tube_rad[p+1])) new_tube_dpos.append(0.5*(tube_dpos[p]+tube_dpos[p+1])) tube_pos = new_tube_pos tube_col = new_tube_col tube_rad = new_tube_rad tube_dpos = new_tube_dpos if secondary != 1 or \ style != PROTEIN_STYLE_SIMPLE_CARTOONS: tube_pos, tube_col, tube_rad, tube_dpos = make_tube( tube_pos, tube_col, tube_rad, tube_dpos, resolution=resolution) if style == PROTEIN_STYLE_ZIGZAG or \ style == PROTEIN_STYLE_FLAT_RIBBON or \ style == PROTEIN_STYLE_SOLID_RIBBON or \ style == PROTEIN_STYLE_SIMPLE_CARTOONS or \ style == PROTEIN_STYLE_FANCY_CARTOONS: last_pos = None last_width = 1.0 reset = False # Find SS element widths and determine width increment. if secondary == 0: # Coils have a constant width. width = scaleFactor * 0.1 dw = 0.0 elif secondary == 1: # Helices expand and shrink at the ends. width = scaleFactor * 0.1 dw = (1.0 * scaleFactor) / (resolution - 3) else: # Strands just shrink at the C-terminal end. width = scaleFactor * 1.0 dw = (1.6 * scaleFactor) / (1.5 * resolution - 3) if style == PROTEIN_STYLE_FLAT_RIBBON or \ style == PROTEIN_STYLE_SOLID_RIBBON or \ style == PROTEIN_STYLE_SIMPLE_CARTOONS or \ style == PROTEIN_STYLE_FANCY_CARTOONS: tri_arr0 = [] nor_arr0 = [] col_arr0 = [] if style == PROTEIN_STYLE_SOLID_RIBBON or \ style == PROTEIN_STYLE_SIMPLE_CARTOONS or \ style == PROTEIN_STYLE_FANCY_CARTOONS: tri_arr1 = [] nor_arr1 = [] col_arr1 = [] tri_arr2 = [] nor_arr2 = [] col_arr2 = [] tri_arr3 = [] nor_arr3 = [] col_arr3 = [] from copy import copy new_tube_dpos = copy(tube_dpos) for n in range(1, len(tube_pos)-1): pos = tube_pos[n] col = tube_col[n][0] col2 = tube_col[n+1][0] if last_pos: next_pos = tube_pos[n+1] dpos1 = last_width * tube_dpos[n-1] dpos2 = width * tube_dpos[n] ddpos = dpos1-dpos2 if reset: dpos1 = dpos2 reset = False if self.proteinStyle == PROTEIN_STYLE_ZIGZAG: drawline(col, last_pos-dpos1, pos-dpos2, width=3) drawline(col, last_pos+dpos1, pos+dpos2, width=3) drawline(col, last_pos-dpos1, pos+dpos2, width=1) drawline(col, pos-dpos2, pos+dpos2, width=1) drawline(col, last_pos-dpos1, last_pos+dpos1, width=1) if self.proteinStyle == PROTEIN_STYLE_FLAT_RIBBON: if pos != last_pos: nvec1 = norm(cross(dpos1, pos-last_pos)) if next_pos != pos: nvec2 = norm(cross(dpos2, next_pos-pos)) else: nvec2 = nvec1 nor_arr0.append(nvec1) nor_arr0.append(nvec1) nor_arr0.append(nvec2) nor_arr0.append(nvec2) tri_arr0.append(last_pos-dpos1) tri_arr0.append(last_pos+dpos1) tri_arr0.append(pos-dpos2) tri_arr0.append(pos+dpos2) col_arr0.append(col) col_arr0.append(col) col_arr0.append(col2) col_arr0.append(col2) if self.proteinStyle == PROTEIN_STYLE_SOLID_RIBBON or \ self.proteinStyle == PROTEIN_STYLE_SIMPLE_CARTOONS or \ self.proteinStyle == PROTEIN_STYLE_FANCY_CARTOONS: if secondary > 0: col3 = col4 = V(gray) if pos != last_pos: nvec1 = norm(cross(dpos1, pos-last_pos)) if next_pos != pos: nvec2 = norm(cross(dpos2, next_pos-pos)) else: nvec2 = nvec1 nor_arr0.append(nvec1) nor_arr0.append(nvec1) nor_arr0.append(nvec2) nor_arr0.append(nvec2) if self.proteinStyle == PROTEIN_STYLE_FANCY_CARTOONS: dn1 = 0.15 * nvec1 * scaleFactor dn2 = 0.15 * nvec2 * scaleFactor else: dn1 = 0.15 * nvec1 * scaleFactor dn2 = 0.15 * nvec2 * scaleFactor tri_arr0.append(last_pos - dpos1 - dn1) tri_arr0.append(last_pos + dpos1 - dn1) tri_arr0.append(pos - dpos2 - dn2) tri_arr0.append(pos + dpos2 - dn2) col_arr0.append(col) col_arr0.append(col) col_arr0.append(col2) col_arr0.append(col2) nor_arr1.append(nvec1) nor_arr1.append(nvec1) nor_arr1.append(nvec2) nor_arr1.append(nvec2) tri_arr1.append(last_pos - dpos1 + dn1) tri_arr1.append(last_pos + dpos1 + dn1) tri_arr1.append(pos - dpos2 + dn2) tri_arr1.append(pos + dpos2 + dn2) if secondary == 1: col_arr1.append(0.5 * col + 0.5 * V(white)) col_arr1.append(0.5 * col + 0.5 * V(white)) col_arr1.append(0.5 * col2 + 0.5 * V(white)) col_arr1.append(0.5 * col2 + 0.5 * V(white)) else: col_arr1.append(col) col_arr1.append(col) col_arr1.append(col2) col_arr1.append(col2) nor_arr2.append(-dpos1) nor_arr2.append(-dpos1) nor_arr2.append(-dpos2) nor_arr2.append(-dpos2) tri_arr2.append(last_pos - dpos1 - dn1) tri_arr2.append(last_pos - dpos1 + dn1) tri_arr2.append(pos - dpos2 - dn2) tri_arr2.append(pos - dpos2 + dn2) col_arr2.append(col3) col_arr2.append(col3) col_arr2.append(col4) col_arr2.append(col4) nor_arr3.append(-dpos1) nor_arr3.append(-dpos1) nor_arr3.append(-dpos2) nor_arr3.append(-dpos2) tri_arr3.append(last_pos + dpos1 - dn1) tri_arr3.append(last_pos + dpos1 + dn1) tri_arr3.append(pos + dpos2 - dn2) tri_arr3.append(pos + dpos2 + dn2) col_arr3.append(col3) col_arr3.append(col3) col_arr3.append(col4) col_arr3.append(col4) last_pos = pos last_width = width if secondary == 1: if n > len(tube_pos) - resolution: width -= dw elif width < 1.0 * scaleFactor: width += dw if secondary == 2: if n == len(tube_pos) - 1.5 * resolution: width = scaleFactor * 1.6 reset = True if n > len(tube_pos) - 1.5 * resolution: width -= dw new_tube_dpos[n] = width * tube_dpos[n] ###drawcylinder(white, tube_pos[0], tube_pos[10], 1.0) if self.proteinStyle == PROTEIN_STYLE_FLAT_RIBBON: drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr0, nor_arr0, col_arr0) if self.proteinStyle == PROTEIN_STYLE_SOLID_RIBBON or \ self.proteinStyle == PROTEIN_STYLE_SIMPLE_CARTOONS or \ self.proteinStyle == PROTEIN_STYLE_FANCY_CARTOONS: if secondary == 0: drawpolycone_multicolor([0,0,0,-2], tube_pos, tube_col, tube_rad) else: if (secondary == 1 and self.proteinStyle == PROTEIN_STYLE_SOLID_RIBBON) or \ secondary == 2: drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr0, nor_arr0, col_arr0) drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr1, nor_arr1, col_arr1) drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr2, nor_arr2, col_arr2) drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr3, nor_arr3, col_arr3) # Fill in the strand N-terminal end. quad_tri = [] quad_nor = [] quad_col = [] quad_tri.append(tri_arr2[0]) quad_tri.append(tri_arr3[0]) quad_tri.append(tri_arr2[1]) quad_tri.append(tri_arr3[1]) quad_nor.append(nor_arr2[0]) quad_nor.append(nor_arr3[0]) quad_nor.append(nor_arr2[1]) quad_nor.append(nor_arr3[1]) quad_col.append(col_arr2[0]) quad_col.append(col_arr3[0]) quad_col.append(col_arr2[1]) quad_col.append(col_arr3[1]) drawtriangle_strip([1.0,1.0,1.0,-2.0],quad_tri,quad_nor,quad_col) if (secondary == 1 and self.proteinStyle == PROTEIN_STYLE_FANCY_CARTOONS): drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr0, nor_arr0, col_arr0) drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr1, nor_arr1, col_arr1) tube_pos_left = [] tube_pos_right = [] new_tube_dpos[0] *= 0.1 new_tube_dpos[1] *= 0.2 new_tube_dpos[-1] *= 0.1 new_tube_dpos[-2] *= 0.2 for p in range(len(tube_pos)): tube_pos_left.append(tube_pos[p] - new_tube_dpos[p]) tube_pos_right.append(tube_pos[p] + new_tube_dpos[p]) tube_rad[p] *= 0.75 drawpolycone_multicolor([0,0,0,-2], tube_pos_left, tube_col, tube_rad) drawpolycone_multicolor([0,0,0,-2], tube_pos_right, tube_col, tube_rad) # else: if (secondary == 1 and style == PROTEIN_STYLE_SIMPLE_CARTOONS): drawcylinder(tube_col[0][0], tube_pos[1], tube_pos[-3], 2.5, capped=1) #print "hopsa" if style == PROTEIN_STYLE_LADDER or \ style == PROTEIN_STYLE_TUBE: # Draw tube. drawpolycone_multicolor([0,0,0,-2], tube_pos, tube_col, tube_rad) # increase Sec. Str. element counter current_sec += 1