def drawbrick(color, center, axis, l, h, w, opacity=1.0): if len(color) == 3: color = (color[0], color[1], color[2], opacity) if opacity != 1.0: glDepthMask(GL_FALSE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) apply_material(color) glPushMatrix() glTranslatef(center[0], center[1], center[2]) ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes ## display problem on some platforms angle = -acos(axis[2]) * 180.0 / pi if (axis[2] * axis[2] >= 1.0): glRotate(angle, 0.0, 1.0, 0.0) else: glRotate(angle, axis[1], -axis[0], 0.0) glScale(h, w, l) #bruce 060302 revised the contents of solidCubeList while fixing bug 1595 glCallList(drawing_globals.solidCubeList) if opacity != 1.0: glDisable(GL_BLEND) glDepthMask(GL_TRUE) glPopMatrix() return
def drawbrick(color, center, axis, l, h, w, opacity = 1.0): if len(color) == 3: color = (color[0], color[1], color[2], opacity) if opacity != 1.0: glDepthMask(GL_FALSE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) apply_material(color) glPushMatrix() glTranslatef(center[0], center[1], center[2]) ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes ## display problem on some platforms angle = -acos(axis[2])*180.0/pi if (axis[2]*axis[2] >= 1.0): glRotate(angle, 0.0, 1.0, 0.0) else: glRotate(angle, axis[1], -axis[0], 0.0) glScale(h, w, l) #bruce 060302 revised the contents of solidCubeList while fixing bug 1595 glCallList(drawing_globals.solidCubeList) if opacity != 1.0: glDisable(GL_BLEND) glDepthMask(GL_TRUE) glPopMatrix() return
def draw_vertices(self): # Draw all the vbo defined in set_atoms if self.transparent: glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glDepthMask(GL_FALSE) if self.wireframe: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glEnableClientState(GL_VERTEX_ARRAY) self._vbo_v.bind_vertexes(3, GL_FLOAT) glEnableClientState(GL_NORMAL_ARRAY) self._vbo_n.bind_normals(GL_FLOAT) glEnableClientState(GL_COLOR_ARRAY) self._vbo_c.bind_colors(4, GL_UNSIGNED_BYTE) glDrawArrays(GL_TRIANGLES, 0, self._n_triangles) self._vbo_v.unbind() self._vbo_n.unbind() self._vbo_c.unbind() if self.transparent: glDisable(GL_BLEND) #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glDepthMask(GL_TRUE) if self.wireframe: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
def __enable_depth_test(self): """Enable depth test and faces culling. Needed to not render invisible vertices and triangles. """ glDepthMask(GL_TRUE) glDepthFunc(GL_LESS) glEnable(GL_DEPTH_TEST) glEnable(GL_STENCIL_TEST)
def __enable_depth_test(self): """Enable depth test and faces culling. Needed to not render invisible vertices and triangles. """ glDepthMask(GL_TRUE) glDepthFunc(GL_LESS) glCullFace(GL_FRONT) glEnable(GL_DEPTH_TEST) glEnable(GL_STENCIL_TEST)
def schedule(color, func, params): # staticmethod if ColorSorter.sorting: ColorSorter._add_to_sorter(color, func, params) else: ColorSorter._immediate += 1 # for benchmark/debug stats, mostly # 20060216 We know we can do this here because the stack is # only ever one element deep name = ColorSorter._gl_name_stack[-1] if name: glPushName(name) ## Don't check in immediate drawing, e.g. preDraw_glselect_dict. ## else: ## print "bug_1: attempt to push non-glname", name #Apply appropriate opacity for the object if it is specified #in the 'color' param. (Also do necessary things such as #call glBlendFunc it. -- Ninad 20071009 if len(color) == 4: opacity = color[3] else: opacity = 1.0 if opacity >= 0.0 and opacity != 1.0: glDepthMask(GL_FALSE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) elif opacity == -1: # piotr 080429: I replaced the " < 0" condition with " == -1" # The opacity flag is now used to signal either "unshaded # colors" (opacity == -1) or "multicolor object" (opacity == -2) glDisable(GL_LIGHTING) # Don't forget to re-enable it! glColor3fv(color[:3]) pass apply_material(color) func(params) # Call the draw worker function. if opacity > 0.0 and opacity != 1.0: glDisable(GL_BLEND) glDepthMask(GL_TRUE) elif opacity == -1: # piotr 080429: See my comment above. glEnable(GL_LIGHTING) if name: glPopName() return
def _endHighlight(self): """ Restore OpenGL settings changed by _preHighlight to standard values. """ glDepthMask(GL_TRUE) ## glEnable(GL_DEPTH_TEST) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) glDisable(GL_STENCIL_TEST) self.setDepthRange_Normal() glMatrixMode(GL_MODELVIEW) return
def draw(self): TextureManager.GetTexture(Platform.asOSPath(self.textureName)).bind() glDisable(GL_CULL_FACE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glDisable(GL_ALPHA_TEST) glDisable(GL_LIGHTING) glDepthMask(GL_FALSE) glColor4(1, 1, 1, 0.25) self._drawQuad(self.flowOffset) glColor4(1, 1, 1, 0.25) self._drawQuad(-self.flowOffset) glDepthMask(GL_TRUE) glEnable(GL_CULL_FACE)
def draw(self): TextureManager.GetTexture( Platform.asOSPath(self.textureName)).bind() glDisable(GL_CULL_FACE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) glDisable(GL_ALPHA_TEST) glDisable(GL_LIGHTING) glDepthMask( GL_FALSE ) glColor4(1, 1, 1, 0.25) self._drawQuad(self.flowOffset) glColor4(1, 1, 1, 0.25) self._drawQuad(-self.flowOffset) glDepthMask( GL_TRUE ) glEnable(GL_CULL_FACE)
def _preHighlight(self): ### TODO: rename; move into GLPane_minimal, use in GLPane.py """ Change OpenGL settings to prepare for highlighting. """ self.makeCurrent() glClear(GL_STENCIL_BUFFER_BIT) glDepthMask(GL_FALSE) # turn off depth writing (but not depth test) ## glDisable(GL_DEPTH_TEST) glStencilFunc(GL_ALWAYS, 1, 1) glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE) glEnable(GL_STENCIL_TEST) self.setDepthRange_Highlighting() glMatrixMode(GL_MODELVIEW) return
def _preHighlight( self ): ### TODO: rename; move into GLPane_minimal, use in GLPane.py """ Change OpenGL settings to prepare for highlighting. """ self.makeCurrent() glClear(GL_STENCIL_BUFFER_BIT) glDepthMask(GL_FALSE) # turn off depth writing (but not depth test) ## glDisable(GL_DEPTH_TEST) glStencilFunc(GL_ALWAYS, 1, 1) glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE) glEnable(GL_STENCIL_TEST) self.setDepthRange_Highlighting() glMatrixMode(GL_MODELVIEW) return
def _draw_highlighted_selobj(self, selobj, hicolor): # bruce 070920 split this out; 090311 renamed it """ Draw selobj in highlighted form, using its "selobj drawing interface" (not yet a formal interface; we use several methods including draw_in_abs_coords). Record the drawn pixels in the OpenGL stencil buffer to optimize future detection of the mouse remaining over the same selobj (to avoid redraws then). Assume we have standard modelview and projection matrices on entry, and restore that state on exit (copying or recreating it as we prefer). Note: Current implementation uses an extra level on the projection matrix stack by default (selobj can override this). This could be easily revised if desired. """ # draw the selobj as highlighted, and make provisions for fast test # (by external code) of mouse still being over it (using stencil buffer) # note: if selobj highlight is partly translucent or transparent (neither yet supported), # we might need to draw it depth-sorted with other translucent objects # (now drawn by some modes using Draw_after_highlighting, not depth-sorted or modularly); # but our use of the stencil buffer assumes it's drawn at the end (except for objects which # don't obscure it for purposes of highlighting hit-test). This will need to be thought through # carefully if there can be several translucent objects (meant to be opaque re hit-tests), # and traslucent highlighting. See also the comment about highlight_into_depth, below. [bruce 060724 comment] # first gather info needed to know what to do -- highlight color (and whether to draw that at all) # and whether object might be bigger when highlighted (affects whether depth write is needed now). assert hicolor is not None # bruce 070919 highlight_might_be_bigger = ( True ) # True is always ok; someday we might let some objects tell us this can be False # color-writing is needed here, iff the mode asked for it, for this selobj. # # Note: in current code this is always True (as assertion above implies), # but it's possible we'll decide to retain self.selobj even if its # hicolor is None, but just not draw it in that case, or even to draw it # in some ways and not others -- so just in case, keep this test for now. # [bruce 070919 comment] highlight_into_color = hicolor is not None if highlight_into_color: # depth-writing is needed here, if highlight might be drawn in front of not-yet-drawn transparent surfaces # (like Build mode water surface) -- otherwise they will look like they're in front of some of the highlighting # even though they're not. (In principle, the preDraw_glselect_dict call above needs to know whether this depth # writing occurred ###doc why. Probably we should store it into the object itself... ###@@@ review, then doit ) highlight_into_depth = highlight_might_be_bigger else: highlight_into_depth = False ###@@@ might also need to store 0 into obj...see discussion above if not highlight_into_depth: glDepthMask(GL_FALSE) # turn off depth writing (but not depth test) if not highlight_into_color: glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) # don't draw color pixels # Note: stencil buffer was cleared earlier in this paintGL call. glStencilFunc(GL_ALWAYS, 1, 1) # These args make sure stencil test always passes, so color is drawn if we want it to be, # and so we can tell whether depth test passes in glStencilOp (even if depth *writing* is disabled ###untested); # this also sets reference value of 1 for use by GL_REPLACE. # (Args are: func to say when drawing-test passes; ref value; comparison mask. # Warning: Passing -1 for reference value, to get all 1's, does not work -- it makes ref value 0!) glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE) # turn on stencil-buffer writing based on depth test # (args are: what to do on fail, zfail, zpass (see OpenGL "red book" p. 468)) glEnable(GL_STENCIL_TEST) # this enables both aspects of the test: effect on drawing, and use of stencil op (I think #k); # apparently they can't be enabled separately ##print glGetIntegerv( GL_STENCIL_REF) # Now "translate the world" slightly closer to the screen, # to ensure depth test passes for appropriate parts of highlight-drawing # even if roundoff errors would make it unreliable to just let equal depths pass the test. # As of 070921 we use glDepthRange for this. self.setDepthRange_Highlighting() try: colorsorter_safe = getattr(selobj, "_selobj_colorsorter_safe", False) # colorsorter_safe being False (in two places in this file) # is a bugfix for the breaking of expr handle highlighting # by the debug_pref('GLPane: highlight atoms in CSDLs?') # (but bug's cause is not understood) [bruce 090311] self.set_drawing_phase("selobj") # bruce 070124 # bruce 070329 moved set of drawing_phase from just after selobj.draw_in_abs_coords to just before it. # [This should fix the Qt4 transition issue which is the subject of reminder bug 2300, # though it can't be tested yet since it has no known effect on current code, only on future code.] def func(): self.graphicsMode.Draw_highlighted_selobj(self, selobj, hicolor) # TEST someday: test having color writing disabled here -- does stencil write still happen?? # (not urgent, since we definitely need color writing here.) return self._call_func_that_draws_objects(func, self.part, bare_primitives=colorsorter_safe) except: # try/except added for GL-state safety, bruce 061218 print_compact_traceback( "bug: exception in %r.Draw_highlighted_selobj for %r ignored: " % (self.graphicsMode, selobj) ) pass self.set_drawing_phase("?") self.setDepthRange_Normal() # restore other gl state # (but don't do unneeded OpenGL ops # in case that speeds up OpenGL drawing) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) # no need to undo glStencilFunc state, I think -- whoever cares will set it up again # when they reenable stenciling. if not highlight_into_color: glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) if not highlight_into_depth: glDepthMask(GL_TRUE) if debug_pref("GLPane: draw stencil buffer?", Choice_boolean_False, prefs_key=True): # draw stencil buffer in orange [bruce 090105] glStencilFunc(GL_EQUAL, 1, 1) # only draw where stencil is set glDepthMask(GL_FALSE) glDisable(GL_DEPTH_TEST) # Note: according to some web forum (not confirmed in red book or by test), # glDisable(GL_DEPTH_TEST) also disables depth writing, # so the above glDepthMask(GL_FALSE) is redundant. # This differs from my recollection, so should be checked if it matters. # [bruce 090105] self.draw_solid_color_everywhere(orange) # note: we already drew highlighting selobj above, so that won't obscure this glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) pass glDisable(GL_STENCIL_TEST) return # from _draw_highlighted_selobj
def draw(self): """ Draws the rulers. """ width = self.glpane.width height = self.glpane.height # These 3 attrs (scale, aspect, and ruler_position) are checked to # determine if they've changed. If any of them have, # getRulerDrawingParameters() must be called to get new drawing parms. if ( (self.scale != self.glpane.scale) or (self.zoomFactor != self.glpane.zoomFactor) or (self.aspect != self.glpane.aspect) or (self.ruler_position != env.prefs[rulerPosition_prefs_key]) ): self.scale = self.glpane.scale self.zoomFactor = self.glpane.zoomFactor self.aspect = self.glpane.aspect self.ruler_position = env.prefs[rulerPosition_prefs_key] self.ruler_drawing_params = getRulerDrawingParameters( width, height, self.aspect, self.scale, self.zoomFactor, self.ruler_position ) ( draw_ticks_and_text, units_text, units_format, units_scale, unit_label_inc, long_tickmark_inc, medium_tickmark_inc, num_vert_ticks, num_horz_ticks, tickmark_spacing_multiplier, ruler_origin, ruler_start_pt, units_text_origin, origin_square_pt1, origin_square_pt2, vr_thickness, vr_tickmark_spacing, vr_long_tick_len, vr_medium_tick_len, vr_short_tick_len, vr_rect_pt1, vr_rect_pt2, vr_line_pt1, vr_line_pt2, vr_units_x_offset, vr_units_y_offset, hr_thickness, hr_tickmark_spacing, hr_long_tick_len, hr_medium_tick_len, hr_short_tick_len, hr_rect_pt1, hr_rect_pt2, hr_line_pt1, hr_line_pt2, hr_units_x_offset, hr_units_y_offset, ) = self.ruler_drawing_params ruler_color = env.prefs[rulerColor_prefs_key] ruler_opacity = env.prefs[rulerOpacity_prefs_key] # These may become user preferences in the future. tickmark_color = darkgray text_color = black # Set up 2D (window) coordinate system. # Bruce - please review this section. glMatrixMode(GL_MODELVIEW) glPushMatrix() glLoadIdentity() glMatrixMode(GL_PROJECTION) glPushMatrix() glLoadIdentity() # needed! gluOrtho2D(0.0, float(width), 0.0, float(height)) glMatrixMode(GL_MODELVIEW) # About this glMatrixMode(GL_MODELVIEW) call, Bruce wrote in a review: # The only reason this is desirable (it's not really needed) is if, # when someone is editing the large body of drawing code after this, # they inadvertently do something which is only correct if the matrix # mode is GL_MODELVIEW (e.g. if they use glTranslate to shift a ruler # or tickmark position). Most of our drawing code assumes it can do # this, so a typical NE1 OpenGL programmer may naturally assume this, # which is why it's good to leave the matrix mode as GL_MODELVIEW when # entering into a large hunk of ordinary drawing code (especially if # it might call other drawing functions, now or in the future). # Mark 2008-03-03 glDisable(GL_LIGHTING) glDisable(GL_DEPTH_TEST) # Note: disabling GL_DEPTH_TEST is not honored by the 3d version of # glpane.renderText -- ruler text can still be obscured by # previously drawn less-deep model objects. # But the 2d call of renderText in part.py does honor this. # The Qt doc says why, if I guess how to interpret it: # http://doc.trolltech.com/4.3/qglwidget.html#renderText # says, for the 3d version of renderText only (passing three model # coords as opposed to two window coords): # Note that this function only works properly if GL_DEPTH_TEST # is enabled, and you have a properly initialized depth buffer. # Possible fixes: # - revise ruler_origin to be very close to the screen, # and hope that this disable is merely ignored, not a messup; # - or, use the 2d version of the function. # I did the latter fix (2d renderText, below) and it seems to work. # [bruce 081204 comment] # Suppress writing into the depth buffer so anything behind the ruler # can still be highlighted/selected. glDepthMask(GL_FALSE) # == Draw v/h ruler rectangles in the user defined color and opacity. glColor4fv(list(ruler_color) + [ruler_opacity]) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glRectf(origin_square_pt1[0], origin_square_pt1[1], origin_square_pt2[0], origin_square_pt2[1]) # Origin square if env.prefs[displayVertRuler_prefs_key]: glRectf(vr_rect_pt1[0], vr_rect_pt1[1], vr_rect_pt2[0], vr_rect_pt2[1]) # Vertical ruler if env.prefs[displayHorzRuler_prefs_key]: glRectf(hr_rect_pt1[0], hr_rect_pt1[1], hr_rect_pt2[0], hr_rect_pt2[1]) # Horizontal ruler glDisable(GL_BLEND) # Set color of ruler lines, tick marks and text. glColor3fv(tickmark_color) self.glpane.qglColor(RGBf_to_QColor(text_color)) # Draw unit of measurement in corner (A or nm). # piotr 080326: replaced drawText with drawCenteredText self.drawCenteredText(units_text, units_text_origin) # Kludge alert. Finish drawing ruler edge(s) if we will not be # drawing the ruler tick marks and text (only happens when the user # is zoomed out to an "absurd scale factor"). if not draw_ticks_and_text: if env.prefs[displayVertRuler_prefs_key]: self.drawLine(vr_line_pt1, vr_line_pt2) if env.prefs[displayHorzRuler_prefs_key]: self.drawLine(hr_line_pt1, hr_line_pt2) # == Draw vertical ruler line(s) and tick marks if env.prefs[displayVertRuler_prefs_key] and draw_ticks_and_text: # Draw vertical line along right/left edge of ruler. self.drawLine(vr_line_pt1, vr_line_pt2) # Initialize pt1 and pt2, the tick mark endpoints. The first tick # mark will span the entire width of the ruler, which serves as a # divider b/w the unit of measure text (i.e. A or nm) and the rest # of the ruler. pt1 = ruler_start_pt pt2 = ruler_start_pt + V(-vr_thickness, 0.0, 0.0) # Draw vertical ruler tickmarks, including numeric unit labels for tick_num in range(num_horz_ticks + 1): # pt1 and pt2 are modified by each iteration of the loop. self.drawLine(pt1, pt2) # Draw units number beside long tickmarks. if not tick_num % unit_label_inc: units_num_origin = pt1 + V(vr_units_x_offset, vr_units_y_offset, 0.0) units_num = units_format % (tick_num * units_scale) self.drawText(units_num, units_num_origin) # Update tickmark endpoints for next tickmark. pt1 = ruler_start_pt + V(0.0, vr_tickmark_spacing * tickmark_spacing_multiplier * (tick_num + 1), 0.0) if not (tick_num + 1) % long_tickmark_inc: pt2 = pt1 + V(vr_long_tick_len, 0.0, 0.0) elif not (tick_num + 1) % medium_tickmark_inc: pt2 = pt1 + V(vr_medium_tick_len, 0.0, 0.0) else: pt2 = pt1 + V(vr_short_tick_len, 0.0, 0.0) # End vertical ruler # == Draw horizontal ruler line(s) and tick marks if env.prefs[displayHorzRuler_prefs_key] and draw_ticks_and_text: # Draw horizontal line along top/bottom edge of ruler. self.drawLine(hr_line_pt1, hr_line_pt2) # Initialize pt1 and pt2, the tick mark endpoints. The first tick # mark will span the entire width of the ruler, which serves as a # divider b/w the unit of measure text (i.e. A or nm) and the rest # of the ruler. pt1 = ruler_start_pt pt2 = ruler_start_pt + V(0.0, -hr_thickness, 0.0) # Draw horizontal ruler (with vertical) tickmarks, including its # numeric unit labels for tick_num in range(num_vert_ticks + 1): # pt1 and pt2 are modified by each iteration of the loop. self.drawLine(pt1, pt2) # Draw units number beside long tickmarks. if not tick_num % unit_label_inc: units_num_origin = pt1 + V(hr_units_x_offset, hr_units_y_offset, 0.0) units_num = units_format % (tick_num * units_scale) self.drawText(units_num, units_num_origin) # Update tickmark endpoints for next tickmark. pt1 = ruler_start_pt + V(hr_tickmark_spacing * tickmark_spacing_multiplier * (tick_num + 1), 0.0, 0.0) if not (tick_num + 1) % long_tickmark_inc: pt2 = pt1 + V(0.0, hr_long_tick_len, 0.0) elif not (tick_num + 1) % medium_tickmark_inc: pt2 = pt1 + V(0.0, hr_medium_tick_len, 0.0) else: pt2 = pt1 + V(0.0, hr_short_tick_len, 0.0) # End horizontal ruler # Restore OpenGL state. glDepthMask(GL_TRUE) glEnable(GL_DEPTH_TEST) glEnable(GL_LIGHTING) glDepthMask(GL_TRUE) glMatrixMode(GL_PROJECTION) glPopMatrix() glMatrixMode(GL_MODELVIEW) glPopMatrix() return # from drawRulers
def drawHeightfield(color, w, h, textureReady, opacity, SOLID = False, pickCheckOnly = False, hf = None): """ Draw a heighfield using vertex and normal arrays. Optionally, it could be texture mapped. @pickCheckOnly This is used to draw the geometry only, used for OpenGL pick selection purpose. """ if not hf: # Return if heightfield is not provided return glEnable(GL_COLOR_MATERIAL) glEnable(GL_LIGHTING) # Don't use opacity, otherwise the heighfield polygons should be sorted # - something to implement later... ## glColor3v(list(color)) if textureReady: # For texturing, use white color (to be modulated by the texture) glColor3f(1,1,1) else: glColor3fv(list(color)) glPushMatrix() glScalef(w, h, 1.0) if SOLID: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) else: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glDisable(GL_CULL_FACE) if not pickCheckOnly: glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) if textureReady: glEnable(GL_TEXTURE_2D) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) glEnableClientState(GL_TEXTURE_COORD_ARRAY) for tstrip_vert, tstrip_norm, tstrip_tex in hf: glVertexPointer(3, GL_FLOAT, 0, tstrip_vert) glNormalPointer(GL_FLOAT, 0, tstrip_norm) glTexCoordPointer(2, GL_FLOAT, 0, tstrip_tex) glDrawArrays(GL_TRIANGLE_STRIP, 0, len(tstrip_vert)) glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) glDisableClientState(GL_TEXTURE_COORD_ARRAY) glDisable(GL_COLOR_MATERIAL) if not pickCheckOnly: if textureReady: glDisable(GL_TEXTURE_2D) glDepthMask(GL_TRUE) glEnable(GL_CULL_FACE) if not SOLID: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glPopMatrix() glEnable(GL_LIGHTING) return
def _draw_highlighted_selobj(self, selobj, hicolor): #bruce 070920 split this out; 090311 renamed it """ Draw selobj in highlighted form, using its "selobj drawing interface" (not yet a formal interface; we use several methods including draw_in_abs_coords). Record the drawn pixels in the OpenGL stencil buffer to optimize future detection of the mouse remaining over the same selobj (to avoid redraws then). Assume we have standard modelview and projection matrices on entry, and restore that state on exit (copying or recreating it as we prefer). Note: Current implementation uses an extra level on the projection matrix stack by default (selobj can override this). This could be easily revised if desired. """ # draw the selobj as highlighted, and make provisions for fast test # (by external code) of mouse still being over it (using stencil buffer) # note: if selobj highlight is partly translucent or transparent (neither yet supported), # we might need to draw it depth-sorted with other translucent objects # (now drawn by some modes using Draw_after_highlighting, not depth-sorted or modularly); # but our use of the stencil buffer assumes it's drawn at the end (except for objects which # don't obscure it for purposes of highlighting hit-test). This will need to be thought through # carefully if there can be several translucent objects (meant to be opaque re hit-tests), # and traslucent highlighting. See also the comment about highlight_into_depth, below. [bruce 060724 comment] # first gather info needed to know what to do -- highlight color (and whether to draw that at all) # and whether object might be bigger when highlighted (affects whether depth write is needed now). assert hicolor is not None #bruce 070919 highlight_might_be_bigger = True # True is always ok; someday we might let some objects tell us this can be False # color-writing is needed here, iff the mode asked for it, for this selobj. # # Note: in current code this is always True (as assertion above implies), # but it's possible we'll decide to retain self.selobj even if its # hicolor is None, but just not draw it in that case, or even to draw it # in some ways and not others -- so just in case, keep this test for now. # [bruce 070919 comment] highlight_into_color = (hicolor is not None) if highlight_into_color: # depth-writing is needed here, if highlight might be drawn in front of not-yet-drawn transparent surfaces # (like Build mode water surface) -- otherwise they will look like they're in front of some of the highlighting # even though they're not. (In principle, the preDraw_glselect_dict call above needs to know whether this depth # writing occurred ###doc why. Probably we should store it into the object itself... ###@@@ review, then doit ) highlight_into_depth = highlight_might_be_bigger else: highlight_into_depth = False ###@@@ might also need to store 0 into obj...see discussion above if not highlight_into_depth: glDepthMask( GL_FALSE) # turn off depth writing (but not depth test) if not highlight_into_color: glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) # don't draw color pixels # Note: stencil buffer was cleared earlier in this paintGL call. glStencilFunc(GL_ALWAYS, 1, 1) # These args make sure stencil test always passes, so color is drawn if we want it to be, # and so we can tell whether depth test passes in glStencilOp (even if depth *writing* is disabled ###untested); # this also sets reference value of 1 for use by GL_REPLACE. # (Args are: func to say when drawing-test passes; ref value; comparison mask. # Warning: Passing -1 for reference value, to get all 1's, does not work -- it makes ref value 0!) glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE) # turn on stencil-buffer writing based on depth test # (args are: what to do on fail, zfail, zpass (see OpenGL "red book" p. 468)) glEnable(GL_STENCIL_TEST) # this enables both aspects of the test: effect on drawing, and use of stencil op (I think #k); # apparently they can't be enabled separately ##print glGetIntegerv( GL_STENCIL_REF) # Now "translate the world" slightly closer to the screen, # to ensure depth test passes for appropriate parts of highlight-drawing # even if roundoff errors would make it unreliable to just let equal depths pass the test. # As of 070921 we use glDepthRange for this. self.setDepthRange_Highlighting() try: colorsorter_safe = getattr(selobj, '_selobj_colorsorter_safe', False) # colorsorter_safe being False (in two places in this file) # is a bugfix for the breaking of expr handle highlighting # by the debug_pref('GLPane: highlight atoms in CSDLs?') # (but bug's cause is not understood) [bruce 090311] self.set_drawing_phase('selobj') #bruce 070124 #bruce 070329 moved set of drawing_phase from just after selobj.draw_in_abs_coords to just before it. # [This should fix the Qt4 transition issue which is the subject of reminder bug 2300, # though it can't be tested yet since it has no known effect on current code, only on future code.] def func(): self.graphicsMode.Draw_highlighted_selobj( self, selobj, hicolor) # TEST someday: test having color writing disabled here -- does stencil write still happen?? # (not urgent, since we definitely need color writing here.) return self._call_func_that_draws_objects( func, self.part, bare_primitives=colorsorter_safe) except: # try/except added for GL-state safety, bruce 061218 print_compact_traceback( "bug: exception in %r.Draw_highlighted_selobj for %r ignored: " % \ (self.graphicsMode, selobj) ) pass self.set_drawing_phase('?') self.setDepthRange_Normal() # restore other gl state # (but don't do unneeded OpenGL ops # in case that speeds up OpenGL drawing) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) # no need to undo glStencilFunc state, I think -- whoever cares will set it up again # when they reenable stenciling. if not highlight_into_color: glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) if not highlight_into_depth: glDepthMask(GL_TRUE) if debug_pref("GLPane: draw stencil buffer?", Choice_boolean_False, prefs_key=True): # draw stencil buffer in orange [bruce 090105] glStencilFunc(GL_EQUAL, 1, 1) # only draw where stencil is set glDepthMask(GL_FALSE) glDisable(GL_DEPTH_TEST) # Note: according to some web forum (not confirmed in red book or by test), # glDisable(GL_DEPTH_TEST) also disables depth writing, # so the above glDepthMask(GL_FALSE) is redundant. # This differs from my recollection, so should be checked if it matters. # [bruce 090105] self.draw_solid_color_everywhere(orange) # note: we already drew highlighting selobj above, so that won't obscure this glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) pass glDisable(GL_STENCIL_TEST) return # from _draw_highlighted_selobj
def drawPlane(color, w, h, textureReady, opacity, SOLID=False, pickCheckOnly=False, tex_coords=None): """ Draw polygon with size of <w>*<h> and with color <color>. Optionally, it could be texuture mapped, translucent. @pickCheckOnly This is used to draw the geometry only, used for OpenGL pick selection purpose. """ vs = [[-0.5, 0.5, 0.0], [-0.5, -0.5, 0.0], [0.5, -0.5, 0.0], [0.5, 0.5, 0.0]] # piotr 080529: use external texture coordinates if provided if tex_coords is None: vt = [[0.0, 1.0], [0.0, 0.0], [1.0, 0.0], [1.0, 1.0]] else: vt = tex_coords if textureReady: opacity = 1.0 glDisable(GL_LIGHTING) glColor4fv(list(color) + [opacity]) glPushMatrix() glScalef(w, h, 1.0) if SOLID: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) else: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glDisable(GL_CULL_FACE) if not pickCheckOnly: # This makes sure a translucent object will not occlude another # translucent object. glDepthMask(GL_FALSE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) if textureReady: glEnable(GL_TEXTURE_2D) glBegin(GL_QUADS) for ii in range(len(vs)): t = vt[ii]; v = vs[ii] if textureReady: glTexCoord2fv(t) glVertex3fv(v) glEnd() if not pickCheckOnly: if textureReady: glDisable(GL_TEXTURE_2D) glDisable(GL_BLEND) glDepthMask(GL_TRUE) glEnable(GL_CULL_FACE) if not SOLID: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glPopMatrix() glEnable(GL_LIGHTING) return
def drawHeightfield(color, w, h, textureReady, opacity, SOLID=False, pickCheckOnly=False, hf=None): """ Draw a heighfield using vertex and normal arrays. Optionally, it could be texuture mapped. @pickCheckOnly This is used to draw the geometry only, used for OpenGL pick selection purpose. """ from OpenGL.GL import glTexEnvf from OpenGL.GL import GL_TEXTURE_ENV from OpenGL.GL import GL_TEXTURE_ENV_MODE from OpenGL.GL import GL_MODULATE from OpenGL.GL import glVertexPointer from OpenGL.GL import glNormalPointer from OpenGL.GL import glTexCoordPointer from OpenGL.GL import glDrawArrays from OpenGL.GL import glEnableClientState from OpenGL.GL import GL_VERTEX_ARRAY from OpenGL.GL import GL_NORMAL_ARRAY from OpenGL.GL import GL_TEXTURE_COORD_ARRAY glEnable(GL_COLOR_MATERIAL) glEnable(GL_LIGHTING) ### glColor4fv(list(color) + [opacity]) ### glColor3fv(list(color)) glColor3f(1.0, 1.0, 1.0) glPushMatrix() glScalef(w, h, 1.0) if SOLID: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) else: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glDisable(GL_CULL_FACE) if not pickCheckOnly: glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) if textureReady: glEnable(GL_TEXTURE_2D) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) glEnableClientState(GL_TEXTURE_COORD_ARRAY) for tstrip_vert, tstrip_norm, tstrip_tex in hf: glVertexPointer(3, GL_FLOAT, 0, tstrip_vert) glNormalPointer(GL_FLOAT, 0, tstrip_norm) glTexCoordPointer(2, GL_FLOAT, 0, tstrip_tex) glDrawArrays(GL_TRIANGLE_STRIP, 0, len(tstrip_vert)) glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) glDisableClientState(GL_TEXTURE_COORD_ARRAY) glDisable(GL_COLOR_MATERIAL) if not pickCheckOnly: if textureReady: glDisable(GL_TEXTURE_2D) glDepthMask(GL_TRUE) glEnable(GL_CULL_FACE) if not SOLID: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glPopMatrix() glEnable(GL_LIGHTING) return
def run(): #Start OpenGL and ask it for an OpenGL context pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode( SCREEN_SIZE, pygame.HWSURFACE | pygame.OPENGL | pygame.DOUBLEBUF) #The first thing we do is print some OpenGL details and check that we have a good enough version print("OpenGL Implementation Details:") if glGetString(GL_VENDOR): print("\tGL_VENDOR: {}".format(glGetString(GL_VENDOR).decode())) if glGetString(GL_RENDERER): print("\tGL_RENDERER: {}".format(glGetString(GL_RENDERER).decode())) if glGetString(GL_VERSION): print("\tGL_VERSION: {}".format(glGetString(GL_VERSION).decode())) if glGetString(GL_SHADING_LANGUAGE_VERSION): print("\tGL_SHADING_LANGUAGE_VERSION: {}".format( glGetString(GL_SHADING_LANGUAGE_VERSION).decode())) major_version = int( glGetString(GL_VERSION).decode().split()[0].split('.')[0]) minor_version = int( glGetString(GL_VERSION).decode().split()[0].split('.')[1]) if major_version < 3 or (major_version < 3 and minor_version < 0): print("OpenGL version must be at least 3.0 (found {0})".format( glGetString(GL_VERSION).decode().split()[0])) #Now onto the OpenGL initialisation #Set up depth culling glEnable(GL_CULL_FACE) glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) glDepthFunc(GL_LEQUAL) glDepthRange(0.0, 1.0) #We create out shaders which do little more than set a flat colour for each face VERTEX_SHADER = shaders.compileShader( b""" #version 130 in vec4 position; in vec4 normal; uniform mat4 projectionMatrix; uniform mat4 viewMatrix; uniform mat4 modelMatrix; flat out float theColor; void main() { vec4 temp = modelMatrix * position; temp = viewMatrix * temp; gl_Position = projectionMatrix * temp; theColor = clamp(abs(dot(normalize(normal.xyz), normalize(vec3(0.9,0.1,0.5)))), 0, 1); } """, GL_VERTEX_SHADER) FRAGMENT_SHADER = shaders.compileShader( b""" #version 130 flat in float theColor; out vec4 outputColor; void main() { outputColor = vec4(1.0, 0.5, theColor, 1.0); } """, GL_FRAGMENT_SHADER) shader = shaders.compileProgram(VERTEX_SHADER, FRAGMENT_SHADER) #And then grab our attribute locations from it glBindAttribLocation(shader, 0, b"position") glBindAttribLocation(shader, 1, b"normal") #Create the Vertex Array Object to hold our volume mesh vertexArrayObject = GLuint(0) glGenVertexArrays(1, vertexArrayObject) glBindVertexArray(vertexArrayObject) #Create the index buffer object indexPositions = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER, usage=GL_STATIC_DRAW) #Create the VBO vertexPositions = vbo.VBO(vertices, usage=GL_STATIC_DRAW) #Bind our VBOs and set up our data layout specifications with indexPositions, vertexPositions: glEnableVertexAttribArray(0) glVertexAttribPointer(0, 3, GL_FLOAT, False, 6 * vertices.dtype.itemsize, vertexPositions + (0 * vertices.dtype.itemsize)) glEnableVertexAttribArray(1) glVertexAttribPointer(1, 3, GL_FLOAT, False, 6 * vertices.dtype.itemsize, vertexPositions + (3 * vertices.dtype.itemsize)) glBindVertexArray(0) glDisableVertexAttribArray(0) #Now grab out transformation martix locations modelMatrixUnif = glGetUniformLocation(shader, b"modelMatrix") viewMatrixUnif = glGetUniformLocation(shader, b"viewMatrix") projectionMatrixUnif = glGetUniformLocation(shader, b"projectionMatrix") modelMatrix = np.array([[1.0, 0.0, 0.0, -32.0], [0.0, 1.0, 0.0, -32.0], [0.0, 0.0, 1.0, -32.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') viewMatrix = np.array([[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, -50.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') projectionMatrix = np.array([[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], dtype='f') #These next few lines just set up our camera frustum fovDeg = 45.0 frustumScale = 1.0 / tan(radians(fovDeg) / 2.0) zNear = 1.0 zFar = 1000.0 projectionMatrix[0][0] = frustumScale projectionMatrix[1][1] = frustumScale projectionMatrix[2][2] = (zFar + zNear) / (zNear - zFar) projectionMatrix[2][3] = -1.0 projectionMatrix[3][2] = (2 * zFar * zNear) / (zNear - zFar) #viewMatrix and projectionMatrix don't change ever so just set them once here with shader: glUniformMatrix4fv(projectionMatrixUnif, 1, GL_TRUE, projectionMatrix) glUniformMatrix4fv(viewMatrixUnif, 1, GL_TRUE, viewMatrix) #These are used to track the rotation of the volume LastFrameMousePos = (0, 0) CurrentMousePos = (0, 0) xRotation = 0 yRotation = 0 while True: clock.tick() for event in pygame.event.get(): if event.type == pygame.QUIT: return if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: return if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: CurrentMousePos = event.pos LastFrameMousePos = CurrentMousePos if event.type == pygame.MOUSEMOTION and 1 in event.buttons: CurrentMousePos = event.pos diff = (CurrentMousePos[0] - LastFrameMousePos[0], CurrentMousePos[1] - LastFrameMousePos[1]) xRotation += event.rel[0] yRotation += event.rel[1] LastFrameMousePos = CurrentMousePos glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #Perform the rotation of the mesh moveToOrigin = np.array( [[1.0, 0.0, 0.0, -32.0], [0.0, 1.0, 0.0, -32.0], [0.0, 0.0, 1.0, -32.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') rotateAroundX = np.array( [[1.0, 0.0, 0.0, 0.0], [0.0, cos(radians(yRotation)), -sin(radians(yRotation)), 0.0], [0.0, sin(radians(yRotation)), cos(radians(yRotation)), 0.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') rotateAroundY = np.array( [[cos(radians(xRotation)), 0.0, sin(radians(xRotation)), 0.0], [0.0, 1.0, 0.0, 0.0], [-sin(radians(xRotation)), 0.0, cos(radians(xRotation)), 0.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') modelMatrix = rotateAroundY.dot(rotateAroundX.dot(moveToOrigin)) with shader: glUniformMatrix4fv(modelMatrixUnif, 1, GL_TRUE, modelMatrix) glBindVertexArray(vertexArrayObject) glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None) glBindVertexArray(0) # Show the screen pygame.display.flip()
def drawHeightfield(color, w, h, textureReady, opacity, SOLID=False, pickCheckOnly=False, hf=None): """ Draw a heighfield using vertex and normal arrays. Optionally, it could be texture mapped. @pickCheckOnly This is used to draw the geometry only, used for OpenGL pick selection purpose. """ if not hf: # Return if heightfield is not provided return glEnable(GL_COLOR_MATERIAL) glEnable(GL_LIGHTING) # Don't use opacity, otherwise the heighfield polygons should be sorted # - something to implement later... ## glColor3v(list(color)) if textureReady: # For texturing, use white color (to be modulated by the texture) glColor3f(1, 1, 1) else: glColor3fv(list(color)) glPushMatrix() glScalef(w, h, 1.0) if SOLID: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) else: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glDisable(GL_CULL_FACE) if not pickCheckOnly: glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) if textureReady: glEnable(GL_TEXTURE_2D) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) glEnableClientState(GL_TEXTURE_COORD_ARRAY) for tstrip_vert, tstrip_norm, tstrip_tex in hf: glVertexPointer(3, GL_FLOAT, 0, tstrip_vert) glNormalPointer(GL_FLOAT, 0, tstrip_norm) glTexCoordPointer(2, GL_FLOAT, 0, tstrip_tex) glDrawArrays(GL_TRIANGLE_STRIP, 0, len(tstrip_vert)) glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) glDisableClientState(GL_TEXTURE_COORD_ARRAY) glDisable(GL_COLOR_MATERIAL) if not pickCheckOnly: if textureReady: glDisable(GL_TEXTURE_2D) glDepthMask(GL_TRUE) glEnable(GL_CULL_FACE) if not SOLID: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glPopMatrix() glEnable(GL_LIGHTING) return
def drawPlane(color, w, h, textureReady, opacity, SOLID=False, pickCheckOnly=False, tex_coords=None): """ Draw polygon with size of <w>*<h> and with color <color>. Optionally, it could be texuture mapped, translucent. @pickCheckOnly This is used to draw the geometry only, used for OpenGL pick selection purpose. @param tex_coords: texture coordinates to be explicitly provided (for simple image transformation purposes) """ vs = [[-0.5, 0.5, 0.0], [-0.5, -0.5, 0.0], [0.5, -0.5, 0.0], [0.5, 0.5, 0.0]] # piotr 080529: use external texture coordinates if provided if tex_coords is None: vt = [[0.0, 1.0], [0.0, 0.0], [1.0, 0.0], [1.0, 1.0]] else: vt = tex_coords if textureReady: opacity = 1.0 glDisable(GL_LIGHTING) glColor4fv(list(color) + [opacity]) glPushMatrix() glScalef(w, h, 1.0) if SOLID: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) else: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glDisable(GL_CULL_FACE) if not pickCheckOnly: # This makes sure a translucent object will not occlude another # translucent object. glDepthMask(GL_FALSE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) if textureReady: glEnable(GL_TEXTURE_2D) glBegin(GL_QUADS) for ii in range(len(vs)): t = vt[ii] v = vs[ii] if textureReady: glTexCoord2fv(t) glVertex3fv(v) glEnd() if not pickCheckOnly: if textureReady: glDisable(GL_TEXTURE_2D) glDisable(GL_BLEND) glDepthMask(GL_TRUE) glEnable(GL_CULL_FACE) if not SOLID: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glPopMatrix() glEnable(GL_LIGHTING) return
def draw(self): """ Draws the rulers. """ width = self.glpane.width height = self.glpane.height # These 3 attrs (scale, aspect, and ruler_position) are checked to # determine if they've changed. If any of them have, # getRulerDrawingParameters() must be called to get new drawing parms. if (self.scale != self.glpane.scale) or \ (self.zoomFactor != self.glpane.zoomFactor) or \ (self.aspect != self.glpane.aspect) or \ (self.ruler_position != env.prefs[rulerPosition_prefs_key]): self.scale = self.glpane.scale self.zoomFactor = self.glpane.zoomFactor self.aspect = self.glpane.aspect self.ruler_position = env.prefs[rulerPosition_prefs_key] self.ruler_drawing_params = \ getRulerDrawingParameters(width, height, self.aspect, self.scale, self.zoomFactor, self.ruler_position) (draw_ticks_and_text, units_text, units_format, units_scale, unit_label_inc, long_tickmark_inc, medium_tickmark_inc, num_vert_ticks, num_horz_ticks, tickmark_spacing_multiplier, ruler_origin, ruler_start_pt, units_text_origin, origin_square_pt1, origin_square_pt2, vr_thickness, vr_tickmark_spacing, vr_long_tick_len, vr_medium_tick_len, vr_short_tick_len, vr_rect_pt1, vr_rect_pt2, vr_line_pt1, vr_line_pt2, vr_units_x_offset, vr_units_y_offset, hr_thickness, hr_tickmark_spacing, hr_long_tick_len, hr_medium_tick_len, hr_short_tick_len, hr_rect_pt1, hr_rect_pt2, hr_line_pt1, hr_line_pt2, hr_units_x_offset, hr_units_y_offset) = self.ruler_drawing_params ruler_color = env.prefs[rulerColor_prefs_key] ruler_opacity = env.prefs[rulerOpacity_prefs_key] # These may become user preferences in the future. tickmark_color = darkgray text_color = black # Set up 2D (window) coordinate system. # Bruce - please review this section. glMatrixMode(GL_MODELVIEW) glPushMatrix() glLoadIdentity() glMatrixMode(GL_PROJECTION) glPushMatrix() glLoadIdentity() # needed! gluOrtho2D(0.0, float(width), 0.0, float(height)) glMatrixMode(GL_MODELVIEW) # About this glMatrixMode(GL_MODELVIEW) call, Bruce wrote in a review: # The only reason this is desirable (it's not really needed) is if, # when someone is editing the large body of drawing code after this, # they inadvertently do something which is only correct if the matrix # mode is GL_MODELVIEW (e.g. if they use glTranslate to shift a ruler # or tickmark position). Most of our drawing code assumes it can do # this, so a typical NE1 OpenGL programmer may naturally assume this, # which is why it's good to leave the matrix mode as GL_MODELVIEW when # entering into a large hunk of ordinary drawing code (especially if # it might call other drawing functions, now or in the future). # Mark 2008-03-03 glDisable(GL_LIGHTING) glDisable(GL_DEPTH_TEST) # Suppress writing into the depth buffer so anything behind the ruler # can still be highlighted/selected. glDepthMask(GL_FALSE) # Draw v/h ruler rectangles in the user defined color and opacity. ##### glColor4fv(list(ruler_color) + [ruler_opacity]) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glRectf(origin_square_pt1[0], origin_square_pt1[1], origin_square_pt2[0], origin_square_pt2[1]) # Origin square if env.prefs[displayVertRuler_prefs_key]: glRectf(vr_rect_pt1[0], vr_rect_pt1[1], vr_rect_pt2[0], vr_rect_pt2[1]) # Vertical ruler if env.prefs[displayHorzRuler_prefs_key]: glRectf(hr_rect_pt1[0], hr_rect_pt1[1], hr_rect_pt2[0], hr_rect_pt2[1]) # Horizontal ruler glDisable(GL_BLEND) # Set color of ruler lines, tick marks and text. glColor3fv(tickmark_color) self.glpane.qglColor(RGBf_to_QColor(text_color)) # Draw unit of measurement in corner (A or nm). # piotr 080326: replaced drawText with drawCenteredText self.drawCenteredText(units_text, units_text_origin) # Kludge alert. Finish drawing ruler edge(s) if we will not be # drawing the ruler tick marks and text (only happens when the user # is zoomed out to an "absured scale factor". if not draw_ticks_and_text: if env.prefs[displayVertRuler_prefs_key]: self.drawLine(vr_line_pt1, vr_line_pt2) if env.prefs[displayHorzRuler_prefs_key]: self.drawLine(hr_line_pt1, hr_line_pt2) # Draw vertical ruler line(s) and tick marks ########################## if env.prefs[displayVertRuler_prefs_key] and draw_ticks_and_text: # Draw vertical line along right/left edge of ruler. self.drawLine(vr_line_pt1, vr_line_pt2) # Initialize pt1 and pt2, the tick mark endpoints. The first tick # mark will span the entire width of the ruler, which serves as a # divider b/w the unit of measure text (i.e. A or nm) and the rest # of the ruler. pt1 = ruler_start_pt pt2 = ruler_start_pt + V(-vr_thickness, 0.0, 0.0) # Draw vertical ruler tickmarks, including numeric unit labels for tick_num in range(num_horz_ticks + 1): # pt1 and pt2 are modified by each iteration of the loop. self.drawLine(pt1, pt2) # Draw units number beside long tickmarks. if not tick_num % unit_label_inc: units_num_origin = pt1 \ + V(vr_units_x_offset, vr_units_y_offset, 0.0) units_num = units_format % (tick_num * units_scale) self.drawText(units_num, units_num_origin) # Update tickmark endpoints for next tickmark. pt1 = ruler_start_pt + \ V(0.0, vr_tickmark_spacing * tickmark_spacing_multiplier * (tick_num + 1), 0.0) if not (tick_num + 1) % long_tickmark_inc: pt2 = pt1 + V(vr_long_tick_len, 0.0, 0.0) elif not (tick_num + 1) % medium_tickmark_inc: pt2 = pt1 + V(vr_medium_tick_len, 0.0, 0.0) else: pt2 = pt1 + V(vr_short_tick_len, 0.0, 0.0) # End vertical ruler # Draw horizontal ruler line(s) and tick marks ######################### if env.prefs[displayHorzRuler_prefs_key] and draw_ticks_and_text: # Draw horizontal line along top/bottom edge of ruler. self.drawLine(hr_line_pt1, hr_line_pt2) # Initialize pt1 and pt2, the tick mark endpoints. The first tick # mark will span the entire width of the ruler, which serves as a # divider b/w the unit of measure text (i.e. A or nm) and the rest # of the ruler. pt1 = ruler_start_pt pt2 = ruler_start_pt + V(0.0, -hr_thickness, 0.0) # Draw horizontal ruler (with vertical) tickmarks, including its # numeric unit labels for tick_num in range(num_vert_ticks + 1): # pt1 and pt2 are modified by each iteration of the loop. self.drawLine(pt1, pt2) # Draw units number beside long tickmarks. if not tick_num % unit_label_inc: units_num_origin = pt1 \ + V(hr_units_x_offset, hr_units_y_offset, 0.0) units_num = units_format % (tick_num * units_scale) self.drawText(units_num, units_num_origin) # Update tickmark endpoints for next tickmark. pt1 = \ ruler_start_pt + \ V(hr_tickmark_spacing * tickmark_spacing_multiplier * (tick_num + 1), 0.0, 0.0) if not (tick_num + 1) % long_tickmark_inc: pt2 = pt1 + V(0.0, hr_long_tick_len, 0.0) elif not (tick_num + 1) % medium_tickmark_inc: pt2 = pt1 + V(0.0, hr_medium_tick_len, 0.0) else: pt2 = pt1 + V(0.0, hr_short_tick_len, 0.0) # End horizontal ruler # Restore OpenGL state. glDepthMask(GL_TRUE) glEnable(GL_DEPTH_TEST) glEnable(GL_LIGHTING) glDepthMask(GL_TRUE) glMatrixMode(GL_PROJECTION) glPopMatrix() glMatrixMode(GL_MODELVIEW) glPopMatrix() return # from drawRulers
def run(): #Start OpenGL and ask it for an OpenGL context pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode(SCREEN_SIZE, pygame.HWSURFACE|pygame.OPENGL|pygame.DOUBLEBUF) #The first thing we do is print some OpenGL details and check that we have a good enough version print("OpenGL Implementation Details:") if glGetString(GL_VENDOR): print("\tGL_VENDOR: {}".format(glGetString(GL_VENDOR).decode())) if glGetString(GL_RENDERER): print("\tGL_RENDERER: {}".format(glGetString(GL_RENDERER).decode())) if glGetString(GL_VERSION): print("\tGL_VERSION: {}".format(glGetString(GL_VERSION).decode())) if glGetString(GL_SHADING_LANGUAGE_VERSION): print("\tGL_SHADING_LANGUAGE_VERSION: {}".format(glGetString(GL_SHADING_LANGUAGE_VERSION).decode())) major_version = int(glGetString(GL_VERSION).decode().split()[0].split('.')[0]) minor_version = int(glGetString(GL_VERSION).decode().split()[0].split('.')[1]) if major_version < 3 or (major_version < 3 and minor_version < 0): print("OpenGL version must be at least 3.0 (found {0})".format(glGetString(GL_VERSION).decode().split()[0])) #Now onto the OpenGL initialisation #Set up depth culling glEnable(GL_CULL_FACE) glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) glDepthFunc(GL_LEQUAL) glDepthRange(0.0, 1.0) #We create out shaders which do little more than set a flat colour for each face VERTEX_SHADER = shaders.compileShader(b""" #version 130 in vec4 position; in vec4 normal; uniform mat4 projectionMatrix; uniform mat4 viewMatrix; uniform mat4 modelMatrix; flat out float theColor; void main() { vec4 temp = modelMatrix * position; temp = viewMatrix * temp; gl_Position = projectionMatrix * temp; theColor = clamp(abs(dot(normalize(normal.xyz), normalize(vec3(0.9,0.1,0.5)))), 0, 1); } """, GL_VERTEX_SHADER) FRAGMENT_SHADER = shaders.compileShader(b""" #version 130 flat in float theColor; out vec4 outputColor; void main() { outputColor = vec4(1.0, 0.5, theColor, 1.0); } """, GL_FRAGMENT_SHADER) shader = shaders.compileProgram(VERTEX_SHADER, FRAGMENT_SHADER) #And then grab our attribute locations from it glBindAttribLocation(shader, 0, b"position") glBindAttribLocation(shader, 1, b"normal") #Create the Vertex Array Object to hold our volume mesh vertexArrayObject = GLuint(0) glGenVertexArrays(1, vertexArrayObject) glBindVertexArray(vertexArrayObject) #Create the index buffer object indexPositions = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER, usage=GL_STATIC_DRAW) #Create the VBO vertexPositions = vbo.VBO(vertices, usage=GL_STATIC_DRAW) #Bind our VBOs and set up our data layout specifications with indexPositions, vertexPositions: glEnableVertexAttribArray(0) glVertexAttribPointer(0, 3, GL_FLOAT, False, 6*vertices.dtype.itemsize, vertexPositions+(0*vertices.dtype.itemsize)) glEnableVertexAttribArray(1) glVertexAttribPointer(1, 3, GL_FLOAT, False, 6*vertices.dtype.itemsize, vertexPositions+(3*vertices.dtype.itemsize)) glBindVertexArray(0) glDisableVertexAttribArray(0) #Now grab out transformation martix locations modelMatrixUnif = glGetUniformLocation(shader, b"modelMatrix") viewMatrixUnif = glGetUniformLocation(shader, b"viewMatrix") projectionMatrixUnif = glGetUniformLocation(shader, b"projectionMatrix") modelMatrix = np.array([[1.0,0.0,0.0,-32.0],[0.0,1.0,0.0,-32.0],[0.0,0.0,1.0,-32.0],[0.0,0.0,0.0,1.0]], dtype='f') viewMatrix = np.array([[1.0,0.0,0.0,0.0],[0.0,1.0,0.0,0.0],[0.0,0.0,1.0,-50.0],[0.0,0.0,0.0,1.0]], dtype='f') projectionMatrix = np.array([[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0]], dtype='f') #These next few lines just set up our camera frustum fovDeg = 45.0 frustumScale = 1.0 / tan(radians(fovDeg) / 2.0) zNear = 1.0 zFar = 1000.0 projectionMatrix[0][0] = frustumScale projectionMatrix[1][1] = frustumScale projectionMatrix[2][2] = (zFar + zNear) / (zNear - zFar) projectionMatrix[2][3] = -1.0 projectionMatrix[3][2] = (2 * zFar * zNear) / (zNear - zFar) #viewMatrix and projectionMatrix don't change ever so just set them once here with shader: glUniformMatrix4fv(projectionMatrixUnif, 1, GL_TRUE, projectionMatrix) glUniformMatrix4fv(viewMatrixUnif, 1, GL_TRUE, viewMatrix) #These are used to track the rotation of the volume LastFrameMousePos = (0,0) CurrentMousePos = (0,0) xRotation = 0 yRotation = 0 while True: clock.tick() for event in pygame.event.get(): if event.type == pygame.QUIT: return if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: return if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: CurrentMousePos = event.pos LastFrameMousePos = CurrentMousePos if event.type == pygame.MOUSEMOTION and 1 in event.buttons: CurrentMousePos = event.pos diff = (CurrentMousePos[0] - LastFrameMousePos[0], CurrentMousePos[1] - LastFrameMousePos[1]) xRotation += event.rel[0] yRotation += event.rel[1] LastFrameMousePos = CurrentMousePos glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #Perform the rotation of the mesh moveToOrigin = np.array([[1.0,0.0,0.0,-32.0],[0.0,1.0,0.0,-32.0],[0.0,0.0,1.0,-32.0],[0.0,0.0,0.0,1.0]], dtype='f') rotateAroundX = np.array([[1.0,0.0,0.0,0.0],[0.0,cos(radians(yRotation)),-sin(radians(yRotation)),0.0],[0.0,sin(radians(yRotation)),cos(radians(yRotation)),0.0],[0.0,0.0,0.0,1.0]], dtype='f') rotateAroundY = np.array([[cos(radians(xRotation)),0.0,sin(radians(xRotation)),0.0],[0.0,1.0,0.0,0.0],[-sin(radians(xRotation)),0.0,cos(radians(xRotation)),0.0],[0.0,0.0,0.0,1.0]], dtype='f') modelMatrix = rotateAroundY.dot(rotateAroundX.dot(moveToOrigin)) with shader: glUniformMatrix4fv(modelMatrixUnif, 1, GL_TRUE, modelMatrix) glBindVertexArray(vertexArrayObject) glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None) glBindVertexArray(0) # Show the screen pygame.display.flip()