def measureVector(self, p0, p1): '''Returns a 2-tuple (float, Vector2), which is the length and direction of the vector pointing from p0 to p1 in screen space.''' projMat = glGetDoublev(GL_PROJECTION_MATRIX) viewport = glGetIntegerv(GL_VIEWPORT) modelMat = glGetDoublev(GL_MODELVIEW_MATRIX) u0, v0, w0 = gluProject(p0[0], p0[1], p0[2], modelMat, projMat, viewport) u1, v1, w1 = gluProject(p1[0], p1[1], p1[2], modelMat, projMat, viewport) v = Vector2(u1 - u0, v1 - v0) length = v.length() return length, v / length
def screenAxis(self, axis, camControl): '''Reports the screen-space 2d vector of the given vector. @param: axis The axis to determine (x-, y-, or z-axis). @param: camControl The scene's camera control for this event. @returns: A Vector2 - the vector direction and magnitude of that vector in screen space (size in pixels). ''' projMat = glGetDoublev(GL_PROJECTION_MATRIX) viewport = glGetIntegerv(GL_VIEWPORT) glPushMatrix() self.manipXform(camControl) modelMat = glGetDoublev(GL_MODELVIEW_MATRIX) glPopMatrix() u, v, w = gluProject(0.0, 0.0, 0.0, modelMat, projMat, viewport) ux, vx, wx = gluProject(axis[0], axis[1], axis[2], modelMat, projMat, viewport) return Vector2(ux - u, vx - v)
def test_distances(self): """Test distance calculation function Originally was using gluProject, we check to be sure that we return the same value as gluProject used to produce... """ glu = gluProject(0, 0, 0, self.mvMatrix, self.pMatrix, self.viewPort.astype('i')) expected = glu[2] d = distances( array([[0, 0, 0, 1]], 'f'), self.mvMatrix, self.pMatrix, self.viewPort, ) assert allclose(d[0], expected), (d, expected)
def display_screen(self): glDisable(GL_LIGHTING) glColor3f(1, 1, 1) # Projection glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective (self.fov,float(self.width)/float(self.height),self.clippingplanes[0],self.clippingplanes[1]) # Initialize ModelView matrix glMatrixMode(GL_MODELVIEW) glLoadIdentity() # View transformation mat = se3.homogeneous(self.camera.matrix()) cols = zip(*mat) pack = sum((list(c) for c in cols),[]) glMultMatrixf(pack) labels = dict([ (k, T[1]) for (k, T) in vantage_point_xforms.items() ]) for (k, v) in labels.items(): try: labels[k] = gluProject(*v) except: labels[k] = None glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0,self.width,self.height,0,-1,1); glMatrixMode(GL_MODELVIEW) glLoadIdentity() for (s, p) in labels.items(): if p: glRasterPos3f(p[0], self.height - p[1], p[2]) gldraw.glutBitmapString(GLUT_BITMAP_HELVETICA_12, s)
def renderTextAtPosition(self, position, textString, textColor = black, textFont = None, fontSize = 11, ): """ Renders the text at the specified position (x, y, z coordinates) @param position: The x, y, z coordinates of the object at which the text needs to be rendered. @type position: B{A} @param textString: the text to be rendered at the specified position. @type textString : str @see: self.renderTextNearCursor() This method is different than that method. That method uses QPoint (the current cursor position) to render the text (thus needs integers x and y) whereas this method uses the actual object coordinates @see: MultiplednaSegment_GraphicsMode._drawDnaRubberbandLine() [obsolete class name, what is correct one?] @see: QGLWidget.renderText() @TODO: refactor to move the common code in this method and self.renderTextNearCursor(). """ if textFont is not None: font = textFont else: font = self._getFontForTextNearCursor(fontSize = fontSize, isBold = True) x = position[0] y = position[1] z = position[2] glDisable(GL_LIGHTING) #Convert the object coordinates to the window coordinates. wX, wY, wZ = gluProject(x, y, z) halo_color = getTextHaloColor(textColor) offset_val = 1 bg_z_offset = 0 fg_z_offset = -1e-7 render_positions = (( offset_val, offset_val, bg_z_offset, halo_color), (-offset_val, -offset_val, bg_z_offset, halo_color), (-offset_val, offset_val, bg_z_offset, halo_color), ( offset_val, -offset_val, bg_z_offset, halo_color), ( 0, 0, fg_z_offset, textColor)) for dx, dy, dz, color in render_positions: x1, y1, z1 = gluUnProject(wX + dx, wY + dy, wZ + dz) self.qglColor(RGBf_to_QColor(color)) self.renderText(x1, y1, z1, QString(textString), font) ## self.qglClearColor(RGBf_to_QColor(color)) ## # question: is this related to glClearColor? [bruce 071214 question] ## # -- yes [Ninad 2008-08-20] glEnable(GL_LIGHTING)
def drawfont2(glpane, msg=None, charwidth=None, charheight=None, testpattern=False, pixelwidth=None): """ Draws a rect of chars (dimensions given as char counts: charwidth x charheight [#e those args are misnamed] using vv's font texture [later 061113: assumed currently bound, i think -- see ensure_courierfile_loaded()], in a klugy way; msg gives the chars to draw (lines must be shorter than charwidth or they will be truncated) """ _bind_courier_font_texture() # adjust these guessed params (about the specific font image we're using as # a texture) until they work right: # (tex_origin_chars appears lower down, since it is revised there) tex_size = (128, 128) # tex size in pixels tex_nx = 16 # number of chars in a row, in the tex image tex_ny = 8 # number of chars in a column if msg is None: msg = "(redraw %d)" % env.redraw_counter charwidth = tex_nx charheight = tex_ny + 1 lines = msg.split('\n') # tab not supported if charwidth is None: charwidth = 14 # could be max linelength plus 1 if charheight is None: charheight = len(lines) if not testpattern: while len(lines) < charheight: lines.append('') # draw individual chars from font-texture, # but first, try to position it so they look perfect (which worked for a # while, but broke sometime before 060728) ## glTranslatef( 0, pixelheight / 2, 0 ) # perfect! # (Ortho mode, home view, a certain window size -- not sure if that # matters but it might) # restoring last-saved window position (782, 44) and size (891, 749) ## gap = 2 # in pixels - good for debugging # good for looking nice! but note that idlehack uses one extra pixel of # vspace, and that does probably look better. gap = 0 # to do that efficiently i'd want another image to start from. # (or to modify this one to make the texture, by moving pixrects around) pixfactor = 1 # try *2... now i can see some fuzz... what if i start at origin, to draw? # Did that, got it tolerable for pixfactor 2, then back to 1 and i've lost # the niceness! Is it no longer starting at origin? ##pixelwidth = pixelheight = 0.05 * 2/3 #070124 revisions, general comment... current caveats/bugs: #### # - Only tested in Ortho mode. # - Working well but the bugs depend on whether we add "1 or" before # "pixelwidth is None" in if statement below: # Bugs when it computes pixelwidth here (even when passed, as always in # these tests): # - Textlabel for "current redraw" (in exprs/test.py bottom_left_corner) # disappears during highlighting. # Bugs when it doesn't [usual state & state I'll leave it in]: # - Not tested with displists off, maybe. ### # - Fuzzy text in testexpr_18 [not yet understood.] # - [fixed] Fuzzy text in "current redraw" textlabel during anything's # highlighting. [Fixed by removing DisplayListChunk from that.] # - [No bug in clarity of text in highlighted checkbox prefs themselves.] # - Works with displists on or off now. # - Is disable_translate helping?? Not sure (only matters when it computes # pixelwidth here -- not now.) # - ##e Use direct drawing_phase test instead? doesn't seem to be needed # anymore, from remaining bugs listed above. disable_translate = False #070124 #061211 permit caller to pass it [note: the exprs module usually or always # passes it, acc'd to test 070124] if pixelwidth is None: p1junk, p2a = mymousepoints(glpane, 10, 10) p1junk, p2b = mymousepoints(glpane, 11, 10) px, py, pz = vec = p2b - p2a # should be DX * pixelwidth ## print px,py,pz ### 0.0313971755382 0.0 0.0 (in Ortho mode, near but not at home view, ### also at it (??)) # 0.0313971755382 0.0 0.0 home ortho # 0.03139613018 0.0 0.0 home perspective -- still looks good (looks # the same) (with false "smoother textures") ## pixelwidth = pixelheight = px * pixfactor # 061211 Work better for rotated text (still not good unless # screen-parallel.) pixelwidth = pixelheight = vlen(vec) * pixfactor # print "pixelwidth",pixelwidth ####@@@@ can be one of: # 0.0319194157846 # or 0.0313961295259 # or 0.00013878006302 if pixelwidth < 0.01: # print "low pixelwidth:",pixelwidth, glpane.drawing_phase # e.g. 0.000154639183832 glselect pixelwidth = 0.0319194157846 ### kluge, in case you didn't notice [guess: formula is wrong during # highlighting] but this failed to fix the bug in which a TextRect # doesn't notice clicks unless you slide onto it from a Rect # ####@@@@ # Q 070124: when this happens (presumably due to small window in # glSelect) should we disable glTranslatef below? # I guess yes, so try it. Not that it'll help when we re-disable # always using this case. disable_translate = True # I'll leave this in since it seems right, but it's not obviously # helping by test. pass else: pixelheight = pixelwidth tex_origin_chars = V(3, 64) # revised 070124 #070124 -- note that disable_translate is never set given if statements #above -- if 1 and not disable_translate: ##e Use glpane.drawing_phase == 'glselect' instead? doesn't seem to ## be needed anymore, from remaining bugs listed above. # Translate slightly to make characters clearer (since we're still too # lazy to use glDrawPixels or whatever it's called). # Caveats: # - Assumes we're either not in a displist, or it's always drawn in the # same place. # - Will only work if we're drawing at correct depth for pixelwidth, I # presume -- and of course, parallel to screen. x, y, depth = gluProject(0.0, 0.0, 0.0) # Where we'd draw without any correction (ORIGIN). # Change x and y to a better place to draw (in pixel coords on screen.) # (note: This int(x+0.5) was compared by test to int(x) and int(x)+0.5 # -- this is best, as one might guess; not same for y...) ## if we need a "boldface kluge", using int(x)+0.5 here would be one... x = int(x + 0.5) ### NOT UNDERSTOOD: Why x & y differ, in whether it's best to add this ### 0.5. y = int(y + 0.5) + 0.5 # [btw I'd guessed y+0.5 in int() should be (y-0.5)+0.5 due to outer # +0.5, but that looks worse in checkbox_pref centering; I don't know # why.] # [later, 080521: could it be +0.5 effect differing for x & y due to # different sign, since int() rounds towards zero rather than # towards neginf? ### REVIEW: fix this using intRound?] # # Adding outer 0.5 to y became best after I fixed a bug of # translating before glu*Project (just before this if-statement), # which fails inside displists since the translate effect doesn't # show up in glu*Project then. # # I wonder if the x/y difference could be related to the use of # CenterY around TextRect inside displists, which ought to produce a # similar bug if the shift is not by an exact number of pixels # (which is surely the case since the caller is guessing pixelwidth # as a hardcoded constant, IIRC). So the guess is that caller's # pixelwidth is wrong and/or CenterY shifts by an odd number of # halfpixels, inside displist and not seen by this glu*Project, # causing a bug which this +0.5 sometimes compensates for, but not # always due to pixelwidth being wrong. It's not worth # understanding this compared to switching over to glDrawPixels or # whatever it's called. ###DO THAT SOMETIME. p1 = A(gluUnProject(x, y, depth)) # where we'd like to draw (p1) # Test following code -- with this line, it should make us draw # noticeably higher up the screen -- works. ## p1 += DY glTranslatef(p1[0], p1[1], p1[2]) # fyi: NameError if we try glTranslatefv or glTranslatev -- didn't # look for other variants or in gl doc. pass tex_dx = V(tex_width, 0) # in pixels tex_dy = V(0, tex_height) # Using those guesses, come up with tex-rects for each char as triples of # 2-vectors (tex_origin, tex_dx, tex_dy). # i for y, j or x (is that order normal??), still starting at bottom left def ff(i, j): """ Which char to draw at this position? i is y, going up, -1 is lowest line (sorry.) """ nlines = len(lines) bottom = -1 # Change this api sometime. # This one too -- caller ought to be able to use 0 or 1 for the top # (first) line. abovethat = i - bottom if abovethat < nlines: # Draw chars from lines. test = lines[nlines - 1 - abovethat] # Few-day(?)-old comment [as of 060728], not sure why it's # exactly here, maybe since this tells when we redraw, but it # might be correct other than that: this shows that mouseover of # objects (pixels) w/o glnames causes redraws! I understand # glselect ones, but they should not be counted, and should not # show up on the screen, so I don't understand any good reason # for these visible ones to happen. #e To try to find out, we could also record compact_stack of the # first gl_update that caused this redraw... if j < len(test): # Replace i,j with new ones so as to draw those chars instead. ch1 = ord(test[j]) - 32 j = ch1 % tex_nx i = 5 - (ch1 / tex_nx) else: # Draw a blank instead. ch1 = 32 - 32 j = ch1 % tex_nx i = 5 - (ch1 / tex_nx) else: # Use i,j to index the texture, meaning, draw test chars, perhaps # the entire thing. pass return tex_origin_chars + i * tex_dy + j * tex_dx, tex_dx, tex_dy # Now think about where to draw all this... use a gap, but otherwise the # same layout. charwidth1 = tex_width * pixelwidth charheight1 = tex_height * pixelheight char_dx = (tex_width + gap) * pixelwidth char_dy = (tex_height + gap) * pixelheight def gg(i, j): return (ORIGIN + j * char_dx * DX + (i + 1) * char_dy * DY, charwidth1 * DX, charheight1 * DY) # Now draw them. if 1: #### for n in range(65): # Simulate delay of a whole page of chars. # Note, this is significantly slow even if we just draw 5x as many # chars! (range was -1,tex_ny == 8, length 9) - Note, increasing i goes # up on screen, not down! for i in range(-1, charheight - 1): for j in range(charwidth): # Was tex_nx == 16 origin, dx, dy = gg(i, j) # Where to draw this char ###k # Still in pixel ints. # What tex coords to use to find it? tex_origin, ltex_dx, ltex_dy = ff(i, j) # Kluge until i look up how to use pixels directly. tex_origin, ltex_dx, ltex_dy = 1.0/tex_size[0] \ * V(tex_origin, ltex_dx, ltex_dy) #print (origin, dx, dy, tex_origin, tex_dx, tex_dy) # Cool bug effect bfr 'l's here. draw_textured_rect(origin, dx, dy, tex_origin, ltex_dx, ltex_dy) # draw some other ones? done above, with test string inside ff function. # Interesting q -- if i use vertex arrays or displist-index arrays, can # drawing 10k chars be fast? (guess: yes.) # Some facts: this window now has 70 lines, about 135 columns... of course # it's mostly blank, and in fact just now it has about 3714 chars, not 70 * # 135 = 9450 as if it was nowhere blank. # Above we draw 9 * 16 = 144, so ratio is 3714 / 144 = 25, or 9450 / 144 = # 65. # Try 65 redundant loops above & see what happens. It takes it a couple # seconds! Too slow! Of course it's mostly the py code. # Anyway, it means we *will* have to do one of those optims mentioned, or # some other one like not clearing/redrawing the entire screen during most # text editing, or having per-line display lists. glpane.kluge_reset_texture_mode_to_work_around_renderText_bug() return #drawfont2 #e rename, clean up
def world_to_window(self, x, y, z): x, y, z = gluProject(x, y, z) y = self._height - y return x, y
def draw(self, performance): W, H = glfwGetWindowSize() scale = gameglobals.fontScale nameScoreList = [] #draw players scores player = self.players['Player'] text = 'Player: ' + str(self.scoreBoard['Player'][0]) x = 10.0 y = self.font_aa.getSize(text)[1] * scale nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Red' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = 10.0 y = H nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Green' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = W - self.font_aa.getSize(text)[0] * scale - 10 y = H nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Yellow' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = W - self.font_aa.getSize(text)[0] * scale - 10 y = self.font_aa.getSize(text)[1] * scale nameScoreList.append([text, x, y, player.color]) self.font_aa.begin() for nameScore in nameScoreList: glColor3f(nameScore[3][0], nameScore[3][1], nameScore[3][2]) self.font_aa.renderShadowed(nameScore[0], nameScore[1], nameScore[2], (0,0,0), scale) self.font_aa.end() #draw "hits" messages px = 50 for hit in self.hitMsgList: if hit[1] < px: addend = self.msgFlowFunction(hit[1], px) hitText = ' HITS!' if hit[0] < 2: hitText = ' HIT!' text = '+' + str(hit[0]) + hitText pCoords = hit[2] x, y, _ = gluProject(pCoords[0], pCoords[1], pCoords[2]) y = y + hit[1] glColor4f(hit[3][0], hit[3][1], hit[3][2], addend) self.font_aa.begin() self.font_aa.renderOutlined(text, x, y, (0,0,0), scale) self.font_aa.end() hit[1] += 200 * (1.2 - addend) * performance else: self.hitMsgList = self.hitMsgList[1:] #draw the faults messages px = 80 for fault in self.faultMsgList: if fault[2] < px: addend = self.msgFlowFunction(fault[2], px) text = fault[0] pts = fault[1] x, y = W / 2 - self.font_aa.getSize(text)[0] * scale / 2, H - 50 * scale y = y + fault[2] glColor4f(1.0, 0.8, 0.0, addend) self.font_aa.begin() self.font_aa.renderShadowed(text, x, y, (0,0,0), scale) if pts: glColor4f(0.5, 0.8, 0.1, addend) pts = '+' + pts x = W / 2 - self.font_aa.getSize(pts)[0] * scale / 2 y -= self.font_aa.getSize(pts)[1] * scale self.font_aa.renderShadowed(pts, x, y, (0,0,0), scale) self.font_aa.end() fault[2] += 200 * (1.2 - addend) * performance else: self.faultMsgList = self.faultMsgList[1:] #draw the taunts px = 100 for taunt in self.taunts: if taunt[1] < px: addend = self.msgFlowFunction(taunt[1], px) text = taunt[0] pCoords = taunt[2] x, y, _ = gluProject(pCoords[0], pCoords[1], pCoords[2]) y = y + taunt[1] x = x - self.font_aa.getSize(text)[0] * scale / 2 c = taunt[3] #players.colorNamesColors[taunt[2]] glColor4f(c[0], c[1], c[2], addend) self.font_aa.begin() self.font_aa.renderShadowed(text, x, y, (0,0,0), scale) self.font_aa.end() taunt[1] += 200 * (1.2 - addend) * performance else: self.taunts= self.taunts[1:] #draw current total combo total = self.scoreBoard.getTotalPoints() if total > 1: comboScale = scale * 1.25 totalText = 'Combo ' + str(total) + '!' x = W / 2 - self.font_aa.getSize(totalText)[0] * comboScale / 2 y = 2 * self.font_aa.getSize(totalText)[1] * comboScale glColor4f(0.0, 1.0, 1.0, 1) self.font_aa.begin() self.font_aa.renderShadowed(totalText, x, y, (0,0,0), comboScale) self.font_aa.end() #draw game over message if self.gameOver == True: loserMsg, loserColor = self.getLoserNameColor() loserMsg += ' lost!' msg = 'Game Over' loserScale = scale * 1.25 gOverScale = scale * 2.5 x0 = W / 2 - self.font_aa.getSize(loserMsg)[0] * loserScale / 2 y0 = H / 2 + H / 4 - self.font_aa.getSize(loserMsg)[1] * loserScale / 2 x1 = W / 2 - self.font_aa.getSize(msg)[0] * gOverScale / 2 y1 = H / 2 - self.font_aa.getSize(msg)[1] * gOverScale / 2 self.font_aa.begin() glColor4f(loserColor[0], loserColor[1], loserColor[2], 0.9) self.font_aa.render(loserMsg, x0, y0, loserScale) glColor4f(1.0, 0.0, 0.0, 0.9) self.font_aa.render(msg, x1, y1, gOverScale) self.font_aa.end()
def drawfont2(glpane, msg = None, charwidth = None, charheight = None, testpattern = False, pixelwidth = None): """ Draws a rect of chars (dimensions given as char counts: charwidth x charheight [#e those args are misnamed] using vv's font texture [later 061113: assumed currently bound, i think -- see ensure_courierfile_loaded()], in a klugy way; msg gives the chars to draw (lines must be shorter than charwidth or they will be truncated) """ _bind_courier_font_texture() # adjust these guessed params (about the specific font image we're using as # a texture) until they work right: # (tex_origin_chars appears lower down, since it is revised there) tex_size = (128,128) # tex size in pixels tex_nx = 16 # number of chars in a row, in the tex image tex_ny = 8 # number of chars in a column if msg is None: msg = "(redraw %d)" % env.redraw_counter charwidth = tex_nx charheight = tex_ny + 1 lines = msg.split('\n') # tab not supported if charwidth is None: charwidth = 14 # could be max linelength plus 1 if charheight is None: charheight = len(lines) if not testpattern: while len(lines) < charheight: lines.append('') # draw individual chars from font-texture, # but first, try to position it so they look perfect (which worked for a # while, but broke sometime before 060728) ## glTranslatef( 0, pixelheight / 2, 0 ) # perfect! # (Ortho mode, home view, a certain window size -- not sure if that # matters but it might) # restoring last-saved window position (782, 44) and size (891, 749) ## gap = 2 # in pixels - good for debugging # good for looking nice! but note that idlehack uses one extra pixel of # vspace, and that does probably look better. gap = 0 # to do that efficiently i'd want another image to start from. # (or to modify this one to make the texture, by moving pixrects around) pixfactor = 1 # try *2... now i can see some fuzz... what if i start at origin, to draw? # Did that, got it tolerable for pixfactor 2, then back to 1 and i've lost # the niceness! Is it no longer starting at origin? ##pixelwidth = pixelheight = 0.05 * 2/3 #070124 revisions, general comment... current caveats/bugs: #### # - Only tested in Ortho mode. # - Working well but the bugs depend on whether we add "1 or" before # "pixelwidth is None" in if statement below: # Bugs when it computes pixelwidth here (even when passed, as always in # these tests): # - Textlabel for "current redraw" (in exprs/test.py bottom_left_corner) # disappears during highlighting. # Bugs when it doesn't [usual state & state I'll leave it in]: # - Not tested with displists off, maybe. ### # - Fuzzy text in testexpr_18 [not yet understood.] # - [fixed] Fuzzy text in "current redraw" textlabel during anything's # highlighting. [Fixed by removing DisplayListChunk from that.] # - [No bug in clarity of text in highlighted checkbox prefs themselves.] # - Works with displists on or off now. # - Is disable_translate helping?? Not sure (only matters when it computes # pixelwidth here -- not now.) # - ##e Use direct drawing_phase test instead? doesn't seem to be needed # anymore, from remaining bugs listed above. disable_translate = False #070124 #061211 permit caller to pass it [note: the exprs module usually or always # passes it, acc'd to test 070124] if pixelwidth is None: p1junk, p2a = mymousepoints(glpane, 10, 10) p1junk, p2b = mymousepoints(glpane, 11, 10) px,py,pz = vec = p2b - p2a # should be DX * pixelwidth ## print px,py,pz ### 0.0313971755382 0.0 0.0 (in Ortho mode, near but not at home view, ### also at it (??)) # 0.0313971755382 0.0 0.0 home ortho # 0.03139613018 0.0 0.0 home perspective -- still looks good (looks # the same) (with false "smoother textures") ## pixelwidth = pixelheight = px * pixfactor # 061211 Work better for rotated text (still not good unless # screen-parallel.) pixelwidth = pixelheight = vlen(vec) * pixfactor # print "pixelwidth",pixelwidth ####@@@@ can be one of: # 0.0319194157846 # or 0.0313961295259 # or 0.00013878006302 if pixelwidth < 0.01: # print "low pixelwidth:",pixelwidth, glpane.drawing_phase # e.g. 0.000154639183832 glselect pixelwidth = 0.0319194157846 ### kluge, in case you didn't notice [guess: formula is wrong during # highlighting] but this failed to fix the bug in which a TextRect # doesn't notice clicks unless you slide onto it from a Rect # ####@@@@ # Q 070124: when this happens (presumably due to small window in # glSelect) should we disable glTranslatef below? # I guess yes, so try it. Not that it'll help when we re-disable # always using this case. disable_translate = True # I'll leave this in since it seems right, but it's not obviously # helping by test. pass else: pixelheight = pixelwidth tex_origin_chars = V(3, 64) # revised 070124 #070124 -- note that disable_translate is never set given if statements #above -- if 1 and not disable_translate: ##e Use glpane.drawing_phase == 'glselect' instead? doesn't seem to ## be needed anymore, from remaining bugs listed above. # Translate slightly to make characters clearer (since we're still too # lazy to use glDrawPixels or whatever it's called). # Caveats: # - Assumes we're either not in a displist, or it's always drawn in the # same place. # - Will only work if we're drawing at correct depth for pixelwidth, I # presume -- and of course, parallel to screen. x,y,depth = gluProject(0.0, 0.0, 0.0) # Where we'd draw without any correction (ORIGIN). # Change x and y to a better place to draw (in pixel coords on screen.) # (note: This int(x+0.5) was compared by test to int(x) and int(x)+0.5 # -- this is best, as one might guess; not same for y...) ## if we need a "boldface kluge", using int(x)+0.5 here would be one... x = int(x+0.5) ### NOT UNDERSTOOD: Why x & y differ, in whether it's best to add this ### 0.5. y = int(y+0.5)+0.5 # [btw I'd guessed y+0.5 in int() should be (y-0.5)+0.5 due to outer # +0.5, but that looks worse in checkbox_pref centering; I don't know # why.] # [later, 080521: could it be +0.5 effect differing for x & y due to # different sign, since int() rounds towards zero rather than # towards neginf? ### REVIEW: fix this using intRound?] # # Adding outer 0.5 to y became best after I fixed a bug of # translating before glu*Project (just before this if-statement), # which fails inside displists since the translate effect doesn't # show up in glu*Project then. # # I wonder if the x/y difference could be related to the use of # CenterY around TextRect inside displists, which ought to produce a # similar bug if the shift is not by an exact number of pixels # (which is surely the case since the caller is guessing pixelwidth # as a hardcoded constant, IIRC). So the guess is that caller's # pixelwidth is wrong and/or CenterY shifts by an odd number of # halfpixels, inside displist and not seen by this glu*Project, # causing a bug which this +0.5 sometimes compensates for, but not # always due to pixelwidth being wrong. It's not worth # understanding this compared to switching over to glDrawPixels or # whatever it's called. ###DO THAT SOMETIME. p1 = A(gluUnProject(x, y, depth)) # where we'd like to draw (p1) # Test following code -- with this line, it should make us draw # noticeably higher up the screen -- works. ## p1 += DY glTranslatef( p1[0], p1[1], p1[2]) # fyi: NameError if we try glTranslatefv or glTranslatev -- didn't # look for other variants or in gl doc. pass tex_dx = V(tex_width, 0) # in pixels tex_dy = V(0, tex_height) # Using those guesses, come up with tex-rects for each char as triples of # 2-vectors (tex_origin, tex_dx, tex_dy). # i for y, j or x (is that order normal??), still starting at bottom left def ff(i,j): """ Which char to draw at this position? i is y, going up, -1 is lowest line (sorry.) """ nlines = len(lines) bottom = -1 # Change this api sometime. # This one too -- caller ought to be able to use 0 or 1 for the top # (first) line. abovethat = i - bottom if abovethat < nlines: # Draw chars from lines. test = lines[nlines-1 - abovethat] # Few-day(?)-old comment [as of 060728], not sure why it's # exactly here, maybe since this tells when we redraw, but it # might be correct other than that: this shows that mouseover of # objects (pixels) w/o glnames causes redraws! I understand # glselect ones, but they should not be counted, and should not # show up on the screen, so I don't understand any good reason # for these visible ones to happen. #e To try to find out, we could also record compact_stack of the # first gl_update that caused this redraw... if j < len(test): # Replace i,j with new ones so as to draw those chars instead. ch1 = ord(test[j]) - 32 j = ch1 % tex_nx i = 5 - (ch1 / tex_nx) else: # Draw a blank instead. ch1 = 32 - 32 j = ch1 % tex_nx i = 5 - (ch1 / tex_nx) else: # Use i,j to index the texture, meaning, draw test chars, perhaps # the entire thing. pass return tex_origin_chars + i * tex_dy + j * tex_dx , tex_dx, tex_dy # Now think about where to draw all this... use a gap, but otherwise the # same layout. charwidth1 = tex_width * pixelwidth charheight1 = tex_height * pixelheight char_dx = (tex_width + gap) * pixelwidth char_dy = (tex_height + gap) * pixelheight def gg(i,j): return (ORIGIN + j * char_dx * DX + (i + 1) * char_dy * DY, charwidth1 * DX, charheight1 * DY) # Now draw them. if 1: #### for n in range(65): # Simulate delay of a whole page of chars. # Note, this is significantly slow even if we just draw 5x as many # chars! (range was -1,tex_ny == 8, length 9) - Note, increasing i goes # up on screen, not down! for i in range(-1, charheight - 1): for j in range(charwidth): # Was tex_nx == 16 origin, dx, dy = gg(i,j) # Where to draw this char ###k # Still in pixel ints. # What tex coords to use to find it? tex_origin, ltex_dx, ltex_dy = ff(i,j) # Kluge until i look up how to use pixels directly. tex_origin, ltex_dx, ltex_dy = 1.0/tex_size[0] \ * V(tex_origin, ltex_dx, ltex_dy) #print (origin, dx, dy, tex_origin, tex_dx, tex_dy) # Cool bug effect bfr 'l's here. draw_textured_rect(origin, dx, dy, tex_origin, ltex_dx, ltex_dy) # draw some other ones? done above, with test string inside ff function. # Interesting q -- if i use vertex arrays or displist-index arrays, can # drawing 10k chars be fast? (guess: yes.) # Some facts: this window now has 70 lines, about 135 columns... of course # it's mostly blank, and in fact just now it has about 3714 chars, not 70 * # 135 = 9450 as if it was nowhere blank. # Above we draw 9 * 16 = 144, so ratio is 3714 / 144 = 25, or 9450 / 144 = # 65. # Try 65 redundant loops above & see what happens. It takes it a couple # seconds! Too slow! Of course it's mostly the py code. # Anyway, it means we *will* have to do one of those optims mentioned, or # some other one like not clearing/redrawing the entire screen during most # text editing, or having per-line display lists. return #drawfont2 #e rename, clean up
def save(self): glFlush() ##k needed? don't know; works with it. Or try glFinish? not sure it's legal here. Not needed, never tried. glpane = self.env.glpane image = glpane.grabFrameBuffer() # not sure this is legal during the draw... but it seems to work # This is a QGLWidget method. Does it have args? only withalpha, not size (no way to only grab a subimage directly). # It returns a QImage. # See also QGLWidget::renderPixmap (sounds easy to mess up, so not tried). # Or we could use OpenGL to grab raw data (as we now do from depth buffer), then use PIL (or QImage) to output it... # maybe best in long run, but grabFrameBuffer works ok for now. #e # # Note: Return value is a constants.qt.QImage object; for debug prints including dir(image), see cvs rev 1.8 #e optim: use GL calls instead -- but that optim won't matter once we stop this from happening on every draw call ## print "glpane dims",glpane.width, glpane.height # on bruce's g4 now, whole glpane dims 633 573 (plausible; same as image dims); on g5, 690 637, also same in image assert glpane.width == image.width() assert glpane.height == image.height() # figure out where the image of self lies in this image of the entire glpane (in a rect defined by GL window coords x0,x1, y0,y1) #### WARNING: this method only works if we're not inside a display list thing = self.delegate lbox_corners = [(x,y) for x in (-thing.bleft, thing.bright) for y in (-thing.bbottom, thing.btop)] # Note, these are in local model coords, with implicit z = 0, NOT pixels. #bugfix 061127 133p: those minus signs -- I forgot them, and it took hours to debug this, since in simple examples # the affected attrs are 0. Does this indicate a design flaw in the lbox attr meanings? Guess: maybe -- # it might affect a lot of code, and be worse in some code like Column. Maybe we just need a default lbox_rect formula # which includes the proper signs. ###e points = [gluProject(x,y,0) for x,y in lbox_corners] # each point is x,y,depth, with x,y in OpenGL GLPane-window coords ## print "raw points are",points # this shows they are a list of 4 triples, are fractional, and are perfectly rectangular (since view not rotated). xs = [p[0] for p in points] ys = [p[1] for p in points] x0, x1 = min(xs), max(xs) y0, y1 = min(ys), max(ys) ###e could warn if the points are not a rectangle, i.e. if self is drawn in a rotated view # add pixelmargin, but limit by window size (glpane.width, glpane.height) # (the reason is to verify this grabs bgcolor from around the image; not sure it will, if pixel coords are pixel-centers) pixelmargin = 2 + 0.5 #e make 2 an option, so more easily usable for display of saved images too # note: if original points are pixel centers, then 0.5 of this serves to turn them into pixel boundaries, # but then we'd also want to round them, differently for low and high values, # so to do that, add 1 to high values before int() ### REVIEW: should we use intRound to avoid issue of int() rounding towards zero # even for negative coordinates (for which adding 0.5 has the wrong effect)? [bruce 080521 Q] x0 -= pixelmargin x0 = int(x0) if x0 < 0: x0 = 0 y0 -= pixelmargin y0 = int(y0) if y0 < 0: y0 = 0 x1 += pixelmargin + 1 # 1 is for rounding (see comment) x1 = int(x1) if x1 > glpane.width: x1 = glpane.width ###k need -1?? are these pixels or pixel-boundaries?? assume boundaries, see comment above y1 += pixelmargin + 1 y1 = int(y1) if y1 > glpane.height: y1 = glpane.height # convert to Qt window coords [note: the other code that does this doesn't use -1 either] y0 = glpane.height - y0 y1 = glpane.height - y1 y0, y1 = y1, y0 w = x1-x0 h = y1-y0 ## print "subimage dims",w,h assert x0 <= x1, "need x0 <= x1, got x0 = %r, x1 = %r" % (x0,x1) assert y0 <= y1, "need y0 <= y1, got y0 = %r, y1 = %r" % (y0,y1) # trim image, i.e. replace it with a subimage which only shows self.delegate image = image.copy(x0, y0, w, h) # QImage::copy ( int x, int y, int w, int h, int conversion_flags = 0 ) -- copy a subarea, return a new image filename = self.filename try: os.remove(filename) except OSError: # file doesn't exist pass image.save(filename, "JPEG", 85) #e 85->100 for testing, or use "quality" option; option for filetype, or split into helper... #e also possible: image.save(filename, "PNG") ##e probably better: "If format is omitted, the format is determined from the filename extension, if possible." # (Note that's about image.img.save -- not sure it also applies yet to image.save itself. # It's in http://www.pythonware.com/library/pil/handbook/image.htm .) # But I'd need to read up about how the option should be given for other formats. if os.path.isfile(filename): print "saved image, %d x %d:" % (w,h), filename else: print "save image (%d x %d) didn't work:" % (w,h), filename return
def save(self): glFlush( ) ##k needed? don't know; works with it. Or try glFinish? not sure it's legal here. Not needed, never tried. glpane = self.env.glpane image = glpane.grabFrameBuffer( ) # not sure this is legal during the draw... but it seems to work # This is a QGLWidget method. Does it have args? only withalpha, not size (no way to only grab a subimage directly). # It returns a QImage. # See also QGLWidget::renderPixmap (sounds easy to mess up, so not tried). # Or we could use OpenGL to grab raw data (as we now do from depth buffer), then use PIL (or QImage) to output it... # maybe best in long run, but grabFrameBuffer works ok for now. #e # # Note: Return value is a constants.qt.QImage object; for debug prints including dir(image), see cvs rev 1.8 #e optim: use GL calls instead -- but that optim won't matter once we stop this from happening on every draw call ## print "glpane dims",glpane.width, glpane.height # on bruce's g4 now, whole glpane dims 633 573 (plausible; same as image dims); on g5, 690 637, also same in image assert glpane.width == image.width() assert glpane.height == image.height() # figure out where the image of self lies in this image of the entire glpane (in a rect defined by GL window coords x0,x1, y0,y1) #### WARNING: this method only works if we're not inside a display list thing = self.delegate lbox_corners = [(x, y) for x in (-thing.bleft, thing.bright) for y in (-thing.bbottom, thing.btop)] # Note, these are in local model coords, with implicit z = 0, NOT pixels. #bugfix 061127 133p: those minus signs -- I forgot them, and it took hours to debug this, since in simple examples # the affected attrs are 0. Does this indicate a design flaw in the lbox attr meanings? Guess: maybe -- # it might affect a lot of code, and be worse in some code like Column. Maybe we just need a default lbox_rect formula # which includes the proper signs. ###e points = [ gluProject(x, y, 0) for x, y in lbox_corners ] # each point is x,y,depth, with x,y in OpenGL GLPane-window coords ## print "raw points are",points # this shows they are a list of 4 triples, are fractional, and are perfectly rectangular (since view not rotated). xs = [p[0] for p in points] ys = [p[1] for p in points] x0, x1 = min(xs), max(xs) y0, y1 = min(ys), max(ys) ###e could warn if the points are not a rectangle, i.e. if self is drawn in a rotated view # add pixelmargin, but limit by window size (glpane.width, glpane.height) # (the reason is to verify this grabs bgcolor from around the image; not sure it will, if pixel coords are pixel-centers) pixelmargin = 2 + 0.5 #e make 2 an option, so more easily usable for display of saved images too # note: if original points are pixel centers, then 0.5 of this serves to turn them into pixel boundaries, # but then we'd also want to round them, differently for low and high values, # so to do that, add 1 to high values before int() ### REVIEW: should we use intRound to avoid issue of int() rounding towards zero # even for negative coordinates (for which adding 0.5 has the wrong effect)? [bruce 080521 Q] x0 -= pixelmargin x0 = int(x0) if x0 < 0: x0 = 0 y0 -= pixelmargin y0 = int(y0) if y0 < 0: y0 = 0 x1 += pixelmargin + 1 # 1 is for rounding (see comment) x1 = int(x1) if x1 > glpane.width: x1 = glpane.width ###k need -1?? are these pixels or pixel-boundaries?? assume boundaries, see comment above y1 += pixelmargin + 1 y1 = int(y1) if y1 > glpane.height: y1 = glpane.height # convert to Qt window coords [note: the other code that does this doesn't use -1 either] y0 = glpane.height - y0 y1 = glpane.height - y1 y0, y1 = y1, y0 w = x1 - x0 h = y1 - y0 ## print "subimage dims",w,h assert x0 <= x1, "need x0 <= x1, got x0 = %r, x1 = %r" % (x0, x1) assert y0 <= y1, "need y0 <= y1, got y0 = %r, y1 = %r" % (y0, y1) # trim image, i.e. replace it with a subimage which only shows self.delegate image = image.copy(x0, y0, w, h) # QImage::copy ( int x, int y, int w, int h, int conversion_flags = 0 ) -- copy a subarea, return a new image filename = self.filename try: os.remove(filename) except OSError: # file doesn't exist pass image.save( filename, "JPEG", 85 ) #e 85->100 for testing, or use "quality" option; option for filetype, or split into helper... #e also possible: image.save(filename, "PNG") ##e probably better: "If format is omitted, the format is determined from the filename extension, if possible." # (Note that's about image.img.save -- not sure it also applies yet to image.save itself. # It's in http://www.pythonware.com/library/pil/handbook/image.htm .) # But I'd need to read up about how the option should be given for other formats. if os.path.isfile(filename): print "saved image, %d x %d:" % (w, h), filename else: print "save image (%d x %d) didn't work:" % (w, h), filename return
def model_coords(self,x,y): """given an (x,y) coordinate pair on the viewport, returns the coordinates in model space""" tz = gluProject(self._look_at[0],self._look_at[1], self._look_at[2])[2] # retrieve the depth coordinate return array(gluUnProject(x,self.get_view_height()-y,tz))
def mouseMoveEvent(self, event, camControl, scene): '''Handle the mouse move event, returning an EventReport. @param: event The event. @param: camControl The scene's camera control for this event. @param: sc ene The scene. @returns: An instance of EventReport. ''' result = SelectContext.mouseMoveEvent(self, event, camControl, scene) if (not result.isHandled and GLOBAL_SELECTION): if (self.manipulating): if (self.highlight == -1): # screen xform currCanonX = 2.0 * event.x() / camControl.VWIDTH - 1.0 currCanonY = 2.0 * event.y() / camControl.VHEIGHT - 1.0 ar = float(camControl.VWIDTH) / camControl.VHEIGHT dx = (currCanonX - self.downPoint[0]) * self.transScale * ar dy = -(currCanonY - self.downPoint[1]) * self.transScale disp = camControl.camera.right * dx + camControl.camera.up * dy else: dx = event.x() - self.downScreen[0] dy = self.downScreen[1] - event.y() if (self.highlight == 0): # manip x-axis disp = Vector3( dx * self.manipAxis[0] + dy * self.manipAxis[1], 0.0, 0.0) elif (self.highlight == 1): # manip y-axis disp = Vector3( 0.0, dx * self.manipAxis[0] + dy * self.manipAxis[1], 0.0) elif (self.highlight == 2): # manip z-axis disp = Vector3( 0.0, 0.0, dx * self.manipAxis[0] + dy * self.manipAxis[1]) self.pivot = self.pivotCache + disp for item in GLOBAL_SELECTION: item.xform.setFromCache(self.xformCache[item]) item.addTranslation(disp) result.needsRedraw = True else: # confirm modifiers projMat = glGetDoublev(GL_PROJECTION_MATRIX) viewport = glGetIntegerv(GL_VIEWPORT) glPushMatrix() self.manipXform(camControl) modelMat = glGetDoublev(GL_MODELVIEW_MATRIX) glPopMatrix() u, v, w = gluProject(0.0, 0.0, 0.0, modelMat, projMat, viewport) ux, vx, wx = gluProject(1.0, 0.0, 0.0, modelMat, projMat, viewport) xDistSq = distSqToSegment( Vector2(u, v), Vector2(ux, vx), Vector2(event.x(), camControl.VHEIGHT - event.y())) ux, vx, wx = gluProject(0.0, 1.0, 0.0, modelMat, projMat, viewport) yDistSq = distSqToSegment( Vector2(u, v), Vector2(ux, vx), Vector2(event.x(), camControl.VHEIGHT - event.y())) ux, vx, wx = gluProject(0.0, 0.0, 1.0, modelMat, projMat, viewport) zDistSq = distSqToSegment( Vector2(u, v), Vector2(ux, vx), Vector2(event.x(), camControl.VHEIGHT - event.y())) dists = np.array((xDistSq, yDistSq, zDistSq)) if (dists.min() < 25): h = dists.argmin() result.needsRedraw = self.highlight != h self.highlight = h else: result.needsRedraw = self.highlight != -1 self.highlight = -1 return result
def draw(self, performance): W, H = glfwGetWindowSize() scale = gameglobals.fontScale nameScoreList = [] #draw players scores player = self.players['Player'] text = 'Player: ' + str(self.scoreBoard['Player'][0]) x = 10.0 y = self.font_aa.getSize(text)[1] * scale nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Red' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = 10.0 y = H nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Green' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = W - self.font_aa.getSize(text)[0] * scale - 10 y = H nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Yellow' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = W - self.font_aa.getSize(text)[0] * scale - 10 y = self.font_aa.getSize(text)[1] * scale nameScoreList.append([text, x, y, player.color]) self.font_aa.begin() for nameScore in nameScoreList: glColor3f(nameScore[3][0], nameScore[3][1], nameScore[3][2]) self.font_aa.renderShadowed(nameScore[0], nameScore[1], nameScore[2], (0, 0, 0), scale) self.font_aa.end() #draw "hits" messages px = 50 for hit in self.hitMsgList: if hit[1] < px: addend = self.msgFlowFunction(hit[1], px) hitText = ' HITS!' if hit[0] < 2: hitText = ' HIT!' text = '+' + str(hit[0]) + hitText pCoords = hit[2] x, y, _ = gluProject(pCoords[0], pCoords[1], pCoords[2]) y = y + hit[1] glColor4f(hit[3][0], hit[3][1], hit[3][2], addend) self.font_aa.begin() self.font_aa.renderOutlined(text, x, y, (0, 0, 0), scale) self.font_aa.end() hit[1] += 200 * (1.2 - addend) * performance else: self.hitMsgList = self.hitMsgList[1:] #draw the faults messages px = 80 for fault in self.faultMsgList: if fault[2] < px: addend = self.msgFlowFunction(fault[2], px) text = fault[0] pts = fault[1] x, y = W / 2 - self.font_aa.getSize( text)[0] * scale / 2, H - 50 * scale y = y + fault[2] glColor4f(1.0, 0.8, 0.0, addend) self.font_aa.begin() self.font_aa.renderShadowed(text, x, y, (0, 0, 0), scale) if pts: glColor4f(0.5, 0.8, 0.1, addend) pts = '+' + pts x = W / 2 - self.font_aa.getSize(pts)[0] * scale / 2 y -= self.font_aa.getSize(pts)[1] * scale self.font_aa.renderShadowed(pts, x, y, (0, 0, 0), scale) self.font_aa.end() fault[2] += 200 * (1.2 - addend) * performance else: self.faultMsgList = self.faultMsgList[1:] #draw the taunts px = 100 for taunt in self.taunts: if taunt[1] < px: addend = self.msgFlowFunction(taunt[1], px) text = taunt[0] pCoords = taunt[2] x, y, _ = gluProject(pCoords[0], pCoords[1], pCoords[2]) y = y + taunt[1] x = x - self.font_aa.getSize(text)[0] * scale / 2 c = taunt[3] #players.colorNamesColors[taunt[2]] glColor4f(c[0], c[1], c[2], addend) self.font_aa.begin() self.font_aa.renderShadowed(text, x, y, (0, 0, 0), scale) self.font_aa.end() taunt[1] += 200 * (1.2 - addend) * performance else: self.taunts = self.taunts[1:] #draw current total combo total = self.scoreBoard.getTotalPoints() if total > 1: comboScale = scale * 1.25 totalText = 'Combo ' + str(total) + '!' x = W / 2 - self.font_aa.getSize(totalText)[0] * comboScale / 2 y = 2 * self.font_aa.getSize(totalText)[1] * comboScale glColor4f(0.0, 1.0, 1.0, 1) self.font_aa.begin() self.font_aa.renderShadowed(totalText, x, y, (0, 0, 0), comboScale) self.font_aa.end() #draw game over message if self.gameOver == True: loserMsg, loserColor = self.getLoserNameColor() loserMsg += ' lost!' msg = 'Game Over' loserScale = scale * 1.25 gOverScale = scale * 2.5 x0 = W / 2 - self.font_aa.getSize(loserMsg)[0] * loserScale / 2 y0 = H / 2 + H / 4 - self.font_aa.getSize( loserMsg)[1] * loserScale / 2 x1 = W / 2 - self.font_aa.getSize(msg)[0] * gOverScale / 2 y1 = H / 2 - self.font_aa.getSize(msg)[1] * gOverScale / 2 self.font_aa.begin() glColor4f(loserColor[0], loserColor[1], loserColor[2], 0.9) self.font_aa.render(loserMsg, x0, y0, loserScale) glColor4f(1.0, 0.0, 0.0, 0.9) self.font_aa.render(msg, x1, y1, gOverScale) self.font_aa.end()