Module Svg
[hide private]
[frames] | no frames]

Source Code for Module Svg

  1  ##################################################################### 
  2  # -*- coding: iso-8859-1 -*-                                        # 
  3  #                                                                   # 
  4  # Frets on Fire                                                     # 
  5  # Copyright (C) 2006 Sami Kyöstilä                                  # 
  6  #                                                                   # 
  7  # This program is free software; you can redistribute it and/or     # 
  8  # modify it under the terms of the GNU General Public License       # 
  9  # as published by the Free Software Foundation; either version 2    # 
 10  # of the License, or (at your option) any later version.            # 
 11  #                                                                   # 
 12  # This program is distributed in the hope that it will be useful,   # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of    # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     # 
 15  # GNU General Public License for more details.                      # 
 16  #                                                                   # 
 17  # You should have received a copy of the GNU General Public License # 
 18  # along with this program; if not, write to the Free Software       # 
 19  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,        # 
 20  # MA  02110-1301, USA.                                              # 
 21  ##################################################################### 
 22   
 23  import re 
 24  import os 
 25  from xml import sax 
 26  from OpenGL.GL import * 
 27  from numpy import reshape, dot, transpose, identity, zeros, float32 
 28  from math import sin, cos 
 29   
 30  import Log 
 31  import Config 
 32  from Texture import Texture, TextureException 
 33   
 34  try: 
 35    import amanith 
 36    import SvgColors 
 37    haveAmanith    = True 
 38  except ImportError: 
 39    Log.warn("PyAmanith not found, SVG support disabled.") 
 40    import DummyAmanith as amanith 
 41    haveAmanith    = False 
 42   
 43  # Add support for 'foo in attributes' syntax 
 44  if not hasattr(sax.xmlreader.AttributesImpl, '__contains__'): 
 45    sax.xmlreader.AttributesImpl.__contains__ = sax.xmlreader.AttributesImpl.has_key 
 46   
 47  # 
 48  #  Bugs and limitations: 
 49  # 
 50  #  - only the translate() and matrix() transforms are supported 
 51  #  - only paths are supported 
 52  #  - only constant color, linear gradient and radial gradient fill supported 
 53  # 
 54   
 55  Config.define("opengl",  "svgshaders",   bool,  False, text = "Use OpenGL SVG shaders",   options = {False: "No", True: "Yes"}) 
 56   
 57  LOW_QUALITY    = amanith.G_LOW_RENDERING_QUALITY 
 58  NORMAL_QUALITY = amanith.G_NORMAL_RENDERING_QUALITY 
 59  HIGH_QUALITY   = amanith.G_HIGH_RENDERING_QUALITY 
 60   
61 -class SvgGradient:
62 - def __init__(self, gradientDesc, transform):
63 self.gradientDesc = gradientDesc 64 self.transform = transform
65
66 - def applyTransform(self, transform):
67 m = dot(transform.matrix, self.transform.matrix) 68 self.gradientDesc.SetMatrix(transform.getGMatrix(m))
69
70 -class SvgContext:
71 - def __init__(self, geometry):
72 self.kernel = amanith.GKernel() 73 self.geometry = geometry 74 self.drawBoard = amanith.GOpenGLBoard(geometry[0], geometry[0] + geometry[2], 75 geometry[1], geometry[1] + geometry[3]) 76 self.drawBoard.SetShadersEnabled(Config.get("opengl", "svgshaders")) 77 self.transform = SvgTransform() 78 self.setGeometry(geometry) 79 self.setProjection(geometry) 80 81 # eat any possible OpenGL errors -- we can't handle them anyway 82 try: 83 glMatrixMode(GL_MODELVIEW) 84 except: 85 Log.warn("SVG renderer initialization failed; expect corrupted graphics. " + 86 "To fix this, upgrade your OpenGL drivers and set your display " + 87 "to 32 bit color precision.")
88
89 - def setGeometry(self, geometry = None):
90 self.drawBoard.SetViewport(geometry[0], geometry[1], 91 geometry[2], geometry[3]) 92 self.transform.reset() 93 self.transform.scale(geometry[2] / 640.0, geometry[3] / 480.0)
94
95 - def setProjection(self, geometry = None):
96 geometry = geometry or self.geometry 97 self.drawBoard.SetProjection(geometry[0], geometry[0] + geometry[2], 98 geometry[1], geometry[1] + geometry[3]) 99 self.geometry = geometry
100
101 - def setRenderingQuality(self, quality):
102 if quality == LOW_QUALITY: 103 q = amanith.G_LOW_RENDERING_QUALITY 104 elif quality == NORMAL_QUALITY: 105 q = amanith.G_NORMAL_RENDERING_QUALITY 106 elif quality == HIGH_QUALITY: 107 q = amanith.G_HIGH_RENDERING_QUALITY 108 else: 109 raise RaiseValueError("Bad rendering quality.") 110 self.drawBoard.SetRenderingQuality(q)
111
112 - def getRenderingQuality(self):
113 q = self.drawBoard.RenderingQuality() 114 if q == amanith.G_LOW_RENDERING_QUALITY: 115 return LOW_QUALITY 116 elif q == amanith.G_NORMAL_RENDERING_QUALITY: 117 return NORMAL_QUALITY 118 return HIGH_QUALITY
119
120 - def clear(self, r = 0, g = 0, b = 0, a = 0):
121 self.drawBoard.Clear(r, g, b, a)
122
123 -class SvgRenderStyle:
124 - def __init__(self, baseStyle = None):
125 self.strokeColor = None 126 self.strokeWidth = None 127 self.fillColor = None 128 self.strokeLineJoin = None 129 self.strokeOpacity = None 130 self.fillOpacity = None 131 132 if baseStyle: 133 self.__dict__.update(baseStyle.__dict__)
134
135 - def parseStyle(self, style):
136 s = {} 137 for m in re.finditer(r"(.+?):\s*(.+?)(;|$)\s*", style): 138 s[m.group(1)] = m.group(2) 139 return s
140
141 - def parseColor(self, color, defs = None):
142 if color.lower() == "none": 143 return None 144 145 try: 146 return SvgColors.colors[color.lower()] 147 except KeyError: 148 pass 149 150 if color[0] == "#": 151 color = color[1:] 152 if len(color) == 3: 153 return (int(color[0], 16) / 15.0, int(color[1], 16) / 15.0, int(color[2], 16) / 15.0, 1.0) 154 return (int(color[0:2], 16) / 255.0, int(color[2:4], 16) / 255.0, int(color[4:6], 16) / 255.0, 1.0) 155 else: 156 if not defs: 157 Log.warn("No patterns or gradients defined.") 158 return None 159 m = re.match("url\(#(.+)\)", color) 160 if m: 161 id = m.group(1) 162 if not id in defs: 163 Log.warn("Pattern/gradient %s has not been defined." % id) 164 return defs.get(id)
165
166 - def __cmp__(self, s):
167 if s: 168 for k, v in self.__dict__.items(): 169 if v != getattr(s, k): 170 return 1 171 return 0 172 return 1
173
174 - def __repr__(self):
175 return "<SvgRenderStyle " + " ".join(["%s:%s" % (k, v) for k, v in self.__dict__.items()]) + ">"
176
177 - def applyAttributes(self, attrs, defs):
178 style = attrs.get("style") 179 if style: 180 style = self.parseStyle(style) 181 #print style 182 if "stroke" in style: 183 self.strokeColor = self.parseColor(style["stroke"], defs) 184 if "fill" in style: 185 self.fillColor = self.parseColor(style["fill"], defs) 186 if "stroke-width" in style: 187 self.strokeWidth = float(style["stroke-width"].replace("px", "")) 188 if "stroke-opacity" in style: 189 self.strokeOpacity = float(style["stroke-opacity"]) 190 if "fill-opacity" in style: 191 self.fillOpacity = float(style["fill-opacity"]) 192 if "stroke-linejoin" in style: 193 j = style["stroke-linejoin"].lower() 194 if j == "miter": 195 self.strokeLineJoin = amanith.G_MITER_JOIN 196 elif j == "round": 197 self.strokeLineJoin = amanith.G_ROUND_JOIN 198 elif j == "bevel": 199 self.strokeLineJoin = amanith.G_BEVEL_JOIN
200
201 - def apply(self, drawBoard, transform):
202 if self.strokeColor is not None: 203 if isinstance(self.strokeColor, SvgGradient): 204 self.strokeColor.applyTransform(transform) 205 drawBoard.SetStrokePaintType(amanith.G_GRADIENT_PAINT_TYPE) 206 drawBoard.SetStrokeGradient(self.strokeColor.gradientDesc) 207 else: 208 drawBoard.SetStrokePaintType(amanith.G_COLOR_PAINT_TYPE) 209 drawBoard.SetStrokeColor(*self.strokeColor) 210 drawBoard.SetStrokeEnabled(True) 211 else: 212 drawBoard.SetStrokeEnabled(False) 213 214 if self.fillColor is not None: 215 if isinstance(self.fillColor, SvgGradient): 216 self.fillColor.applyTransform(transform) 217 drawBoard.SetFillPaintType(amanith.G_GRADIENT_PAINT_TYPE) 218 drawBoard.SetFillGradient(self.fillColor.gradientDesc) 219 else: 220 drawBoard.SetFillPaintType(amanith.G_COLOR_PAINT_TYPE) 221 drawBoard.SetFillColor(*self.fillColor) 222 drawBoard.SetFillEnabled(True) 223 else: 224 drawBoard.SetFillEnabled(False) 225 226 if self.strokeWidth is not None: 227 drawBoard.SetStrokeWidth(self.strokeWidth) 228 229 if self.strokeOpacity is not None: 230 drawBoard.SetStrokeOpacity(self.strokeOpacity) 231 232 if self.fillOpacity is not None: 233 drawBoard.SetFillOpacity(self.fillOpacity) 234 235 if self.strokeLineJoin is not None: 236 drawBoard.SetStrokeJoinStyle(self.strokeLineJoin)
237
238 -class SvgTransform:
239 - def __init__(self, baseTransform = None):
240 self._gmatrix = amanith.GMatrix33() 241 self.reset() 242 243 if baseTransform: 244 self.matrix = baseTransform.matrix.copy()
245
246 - def applyAttributes(self, attrs, key = "transform"):
247 transform = attrs.get(key) 248 if transform: 249 m = re.match(r"translate\(\s*(.+?)\s*,(.+?)\s*\)", transform) 250 if m: 251 dx, dy = [float(c) for c in m.groups()] 252 self.matrix[0, 2] += dx 253 self.matrix[1, 2] += dy 254 m = re.match(r"matrix\(\s*" + "\s*,\s*".join(["(.+?)"] * 6) + r"\s*\)", transform) 255 if m: 256 e = [float(c) for c in m.groups()] 257 e = [e[0], e[2], e[4], e[1], e[3], e[5], 0, 0, 1] 258 m = reshape(e, (3, 3)) 259 self.matrix = dot(self.matrix, m)
260
261 - def transform(self, transform):
262 self.matrix = dot(self.matrix, transform.matrix)
263
264 - def reset(self):
265 self.matrix = identity(3, float32)
266
267 - def translate(self, dx, dy):
268 m = zeros((3, 3)) 269 m[0, 2] = dx 270 m[1, 2] = dy 271 self.matrix += m
272
273 - def rotate(self, angle):
274 m = identity(3, float32) 275 s = sin(angle) 276 c = cos(angle) 277 m[0, 0] = c 278 m[0, 1] = -s 279 m[1, 0] = s 280 m[1, 1] = c 281 self.matrix = dot(self.matrix, m)
282
283 - def scale(self, sx, sy):
284 m = identity(3, float32) 285 m[0, 0] = sx 286 m[1, 1] = sy 287 self.matrix = dot(self.matrix, m)
288
289 - def applyGL(self):
290 # Interpret the 2D matrix as 3D 291 m = self.matrix 292 m = [m[0, 0], m[1, 0], 0.0, 0.0, 293 m[0, 1], m[1, 1], 0.0, 0.0, 294 0.0, 0.0, 1.0, 0.0, 295 m[0, 2], m[1, 2], 0.0, 1.0] 296 glMultMatrixf(m)
297
298 - def getGMatrix(self, m):
299 f = float 300 self._gmatrix.Set( \ 301 f(m[0, 0]), f(m[0, 1]), f(m[0, 2]), \ 302 f(m[1, 0]), f(m[1, 1]), f(m[1, 2]), \ 303 f(m[2, 0]), f(m[2, 1]), f(m[2, 2])) 304 return self._gmatrix
305
306 - def apply(self, drawBoard):
307 drawBoard.SetModelViewMatrix(self.getGMatrix(self.matrix))
308
309 -class SvgHandler(sax.ContentHandler):
310 - def __init__(self, drawBoard, cache):
311 self.drawBoard = drawBoard 312 self.styleStack = [SvgRenderStyle()] 313 self.contextStack = [None] 314 self.transformStack = [SvgTransform()] 315 self.defs = {} 316 self.cache = cache
317
318 - def startElement(self, name, attrs):
319 style = SvgRenderStyle(self.style()) 320 style.applyAttributes(attrs, self.defs) 321 self.styleStack.append(style) 322 323 transform = SvgTransform(self.transform()) 324 transform.applyAttributes(attrs) 325 self.transformStack.append(transform) 326 327 try: 328 f = "start" + name.capitalize() 329 #print f, self.transformStack 330 #print len(self.styleStack) 331 f = getattr(self, f) 332 except AttributeError: 333 return 334 f(attrs)
335
336 - def endElement(self, name):
337 try: 338 f = "end" + name.capitalize() 339 #print f, self.contextStack 340 getattr(self, f)() 341 except AttributeError: 342 pass 343 self.styleStack.pop() 344 self.transformStack.pop()
345
346 - def startG(self, attrs):
347 self.contextStack.append("g")
348
349 - def endG(self):
350 self.contextStack.pop()
351
352 - def startDefs(self, attrs):
353 self.contextStack.append("defs")
354
355 - def endDefs(self):
356 self.contextStack.pop()
357
358 - def startMarker(self, attrs):
359 self.contextStack.append("marker")
360
361 - def endMarker(self):
362 self.contextStack.pop()
363
364 - def context(self):
365 return self.contextStack[-1]
366
367 - def style(self):
368 return self.styleStack[-1]
369
370 - def transform(self):
371 return self.transformStack[-1]
372
373 - def startPath(self, attrs):
374 if self.context() in ["g", None]: 375 if "d" in attrs: 376 self.style().apply(self.drawBoard, self.transform()) 377 self.transform().apply(self.drawBoard) 378 d = str(attrs["d"]) 379 self.cache.addStroke(self.style(), self.transform(), self.drawBoard.DrawPaths(d))
380
381 - def createLinearGradient(self, attrs, keys):
382 a = dict(attrs) 383 if not "x1" in a or not "x2" in a or not "y1" in a or not "y2" in a: 384 a["x1"] = a["y1"] = 0.0 385 a["x2"] = a["y2"] = 1.0 386 if "id" in a and "x1" in a and "x2" in a and "y1" in a and "y2" in a: 387 transform = SvgTransform() 388 if "gradientTransform" in a: 389 transform.applyAttributes(a, key = "gradientTransform") 390 x1, y1, x2, y2 = [float(a[k]) for k in ["x1", "y1", "x2", "y2"]] 391 return a["id"], self.drawBoard.CreateLinearGradient((x1, y1), (x2, y2), keys), transform 392 return None, None, None
393
394 - def createRadialGradient(self, attrs, keys):
395 a = dict(attrs) 396 if not "cx" in a or not "cy" in a or not "fx" in a or not "fy" in a: 397 a["cx"] = a["cy"] = 0.0 398 a["fx"] = a["fy"] = 1.0 399 if "id" in a and "cx" in a and "cy" in a and "fx" in a and "fy" in a and "r" in a: 400 transform = SvgTransform() 401 if "gradientTransform" in a: 402 transform.applyAttributes(a, key = "gradientTransform") 403 cx, cy, fx, fy, r = [float(a[k]) for k in ["cx", "cy", "fx", "fy", "r"]] 404 return a["id"], self.drawBoard.CreateRadialGradient((cx, cy), (fx, fy), r, keys), transform 405 return None, None, None
406
407 - def startLineargradient(self, attrs):
408 if self.context() == "defs": 409 if "xlink:href" in attrs: 410 id = attrs["xlink:href"][1:] 411 if not id in self.defs: 412 Log.warn("Linear gradient %s has not been defined." % id) 413 else: 414 keys = self.defs[id].gradientDesc.ColorKeys() 415 id, grad, trans = self.createLinearGradient(attrs, keys) 416 self.defs[id] = SvgGradient(grad, trans) 417 else: 418 self.contextStack.append("gradient") 419 self.stops = [] 420 self.gradientAttrs = attrs
421
422 - def startRadialgradient(self, attrs):
423 if self.context() == "defs": 424 if "xlink:href" in attrs: 425 id = attrs["xlink:href"][1:] 426 if not id in self.defs: 427 Log.warn("Radial gradient %s has not been defined." % id) 428 else: 429 keys = self.defs[id].gradientDesc.ColorKeys() 430 id, grad, trans = self.createRadialGradient(attrs, keys) 431 self.defs[id] = SvgGradient(grad, trans) 432 else: 433 self.contextStack.append("gradient") 434 self.stops = [] 435 self.gradientAttrs = attrs
436
437 - def parseKeys(self, stops):
438 keys = [] 439 for stop in self.stops: 440 color, opacity, offset = None, None, None 441 if "style" in stop: 442 style = self.style().parseStyle(stop["style"]) 443 if "stop-color" in style: 444 color = self.style().parseColor(style["stop-color"]) 445 if "stop-opacity" in style: 446 opacity = float(style["stop-opacity"]) 447 if "offset" in stop: 448 offset = float(stop["offset"]) 449 if offset is not None and (color is not None or opacity is not None): 450 if opacity is None: opacity = 1.0 451 k = amanith.GKeyValue(offset, (color[0], color[1], color[2], opacity)) 452 keys.append(k) 453 return keys
454
455 - def endLineargradient(self):
456 if self.context() == "gradient": 457 keys = self.parseKeys(self.stops) 458 id, grad, trans = self.createLinearGradient(self.gradientAttrs, keys) 459 del self.stops 460 del self.gradientAttrs 461 if id and grad: 462 self.defs[id] = SvgGradient(grad, trans) 463 self.contextStack.pop()
464
465 - def endRadialgradient(self):
466 if self.context() == "gradient": 467 keys = self.parseKeys(self.stops) 468 id, grad, trans = self.createRadialGradient(self.gradientAttrs, keys) 469 del self.stops 470 del self.gradientAttrs 471 if id and grad: 472 self.defs[id] = SvgGradient(grad, trans) 473 self.contextStack.pop()
474
475 - def startStop(self, attrs):
476 if self.context() == "gradient": 477 self.stops.append(attrs)
478
479 -class SvgCache:
480 - def __init__(self, drawBoard):
481 self.drawBoard = drawBoard 482 self.displayList = [] 483 self.transforms = {} 484 self.bank = drawBoard.CreateCacheBank()
485
486 - def beginCaching(self):
487 self.drawBoard.SetCacheBank(self.bank) 488 self.drawBoard.SetTargetMode(amanith.G_CACHE_MODE)
489
490 - def endCaching(self):
491 self.drawBoard.SetTargetMode(amanith.G_COLOR_MODE) 492 self.drawBoard.SetCacheBank(None)
493
494 - def addStroke(self, style, transform, slot):
495 if self.displayList: 496 lastStyle = self.displayList[-1][0] 497 else: 498 lastStyle = None 499 500 self.transforms[slot] = transform 501 502 if lastStyle == style: 503 lastSlotStart, lastSlotEnd = self.displayList[-1][1][-1] 504 if lastSlotEnd == slot - 1: 505 self.displayList[-1][1][-1] = (lastSlotStart, slot) 506 else: 507 self.displayList[-1][1].append((slot, slot)) 508 else: 509 self.displayList.append((style, [(slot, slot)]))
510
511 - def draw(self, baseTransform):
512 self.drawBoard.SetCacheBank(self.bank) 513 for style, slotList in self.displayList: 514 transform = SvgTransform(baseTransform) 515 transform.transform(self.transforms[slotList[0][0]]) 516 transform.apply(self.drawBoard) 517 style.apply(self.drawBoard, transform) 518 for firstSlot, lastSlot in slotList: 519 self.drawBoard.DrawCacheSlots(firstSlot, lastSlot) 520 self.drawBoard.SetCacheBank(None) 521 522 # eat any possible OpenGL errors -- we can't handle them anyway 523 try: 524 glMatrixMode(GL_MODELVIEW) 525 except: 526 pass
527
528 -class SvgDrawing:
529 - def __init__(self, context, svgData):
530 self.svgData = None 531 self.texture = None 532 self.context = context 533 self.cache = None 534 self.transform = SvgTransform() 535 536 # Detect the type of data passed in 537 if type(svgData) == file: 538 self.svgData = svgData.read() 539 elif type(svgData) == str: 540 # Check whether we have a cached bitmap version 541 bitmapFile = svgData.replace(".svg", ".png") 542 if svgData.endswith(".svg") and os.path.exists(bitmapFile) and 0: 543 Log.debug("Loading cached bitmap '%s' instead of '%s'." % (bitmapFile, svgData)) 544 self.texture = Texture(bitmapFile) 545 else: 546 if not haveAmanith: 547 e = "PyAmanith is not installed and you are trying to load an SVG file." 548 Log.error(e) 549 raise RuntimeError(e) 550 Log.debug("Loading SVG file '%s'." % (svgData)) 551 self.svgData = open(svgData).read()
552
553 - def _cacheDrawing(self, drawBoard):
554 self.cache.beginCaching() 555 parser = sax.make_parser() 556 sax.parseString(self.svgData, SvgHandler(drawBoard, self.cache)) 557 self.cache.endCaching() 558 del self.svgData
559
560 - def convertToTexture(self, width, height):
561 if self.texture: 562 return 563 564 try: 565 self.texture = Texture() 566 self.texture.bind() 567 self.texture.prepareRenderTarget(width, height) 568 self.texture.setAsRenderTarget() 569 quality = self.context.getRenderingQuality() 570 self.context.setRenderingQuality(HIGH_QUALITY) 571 geometry = self.context.geometry 572 self.context.setProjection((0, 0, width, height)) 573 glViewport(0, 0, width, height) 574 self.context.clear() 575 transform = SvgTransform() 576 transform.translate(width / 2, height / 2) 577 self._render(transform) 578 self.texture.resetDefaultRenderTarget() 579 self.context.setProjection(geometry) 580 glViewport(*geometry) 581 self.context.setRenderingQuality(quality) 582 except TextureException, e: 583 Log.warn("Unable to convert SVG drawing to texture: %s" % str(e))
584
585 - def _getEffectiveTransform(self):
589
590 - def _render(self, transform):
591 glMatrixMode(GL_TEXTURE) 592 glPushMatrix() 593 glMatrixMode(GL_MODELVIEW) 594 595 glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_STENCIL_BUFFER_BIT | GL_TRANSFORM_BIT | GL_COLOR_BUFFER_BIT | GL_POLYGON_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT) 596 if not self.cache: 597 self.cache = SvgCache(self.context.drawBoard) 598 self._cacheDrawing(self.context.drawBoard) 599 self.cache.draw(transform) 600 glPopAttrib() 601 602 glMatrixMode(GL_TEXTURE) 603 glPopMatrix() 604 glMatrixMode(GL_MODELVIEW)
605
606 - def draw(self, color = (1, 1, 1, 1)):
607 glMatrixMode(GL_TEXTURE) 608 glPushMatrix() 609 glMatrixMode(GL_PROJECTION) 610 glPushMatrix() 611 self.context.setProjection() 612 glMatrixMode(GL_MODELVIEW) 613 glPushMatrix() 614 615 transform = self._getEffectiveTransform() 616 if self.texture: 617 glLoadIdentity() 618 transform.applyGL() 619 620 glScalef(self.texture.pixelSize[0], self.texture.pixelSize[1], 1) 621 glTranslatef(-.5, -.5, 0) 622 glColor4f(*color) 623 624 self.texture.bind() 625 glEnable(GL_TEXTURE_2D) 626 glBegin(GL_TRIANGLE_STRIP) 627 glTexCoord2f(0.0, 1.0) 628 glVertex2f(0.0, 1.0) 629 glTexCoord2f(1.0, 1.0) 630 glVertex2f(1.0, 1.0) 631 glTexCoord2f(0.0, 0.0) 632 glVertex2f(0.0, 0.0) 633 glTexCoord2f(1.0, 0.0) 634 glVertex2f(1.0, 0.0) 635 glEnd() 636 glDisable(GL_TEXTURE_2D) 637 else: 638 self._render(transform) 639 glMatrixMode(GL_TEXTURE) 640 glPopMatrix() 641 glMatrixMode(GL_MODELVIEW) 642 glPopMatrix() 643 glMatrixMode(GL_PROJECTION) 644 glPopMatrix() 645 glMatrixMode(GL_MODELVIEW)
646