[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] QuadMap



Hi

Since you posted your quad stuff, I got an idea and now finally I had the time to try it out. But I encountered some problems! It does not work as I expect it to work.

The idea is to take an image, slice it into rectangles, then randomize the egdgepoints of the rects and apply your quad code to the quads (rects with randomized edgepoints). But sometimes it works, sometimes not. Because I do not fully understand what you are exactly doing in the quad code I ask you to take a look.

I see no reason why it should not work since I do exactly the same as you have done in the last example (at least I think I do what you do).

If you set 'CHAOS' to 0 then it works perfectly, but is a bit boring because it is without randomness. As soon you set 'CHAOS'!=0 it does not work anymore! (hmm, sometimes single quads work, but the rest does not....)

I have modified mesh to my needs.

Thanks.

~DR0ID



Kamilche schrieb:
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()


import pygame, math, Numeric, random

WIDTH   = 800
HEIGHT  = 600
CELLSIZE = 50
CHAOS = 10


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, orig):
        self.pic = pygame.Surface([WIDTH, HEIGHT], pygame.SRCALPHA, 32).convert_alpha()
        self.quads = []
        self.orig = orig

    def Add(self, quads):
        self.quads.append(quads)

    def Texture(self, texture):
        quad = None
        w, h = self.pic.get_size()
        myarray = pygame.surfarray.pixels3d(self.pic)
        myalpha = pygame.surfarray.pixels_alpha(self.pic)
        texture = pygame.Surface((CELLSIZE, CELLSIZE), pygame.SRCALPHA).convert_alpha()
        tw, th = texture.get_size()
        for quad in self.quads:
            texture = pygame.Surface((CELLSIZE, CELLSIZE), pygame.SRCALPHA).convert_alpha()
            texture.blit(self.orig, (0,0), pygame.Rect(quad.coord, (CELLSIZE, CELLSIZE)))
##            self.pic.blit(texture, quad.coord)
            array = pygame.surfarray.pixels3d(texture)
            alpha = pygame.surfarray.pixels_alpha(texture)
            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:
                print ">>>>>>>>quad.pointToOffset:", pos, quad.minx, quad.maxx, quad.miny, quad.maxy
                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, coord):
        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
        self.coord = coord
        self.initok = False
        print self.polys
        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):
            print "quad.pointToOffset:", x, y, self.minx, self.maxx, self.miny, self.maxy
            return None
        if self.initok:
            print ">>>>>>>>>>>>>quad.pointToOffset:", x, y, self.polys

        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:
                fuk = float(Cy + Ey * t)
                if fuk:
                    s = (Dy - Ay * t) / fuk
                else:
                    s=100
                
            if self.initok:
                print "======>s,t",s,t, self.minx, self.maxx, self.miny, self.maxy
            if (t >= 0) and (t <= 1) and  (s >= 0) and (s <= 1):
                return s, t

def LoadPic(filename = 'small.png'):
    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 = pygame.transform.scale(LoadPic(), (WIDTH, HEIGHT))
    
    mesh = Mesh(pic)
    
    points = {}
    numy = HEIGHT/CELLSIZE
    numx = WIDTH/CELLSIZE
    print "numx, numy", numx, numy
    for y in range(numy+1):
        for x in range(numx+1):
            offsetx = 0
            offsety = 0
            if x>0 and x<numx and y>0 and y<numy:
                print "random x,y:", x,y
                offsetx = random.randint(-CHAOS, CHAOS)
                offsety = random.randint(-CHAOS, CHAOS)
            points[(x, y)] = (x*CELLSIZE+offsetx,y*CELLSIZE+offsety)
    for coord in points.keys():
        x,y = coord
        if x<numx and y<numy:
##            mesh.Add(Quad(points[(x,y)],points[(x, y+1)],points[(x+1, y+1)],points[(x+1, y)], (x*CELLSIZE, y*CELLSIZE)))
            mesh.Add(Quad(points[(x,y)],points[(x, y+1)],points[(x+1, y+1)],points[(x+1, y)], (x*CELLSIZE, y*CELLSIZE)))
    mesh.Texture(pic)
    for quad in mesh.quads:
        quad.initok = True
    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)
                    print offset, e.pos
                    mesh.OffsetToPoint(offset)
    pygame.quit()


if __name__ == '__main__':
    main()