[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [pygame] QuadMap
DR0ID wrote:
nice!
Some comments would be appreciated. Is it an affine transformation? The
hit test look like raytracing code; how does it work?
Well, no can do - I'm looking stuff up in books and online, and barely
understanding this myself. For instance - you must specify the
quadrilateral corners in topleft, bottomleft, bottomright, topright
order for the picture to be upright - why's that? Specifying them in a
different order gives various flipping and mirroring effects... but
sometimes it crashes. Anyways, if you can figure it out, let me know. :-D
But what I can give you, is a more interesting version that textures the
quadrilaterals.
import pygame, math, Numeric
WIDTH = 800
HEIGHT = 600
BLACK = ( 0, 0, 0, 255)
WHITE = (255, 255, 255, 255)
RED = (255, 0, 0, 255)
YELLOW = (255, 255, 0, 255)
BLUE = ( 0, 0, 255, 255)
GREEN = ( 0, 255, 0, 255)
GRAY = (212, 208, 200, 255)
MAGENTA = (255, 0, 255, 255)
class Mesh(object):
quads = None
texture = None
posx = 0
posy = 0
def __init__(self):
self.pic = pygame.Surface([WIDTH, HEIGHT], pygame.SRCALPHA,
32).convert_alpha()
self.quads = []
def Add(self, quads):
self.quads.append(quads)
def Texture(self, texture):
quad = None
w, h = self.pic.get_size()
tw, th = texture.get_size()
array = pygame.surfarray.pixels3d(texture)
alpha = pygame.surfarray.pixels_alpha(texture)
myarray = pygame.surfarray.pixels3d(self.pic)
myalpha = pygame.surfarray.pixels_alpha(self.pic)
for quad in self.quads:
for y in range(quad.miny, quad.maxy):
for x in range(quad.minx, quad.maxx):
offset = quad.PointToOffset([x, y])
if offset:
x1 = int((tw-1) * offset[0])
y1 = int((th-1) * offset[1])
myarray[x, y] = array[x1, y1]
myalpha[x, y] = alpha[x1, y1]
def Draw(self, bg):
bg.blit(self.pic, [self.posx, self.posy])
for quad in self.quads:
quad.Draw(bg)
def PointToOffset(self, pos):
for quad in self.quads:
offset = quad.PointToOffset(pos)
if offset:
return offset
return None
def OffsetToPoint(self, offset):
for quad in self.quads:
quad.point = quad.OffsetToPoint(offset)
class Quad(object):
data = None
point = None
def __init__(self, p1, p2, p3, p4):
self.p1 = list(p1)
self.p2 = list(p2)
self.p3 = list(p3)
self.p4 = list(p4)
self.polys = [self.p1, self.p2, self.p3, self.p4]
self.minx = 99999
self.maxx = -1
self.miny = 99999
self.maxy = -1
for x, y in self.polys:
self.minx = min(self.minx, x)
self.maxx = max(self.maxx, x)
self.miny = min(self.miny, y)
self.maxy = max(self.maxy, y)
def Draw(self, bg):
pygame.draw.line(bg, RED, self.p1, self.p2, 1)
pygame.draw.line(bg, YELLOW, self.p2, self.p3, 1)
pygame.draw.line(bg, BLUE, self.p3, self.p4, 1)
pygame.draw.line(bg, GREEN, self.p4, self.p1, 1)
if self.point:
pygame.draw.rect(bg, MAGENTA, [self.point[0]-2,
self.point[1]-2, 4, 4], 0)
def OffsetToPoint(self, offset):
if offset == None:
return None
s, t = offset
x1, y1 = self.p1
x2, y2 = self.p2
x3, y3 = self.p4
x4, y4 = self.p3
xa = x1 + t * (x2 - x1)
ya = y1 + t * (y2 - y1)
xb = x3 + t * (x4 - x3)
yb = y3 + t * (y4 - y3)
X = xa + s * (xb - xa)
Y = ya + s * (yb - ya)
return int(X), int(Y)
def PointToOffset(self, pos):
x, y = pos[0], pos[1]
if not (x >= self.minx and x <= self.maxx and y >= self.miny
and y <= self.maxy):
return None
x1, y1 = self.p1
x2, y2 = self.p2
x3, y3 = self.p4
x4, y4 = self.p3
Ax = x2 - x1
Ay = y2 - y1
Bx = x4 - x3
By = y4 - y3
Cx = x3 - x1
Cy = y3 - y1
Dx = x - x1
Dy = y - y1
Ex = Bx - Ax
Ey = By - Ay
a = -Ax * Ey + Ay * Ex
b = Ey * Dx - Dy * Ex + Ay * Cx - Ax * Cy
c = Dx * Cy - Dy * Cx
det = b * b - 4 * a * c
if det >= 0:
if abs(a) < 0.001:
t = -c / float(b)
else:
t = (-b - math.sqrt(det)) / float(2 * a)
denom = (Cx + Ex * t)
if denom > 0.01:
s = (Dx - Ax * t) / float(denom)
else:
s = (Dy - Ay * t) / float(Cy + Ey * t)
if (t >= 0) and (t <= 1) and (s >= 0) and (s <= 1):
return s, t
def LoadPic(filename = 'test2.jpg'):
try:
pic = pygame.image.load(filename).convert_alpha()
except:
pic = pygame.Surface([100, 100], pygame.SRCALPHA,
32).convert_alpha()
pic.fill(RED, [0, 0, 50, 50])
pic.fill(YELLOW, [50, 0, 50, 50])
pic.fill(BLUE, [0, 50, 50, 50])
pic.fill(GREEN, [50, 50, 50, 50])
pic = AdjustAlpha(pic, .3)
return pic
def AdjustAlpha(pic, adj = .5):
alphaarray = pygame.surfarray.array_alpha(pic).astype(Numeric.Float)
alphaarray[:, :] = Numeric.clip(alphaarray * adj, 0, 255)
pygame.surfarray.pixels_alpha(pic)[:, :] =
alphaarray.astype(Numeric.UInt8)
return pic
def main():
pygame.init()
bg = pygame.display.set_mode([WIDTH, HEIGHT], 0, 32)
quit = 0
pic = LoadPic()
mesh = Mesh()
w, h = pic.get_size()
x, y = 280, 20
mesh.Add(Quad([x, y], [x, y+h], [x+w, y+h], [x+w, y]) )
x, y = 280, 300
mesh.Add(Quad([x, y+h], [x, y], [x+w, y], [x+w, y+h]) )
x, y = 0, 400
w, h = 200, 150
mesh.Add(Quad([x+w, y], [x, y], [x, y+h], [x+w, y+h]) )
mesh.Add(Quad([ 20, 50], [120, 30], [150, 110], [ 10, 130]) )
mesh.Add(Quad([210, 170], [250, 260], [100, 240], [120, 150]) )
if mesh.Texture(pic):
pass
else:
while not quit:
bg.fill(GRAY)
mesh.Draw(bg)
pygame.display.flip()
pygame.event.pump()
moved = 0
for e in pygame.event.get():
if e.type == pygame.QUIT:
quit = 1
break
elif e.type == pygame.MOUSEMOTION:
if not moved:
moved = 1
offset = mesh.PointToOffset(e.pos)
mesh.OffsetToPoint(offset)
pygame.quit()
if __name__ == '__main__':
main()