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

Re: [pygame] Perspective Test



Awesome code Kamilche. I really like it. I'm going to put it in my favorites folder :)

/J


On Sat, Mar 8, 2008 at 5:51 AM, Kamilche <kamilche@xxxxxxxxxxxx> wrote:
Here's a perspective test I wrote, that I thought others might find
enjoyable. It illustrates a single-point perspective (a 'vanishing
point'), and shows how a room with a floor, ceiling, door, and avatar
changes as the vanishing point changes.


import pygame, os, sys, urllib

SCREENSIZE          = (1024, 768)
BACKCOLOR           = (150, 150, 150)
INVISIBLE           = (  0,   0,   0,   0)
PERSPECTIVECOLOR    = (  0,   0,   0, 128)
PERSPECTIVEWIDTH    = 2
WALLCOLOR           = (255, 128,   0, 220)
WINDOWCOLOR         = (  0,  64, 200, 100)
DOORCOLOR           = (100,  64,  50, 200)
CEILINGCOLOR        = (255, 255, 255, 255)
FLOORCOLOR          = (121,  74,  81, 255)
HORIZONCOLOR        = (  0, 128,   0, 200)
VPCOLOR             = (255,   0,   0, 255)
WALLDEPTH           = .35

VANISHINGPOINT      = (SCREENSIZE[0]/2, SCREENSIZE[1]/2)

bg = None
temp = None
girl = None

def CalculatePoint(depth, point):
    xa, ya = VANISHINGPOINT
    xb, yb = point
    xbb = xa + depth * (xb-xa)
    ybb = ya + depth * (yb-ya)
    return int(xbb), int(ybb)

def Intersection(a,b,c,d):
    Ax,Ay = a; Bx,By = b; Cx,Cy = c; Dx,Dy = d
    u = float((Dx-Cx)*(Ay-Cy)-(Dy-Cy)*(Ax-Cx)) /
float((Dy-Cy)*(Bx-Ax)-(Dx-Cx)*(By-Ay))
    x = Ax + u*(Bx-Ax)
    y = Ay + u*(By-Ay)
    return int(x),int(y)

def DrawWall():
    w, h = SCREENSIZE
    topleft = CalculatePoint(WALLDEPTH, (0, 0))
    topright = CalculatePoint(WALLDEPTH, (w, 0))
    bottomleft = CalculatePoint(WALLDEPTH, (0, h))
    bottomright = CalculatePoint(WALLDEPTH, (w, h))
    pos = topleft
    wallwidth = int(topright[0]-topleft[0])
    wallheight = int(bottomleft[1]-topleft[1])
    temp.fill(WALLCOLOR)
    bg.blit(temp, topleft, [0, 0, wallwidth, wallheight])
    pygame.draw.lines(bg, PERSPECTIVECOLOR, 1, [topleft, topright,
bottomright, bottomleft], PERSPECTIVEWIDTH)

def DrawOrthogonals():
    pygame.draw.line(bg, PERSPECTIVECOLOR, (0, 0), VANISHINGPOINT,
PERSPECTIVEWIDTH)
    pygame.draw.line(bg, PERSPECTIVECOLOR, (SCREENSIZE[0], 0),
VANISHINGPOINT, PERSPECTIVEWIDTH)
    pygame.draw.line(bg, PERSPECTIVECOLOR, (0, SCREENSIZE[1]),
VANISHINGPOINT, PERSPECTIVEWIDTH)
    pygame.draw.line(bg, PERSPECTIVECOLOR, SCREENSIZE, VANISHINGPOINT,
PERSPECTIVEWIDTH)
    pygame.draw.line(bg, HORIZONCOLOR, (0, VANISHINGPOINT[1]),
(SCREENSIZE[0], VANISHINGPOINT[1]), PERSPECTIVEWIDTH)

def DrawDoor():
    w, h = SCREENSIZE
    topleft = CalculatePoint(.9, (0, .25*h))
    topright = CalculatePoint(.7, (0, .25*h))
    bottomleft = CalculatePoint(.9, (0, h))
    bottomright = CalculatePoint(.7, (0, h))
    pos = topleft
    windowwidth = int(topright[0]-topleft[0])
    windowheight = int(bottomleft[1]-topleft[1])
    lst = [topleft, topright, bottomright, bottomleft, topleft]
    temp.fill(INVISIBLE)
    pygame.draw.polygon(temp, DOORCOLOR, lst)
    bg.blit(temp, [0, 0])
    pygame.draw.circle(bg, DOORCOLOR, topleft, 5)
    pygame.draw.circle(bg, DOORCOLOR, topright, 5)
    pygame.draw.circle(bg, DOORCOLOR, bottomright, 5)
    pygame.draw.circle(bg, DOORCOLOR, bottomleft, 5)

def DrawCeiling():
    w, h = SCREENSIZE
    vx, vy = VANISHINGPOINT
    numtiles = 8
    for i in range(0, SCREENSIZE[0]+1, SCREENSIZE[0]/numtiles):
        pygame.draw.line(bg, CEILINGCOLOR, (i, 0), VANISHINGPOINT, 1)

    # Calculate horizontal lines
    topright = CalculatePoint(WALLDEPTH, (w, 0))
    for i in range(0, SCREENSIZE[0]+1, SCREENSIZE[0]/numtiles):
        try:
            x, y = Intersection((0, 0), topright, (i, 0), VANISHINGPOINT)
            left = Intersection([0, y], [w, y], (0, 0), VANISHINGPOINT)
            right = Intersection([0, y], [w, y], (w, 0), VANISHINGPOINT)
            pygame.draw.line(bg, CEILINGCOLOR, left, right, 1)
        except:
            pass
    #pygame.draw.line(bg, CEILINGCOLOR, (0, 0), topright, 1)

def DrawFloor():
    w, h = SCREENSIZE
    factor = 4
    for i in range(-w*factor, w*2*factor, 100):
        pygame.draw.line(bg, FLOORCOLOR, (i, h), VANISHINGPOINT, 1)

def DrawGirl():
    w, h = SCREENSIZE
    data = "" (75, h)), (.9, (w/2+50, h)), (WALLDEPTH+.05, (150, h))]
    data.sort()
    for depth, dest in data:
        pt = CalculatePoint(depth, dest)
        resizedgirl = pygame.transform.rotozoom(girl, 0, depth)
        bg.blit(resizedgirl, [pt[0]-resizedgirl.get_width()/2,
pt[1]-resizedgirl.get_height()])
        pygame.draw.circle(bg, (0, 0, 255), pt, 5)

def Text(s, _font = []):
    if len(_font) == 0:
        font = pygame.font.Font(None, 24)
        _font.append(font)
    font = _font[0]
    shadow = font.render(s, 1, (0, 0, 0))
    color = font.render(s, 1, (255, 255, 0))
    w, h = color.get_size()
    pic = pygame.Surface((w, h), pygame.SRCALPHA, 32).convert_alpha()
    pic.fill(INVISIBLE)
    pic.blit(shadow, [1, 1])
    pic.blit(color, [0, 0])
    return pic

def Draw():
    bg.fill(BACKCOLOR)
    DrawCeiling()
    DrawFloor()
    DrawOrthogonals()
    DrawDoor()
    DrawWall()
    DrawGirl()
    pygame.draw.circle(bg, VPCOLOR, VANISHINGPOINT, 5)

def main():
    global bg, temp, girl, VANISHINGPOINT, WALLDEPTH
    pygame.init()
    pygame.key.set_repeat(500, 30)
    bg = pygame.display.set_mode(SCREENSIZE, 0, 32)
    temp = pygame.Surface(SCREENSIZE, pygame.SRCALPHA, 32).convert_alpha()
    filename = "posette.png"
    if os.path.exists(filename):
        girl = pygame.image.load(filename).convert_alpha()
    else:
        try:
            url = "" href="http://www.kamilche.org/webimages/posette.png" target="_blank">http://www.kamilche.org/webimages/posette.png"
            urllib.urlretrieve(url, filename)
            girl = pygame.image.load(filename).convert_alpha()
        except:
            girl = pygame.Surface((150, 300), pygame.SRCALPHA,
32).convert_alpha()
            girl.fill((255, 0, 0, 128))

    quit = 0
    info1 = Text("Click to move vanishing point, arrow keys to move wall.")
    caption = ""
    while not quit:
        Draw()
        info2 = Text(caption)
        bg.blit(info1, [5, 5])
        bg.blit(info2, [5, info1.get_height()+5])
        pygame.display.flip()
        pygame.event.pump()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit = 1
                break
            elif (event.type == pygame.MOUSEBUTTONDOWN and event.button
== 1) or (event.type == pygame.MOUSEMOTION and event.buttons[0] == 1):
                # Move vanishing point
                VANISHINGPOINT = event.pos
                caption = 'Vanishing point = %s' % str(VANISHINGPOINT)
            elif event.type == pygame.KEYDOWN:
                # Move back wall
                if event.key in [pygame.K_LEFT, pygame.K_UP]:
                    WALLDEPTH = max(0.01, WALLDEPTH - .05)
                elif event.key in [pygame.K_RIGHT, pygame.K_DOWN]:
                    WALLDEPTH = min(1.0, WALLDEPTH + .05)

    pygame.quit()

main()