256 lines
7.4 KiB
Python
256 lines
7.4 KiB
Python
#!/usr/bin/env python
|
|
|
|
# Copyright (C) 2011 Sam Bull
|
|
|
|
"""
|
|
Base widget, all widgets inherit from this.
|
|
|
|
"""
|
|
|
|
from pygame.locals import Rect
|
|
from OpenGL.GL import *
|
|
import FTGL
|
|
|
|
from ..surface import SurfaceBase
|
|
|
|
|
|
class OpenGLImage(SurfaceBase):
|
|
"""
|
|
Class used to emulate the interface of Surface for OpenGL drawing.
|
|
|
|
Functions should be used in the same manner as pygame.Surface.
|
|
Differences are shown in documentation, otherwise assume it to
|
|
function the same as the equivalent pygame.Surface function.
|
|
|
|
"""
|
|
def __init__(self, surf, parent=None, **kwargs):
|
|
self._a = None
|
|
self._lock = False
|
|
self.display_list = []
|
|
self._children = []
|
|
if parent:
|
|
self._parent = parent # Parent surface used for _abs
|
|
else:
|
|
self._parent = self._default_screen
|
|
|
|
self._rect = Rect((0,0), (0,0))
|
|
if isinstance(surf, (tuple,list)):
|
|
self._rect.size = surf
|
|
elif isinstance(surf, OpenGLFont):
|
|
self._rect.size = (surf.size)
|
|
self.display_list.extend(surf.display_list)
|
|
elif isinstance(surf, OpenGLImage):
|
|
self._rect = surf._rect
|
|
self._a = surf._a
|
|
self.display_list = surf.display_list
|
|
self._children = surf._children
|
|
|
|
def blit(self, surf, pos=None):
|
|
assert isinstance(surf, OpenGLImage)
|
|
if surf not in self._children:
|
|
if pos is not None: surf.pos = pos
|
|
surf._parent = self
|
|
self._children.append(surf)
|
|
|
|
def draw(self):
|
|
glLoadIdentity()
|
|
if self.rect.w <= self._parent.rect.w and \
|
|
self.rect.h <= self._parent.rect.h:
|
|
# Mask the area, so nothing is drawn outside surface area.
|
|
bottom = self._default_screen.h - self.rect_abs.bottom
|
|
glScissor(self.rect_abs.x, bottom,
|
|
self.rect.w+1, self.rect.h+1)
|
|
glTranslatef(self.pos_abs[0], self.pos_abs[1], 0)
|
|
for dl,col in self.display_list:
|
|
if col is not None: glColor(col[0], col[1], col[2], self.a)
|
|
glCallList(dl)
|
|
for child in self._children:
|
|
child.draw()
|
|
|
|
def fill(self, col=0, rect=None, special_flags=0):
|
|
"""If col == 0 and rect is None, clears image with no fill."""
|
|
if rect is None:
|
|
# Clear the surface
|
|
self.display_list = []
|
|
self._children = []
|
|
rect = Rect((0,0), self.size)
|
|
if col != 0:
|
|
col = [c/255. for c in col]
|
|
dl = glGenLists(1)
|
|
glNewList(dl, GL_COMPILE)
|
|
glRectfv(rect.topleft, rect.bottomright)
|
|
glEndList()
|
|
self.display_list.append((dl, col))
|
|
|
|
def copy(self):
|
|
return OpenGLImage(self)
|
|
|
|
def get_size(self):
|
|
return self.size
|
|
|
|
def set_alpha(self, alpha):
|
|
self._a = alpha/255.
|
|
|
|
def set_at(self, vertex, col):
|
|
col = [c/255. for c in col]
|
|
|
|
if self._lock:
|
|
glColor(*col)
|
|
else:
|
|
dl = glGenLists(1)
|
|
glNewList(dl, GL_COMPILE)
|
|
glBegin(GL_POINTS)
|
|
|
|
glVertex(vertex)
|
|
|
|
if not self._lock:
|
|
glEnd()
|
|
glEndList()
|
|
surf.display_list.append((dl, col))
|
|
|
|
def lock(self):
|
|
"""
|
|
Should only be used for multiple set_at() calls.
|
|
Should not be used in conjuction with the draw functions.
|
|
|
|
"""
|
|
self._lock = True
|
|
self._lock_dl = glGenLists(1)
|
|
glNewList(self._lock_dl, GL_COMPILE)
|
|
glBegin(GL_POINTS)
|
|
|
|
def unlock(self):
|
|
glEnd()
|
|
glEndList()
|
|
self.display_list.append((self._lock_dl, None))
|
|
del self._lock_dl
|
|
self._lock = False
|
|
|
|
def replace(self, surf, **kwargs):
|
|
self._rect.size = surf.size
|
|
self.display_list = surf.display_list[:]
|
|
self._children = surf._children[:]
|
|
|
|
@property
|
|
def a(self):
|
|
if self._a is not None:
|
|
return self._a
|
|
else:
|
|
return self._parent.a
|
|
|
|
# --- Dummy methods. Ignore. ---
|
|
|
|
def __call__(self):
|
|
return self
|
|
|
|
def set_colorkey(self, col):
|
|
pass
|
|
|
|
class OpenGLFont():
|
|
"""
|
|
Wraps the FTGL.TextureFont to allow it to be added
|
|
to an OpenGLImage object in the same manner as pygame.Font.
|
|
|
|
"""
|
|
def __init__(self, font, size):
|
|
self._children = []
|
|
self.font = FTGL.TextureFont(font)
|
|
self.font.FaceSize(16)
|
|
self.y_offset = self.font.line_height * .75
|
|
|
|
def render(self, text, antialias, color, background=None):
|
|
text = text.encode()
|
|
col = [c/255. for c in color]
|
|
dl = glGenLists(1)
|
|
self.size = (self.font.Advance(text), self.font.line_height)
|
|
glNewList(dl, GL_COMPILE)
|
|
glPushMatrix()
|
|
# Flip text right way up
|
|
glMultMatrixf((1, 0, 0, 0,
|
|
0,-1, 0, 0,
|
|
0, 0, 1, 0,
|
|
0, self.y_offset, 0, 1))
|
|
self.font.Render(text)
|
|
glPopMatrix()
|
|
glEndList()
|
|
self.display_list = [(dl, col)]
|
|
return self
|
|
|
|
class Draw():
|
|
"""
|
|
Class to emulate the pygame.draw module.
|
|
Functions should work in the same manner.
|
|
|
|
"""
|
|
def rect(self, surf, col, rect, width=0):
|
|
col = [c/255. for c in col]
|
|
dl = glGenLists(1)
|
|
glNewList(dl, GL_COMPILE)
|
|
if not width:
|
|
glRectfv(rect.topleft, rect.bottomright)
|
|
else:
|
|
if width > 1: width -= 1
|
|
hw = width/2.
|
|
glLineWidth(width)
|
|
glBegin(GL_LINES)
|
|
glVertex(rect.x, rect.y + hw)
|
|
glVertex(rect.right - width, rect.y + hw)
|
|
# (hw%1) fixes line rendering off by a pixel
|
|
glVertex(rect.right - hw, rect.y + (hw%1))
|
|
glVertex(rect.right - hw, rect.bottom - width + (hw%1))
|
|
glVertex(rect.right, rect.bottom - hw)
|
|
glVertex(rect.x + width, rect.bottom - hw)
|
|
glVertex(rect.x + hw, rect.bottom)
|
|
glVertex(rect.x + hw, rect.y + width)
|
|
glEnd()
|
|
glEndList()
|
|
surf.display_list.append((dl, col))
|
|
|
|
def polygon(self, surf, col, pointlist, width=0):
|
|
"""
|
|
With width == 0, can only draw convex polygons. Be careful of
|
|
the order of vertices if it draws differently than pygame.
|
|
|
|
"""
|
|
col = [c/255. for c in col]
|
|
dl = glGenLists(1)
|
|
glNewList(dl, GL_COMPILE)
|
|
if not width:
|
|
glBegin(GL_POLYGON)
|
|
for v in pointlist:
|
|
glVertex(v)
|
|
glEnd()
|
|
glEndList()
|
|
surf.display_list.append((dl, col))
|
|
|
|
def circle(self, surf, col, pos, radius, width=0):
|
|
col = [c/255. for c in col]
|
|
dl = glGenLists(1)
|
|
glNewList(dl, GL_COMPILE)
|
|
if not width:
|
|
glEnable(GL_POINT_SMOOTH)
|
|
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST)
|
|
glPointSize(radius*2)
|
|
glBegin(GL_POINTS)
|
|
glVertex(pos)
|
|
glEnd()
|
|
glDisable(GL_POINT_SMOOTH)
|
|
glPointSize()
|
|
glEndList()
|
|
surf.display_list.append((dl, col))
|
|
|
|
def line(self, surf, col, start_pos, end_pos, width=1):
|
|
col = [c/255. for c in col]
|
|
dl = glGenLists(1)
|
|
glNewList(dl, GL_COMPILE)
|
|
glLineWidth(width)
|
|
glBegin(GL_LINES)
|
|
glVertex(start_pos)
|
|
glVertex(end_pos)
|
|
glEnd()
|
|
glEndList()
|
|
surf.display_list.append((dl, col))
|
|
|
|
# Export Draw functions
|
|
draw = Draw()
|