rendered paste bodyfrom OpenGL.GL import *from cPickle import dump, loadimport libfovimport pygame#import hotshotimport randomimport sysimport osfrom math import sqrtdef loadImage(image): textureSurface = pygame.image.load(image) colorkey = textureSurface.get_at((0,0)) textureSurface.set_colorkey(colorkey, pygame.RLEACCEL) textureData = pygame.image.tostring(textureSurface, "RGBA") width = textureSurface.get_width() height = textureSurface.get_height() texture = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, texture) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData) return texture, width, heightdef line((x0,y0), (x1,y1)): steep = abs(y1-y0) > abs(x1-x0) if steep: x0, y0 = y0, x0 x1, y1 = y1, x1 if x0 > x1: x0, x1 = x1, x0 y0, y1 = y1, y0 dx = x1 - x0 dy = abs(y1 - y0) er = -dx/2 ystep = 0 y = y0 if y0 < y1: ystep = 1 else: ystep = -1 for x in xrange(x0,x1): if steep: yield (y,x) else: yield (x,y) er += dy if er > 0: y += ystep if steep: yield (y,x) else: yield (x,y) er -= dxclass memoize(object): """Decorator that caches a function's return value each time it is called. If called later with the same arguments, the cached value is returned, and not re-evaluated. Slow for mutable types.""" def __init__(self, func): self.func = func self._cache = {} def __call__(self, *args, **kwds): key = args if kwds: items = kwds.items() items.sort() key = key + tuple(items) if key in self._cache: return self._cache[key] self._cache[key] = result = self.func(*args, **kwds) return resultdef dist2((x0,y0), (x1,y1)): dx = x1-x0 dy = y1-y0 return dx*dx + dy*dy@memoizedef dist(p0,p1): return sqrt(dist2(p0,p1))class Font: def __init__(self, filename, fontspec=(10,12)): self.font, self.w, self.h = loadImage(filename) self.glyphw = fontspec[0] self.glyphh = fontspec[1] self.xchars = self.w / self.glyphw self.ychars = self.h / self.glyphh self.dls = {} def drawc(self, c, pos=None): if pos is not None: x,y = pos glTranslatef(x*self.glyphw, y*self.glyphh, 0) if c in self.dls: glCallList(self.dls[c]) else: glCallList(self.build_dl(c)) def translate(self, x,y,z=0): glTranslatef(x*self.glyphw, y*self.glyphh, z) def build_dl(self, c): y,x = divmod(c, self.xchars) y *= float(self.glyphh) x *= float(self.glyphw) w = float(self.w) h = float(self.h) l = x/w r = l+self.glyphw/w t = y/h b = t+self.glyphh/h ls = glGenLists(1) glNewList(ls, GL_COMPILE) glBegin(GL_QUADS) glTexCoord2f(l,t); glVertex2f(0,0) glTexCoord2f(r,t); glVertex2f(self.glyphw,0) glTexCoord2f(r,b); glVertex2f(self.glyphw,self.glyphh) glTexCoord2f(l,b); glVertex2f(0,self.glyphh) glEnd() glEndList() self.dls[c] = ls return ls def puts(self, str): glBindTexture(GL_TEXTURE_2D, self.font) for c in str: self.drawc(ord(c)) glTranslatef(self.glyphw,0,0)FACE_L=0FACE_R=1FACE_T=2FACE_B=3CORNER_TL=4CORNER_BL=5CORNER_TR=6CORNER_BR=7TREE=0GROUND=1class Cell: def __init__(self): self.type = GROUND self.seen = (0,0,0) self.visible = False self.clear_light() def clear_light(self): self.lit = [(0,0,0)]*8 self.mid_lit = (0,0,0) #self.clear_visited() def clear_visited(self): self.visited = 0 def add_light(self, light, (d1,d2)): if d1 is None: self.mid_lit = tuple(map(max, zip(light, self.mid_lit))) elif d2 is None: self.lit[d1] = tuple(map(max, zip(light, self.lit[d1]))) else: l1 = map((lambda a: a/2), light) self.lit[d1] = tuple([min(1.0,a+b) for a,b in zip(self.lit[d1], l1)]) self.lit[d2] = tuple([min(1.0,a+b) for a,b in zip(self.lit[d2], l1)])class Map: def __init__(self, font, width=64, height=40): self.font = isinstance(font, str) and Font(font) or font self.__cells = {} self.width, self.height = width, height def __getitem__(self, (x,y)): if (x,y) in self.__cells: return self.__cells[x,y] else: self.__cells[x,y] = Cell() return self.__cells[x,y] def __contains__(self, (x,y)): return x >= 0 and x < self.width and y >= 0 and y < self.height def cells(self): return self.__cells.iteritems() def cansee(self, p0, p1): for x,y in line(p0,p1): if self[x,y].type is TREE: return False return True def save(self, filename): out = open(filename, 'wb') dump(self.__cells, out, 2) out.close() def load(self, filename): inf = open(filename, 'rb') self.__cells = load(inf) inf.close()def direction((sx,sy),(dx,dy)): """Returns a (dir1,dir2) pair containing the faces of dest(dx,dy) lit from a source at (sx,sy)""" if sx < dx: if sy < dy: return (FACE_L, FACE_T) if sy > dy: return (FACE_L, FACE_B) return (FACE_L, None) if sx > dx: if sy < dy: return (FACE_R, FACE_T) if sy > dy: return (FACE_R, FACE_B) return (FACE_R, None) if sy < dy: return (FACE_T, None) if sy > dy: return (FACE_B, None) return (None, None)class circle: def __init__(self, size): self.vals = [0] * size self._ptr = 0 def add(self, val): self.vals[self._ptr] = val self._ptr += 1 if self._ptr >= len(self.vals): self._ptr = 0 def set(self, val): self.vals[self._ptr] = valdef blend(t0,t1,a): """Skew tuple t0 towards tuple t1 with a bias (zero is towards t0) of a""" fin = [] for v0,v1 in zip(t0,t1): fin.append(v0+(v1-v0)*a) return tuple(fin)def main(): random.seed() pygame.init() pygame.display.set_mode((640,480), pygame.OPENGL|pygame.DOUBLEBUF) font = Font("curses_800x600.bmp") board = Map(font, 64, 39) fx, fy = -1,-1 px, py = board.width/2, board.height/2 if 0:#os.path.exists('save.pkl'): board.load('save.pkl') for _,c in board.cells(): c.clear_light() else:# for y in xrange(board.height):# for x in xrange(board.width):# c = board[x,y]# c.type = GROUND# c.char = ord(random.choice(["'",'.',',','`']))# c.color = (random.uniform(0,0.3), random.uniform(0.2,1), 0.1)## mapt = """w*.*...*#**......#...*....#...*....#**.*....#.....***#........#.......@#"""# tx = 0# ty = 0# for tile in mapt:# c = board[tx,ty]# if tile == "\n":# ty += 1# tx = 0# continue# if tile == '.':# tx += 1# continue# if tile == '*':# c.type = TREE# c.char = random.choice([ord('*'), 5])# tx += 1# continue# if tile == 'w':# fx, fy = tx, ty# tx += 1# continue# if tile == '@':# px, py = tx, ty# tx += 1# continue #fx, fy = 17,17 for y in xrange(board.height): for x in xrange(board.width): if random.randint(0,3) <= 1: board[x,y].char = ord('*') else: board[x,y].char = 5 board[x,y].type = TREE # now walk out a cave wx, wy = px, py for _ in xrange(1000): if fx < 0 and random.random() < 0.005: fx, fy = wx, wy c = board[wx,wy] c.type = GROUND c.color = (random.uniform(0,0.3), random.uniform(0.1,0.7), 0) r = random.randint(0,3) if r == 0: c.char = ord(',') elif r == 1: c.char = ord('.') elif r == 2: c.char = ord("'") elif r == 3: c.char = ord('`') d = random.randint(0,3) if d == 0: wx += 1 elif d == 1: wx -= 1 elif d == 2: wy += 1 elif d == 3: wy -= 1 if wx >= board.width: wx = board.width-1 elif wx < 0: wx = 0 if wy >= board.height: wy = board.height-1 elif wy < 0: wy = 0 def opacity_test(self, x, y): if (x,y) not in board: return 1 return (board[x,y].type is TREE or (x,y) == (px,py)) and 1 or 0 def apply_light(self, x, y, dx, dy, src): if (x,y) in board: c = board[x,y] #if c.visited: return #c.visited = 1 sx,sy,rad, color = src opaque = opacity_test(self, x, y) if not c.visible: return 1 # don't need to bother with lighting if it's not visible #intensity = min(1.0,(rad/3.0)/(1 + dist2((sx,sy), (x,y)))) pct = 2.0 / (float(dist2((sx,sy),(x,y))) / float(rad*rad) + 1) - 1 intensity = max(0,min(1.0, 1.0*pct)) color = [min(1.0,a*intensity) for a in color] if opaque: dir = direction((sx, sy), (x, y)) if dir[1] is not None: if dir == (FACE_L, FACE_T): opl, opt = opacity_test(self, x-1, y), opacity_test(self, x, y-1) if opl and opt: dir = (CORNER_TL, None) elif opl: dir = (FACE_T, None) elif opt: dir = (FACE_L, None) elif dir == (FACE_R, FACE_T): opr, opt = opacity_test(self, x+1, y), opacity_test(self, x, y-1) if opr and opt: dir = (CORNER_TR, None) elif opr: dir = (FACE_T, None) elif opt: dir = (FACE_R, None) elif dir == (FACE_L, FACE_B): opl, opb = opacity_test(self, x-1, y), opacity_test(self, x, y+1) if opl and opb: dir = (CORNER_BL, None) elif opl: dir = (FACE_B, None) elif opb: dir = (FACE_L, None) elif dir == (FACE_R, FACE_B): opr, opb = opacity_test(self, x+1, y), opacity_test(self, x, y+1) if opr and opb: dir = (CORNER_BR, None) elif opr: dir = (FACE_B, None) elif opb: dir = (FACE_R, None) else: dir = (None,None) c.add_light(color, dir) return opaque and 1 or 0 return 1 def apply_sight(self, x, y, dx, dy, src): if (x,y) in board: c = board[x,y] sx, sy, rad = src c.visible = 2.0 / (float(dx*dx+dy*dy) / float(rad*rad) + 1) - 1 #return (c.type == TREE) and 1 or 0 return 1 fov = libfov.Settings() fov.set_shape(0) fov.set_opacity_test_function(opacity_test) fov.set_apply_lighting_function(apply_light) los = libfov.Settings() los.set_shape(0) los.set_opacity_test_function(opacity_test) los.set_apply_lighting_function(apply_sight) glMatrixMode(GL_PROJECTION) glEnable(GL_TEXTURE_2D) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glEnable(GL_BLEND) glLoadIdentity() glOrtho(0, 640, 480, 0, -1, 1) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glDisable(GL_DEPTH_TEST) def randoff(x): r = random.random() if r >= 1.0-x: return 1 if r < x: return -1 return 0 TORCH='TORCH' ELECTRIC='ELECTRIC' sourcetype = TORCH torchdown = False torchx, torchy = 0,0 moves = circle(3) clock = pygame.time.Clock() while 1: clock.tick(10) glClear(GL_COLOR_BUFFER_BIT) if torchdown: lcx, lcy = torchx, torchy else: lcx, lcy = px,py if sourcetype is TORCH: rad = 8+randoff(0.1)*0.5 if not torchdown: rad -= sum(moves.vals) lcolor = (1,0.6,0.2) elif sourcetype is ELECTRIC: rad = 15 lcolor = (1,1,1) los.fov_circle((px,py,40), px, py, 40) fov.fov_circle((lcx,lcy,rad, lcolor), lcx, lcy, int(rad)) #for y in xrange(board.height): # for x in xrange(board.width): # board[x,y].clear_visited() frad = 15+int(round(random.gauss(0,0.5))) fov.fov_circle((fx,fy,frad, (1,0.7,0.6)), fx, fy, frad) #board[lcx, lcy].lit = 1 for (x,y),c in board.cells(): if c.visible: if opacity_test(None, x, y): d1, d2 = dir = direction((px,py), (x,y)) color = [min(1.0,a+b) for a,b in zip(c.lit[d1], (d2 is None) and (0,0,0) or c.lit[d2])] if dir == (FACE_L, FACE_T): opl, opt = opacity_test(None, x-1, y), opacity_test(None, x, y-1) if opl and opt: color = c.lit[CORNER_TL] elif dir == (FACE_R, FACE_T): opr, opt = opacity_test(None, x+1, y), opacity_test(None, x, y-1) if opr and opt: color = c.lit[CORNER_TR] elif dir == (FACE_L, FACE_B): opl, opb = opacity_test(None, x-1, y), opacity_test(None, x, y+1) if opl and opb: color = c.lit[CORNER_BL] elif dir == (FACE_R, FACE_B): opr, opb = opacity_test(None, x+1, y), opacity_test(None, x, y+1) if opr and opb: color = c.lit[CORNER_BR] else: color = c.mid_lit color = [a*c.visible for a in color] c.seen = tuple(map(max, zip(color, c.seen))) else: color = (0,0,0) if c.seen != (0,0,0): glLoadIdentity() board.font.translate(x,y) if (x,y) == (fx,fy) and c.visible: glColor3f(1*c.visible,0.5*c.visible,0) board.font.drawc(ord('*')) elif torchdown and (x,y) == (torchx, torchy) and c.visible: glColor3f(0.9*c.visible,0.4*c.visible,0) board.font.drawc(ord('$')) elif c.type is TREE: color = [max(seen*0.1, vis)*col for seen,vis,col in zip(c.seen, color, (0.4,1.0,0.2))] glColor3f(*color) board.font.drawc(c.char) elif c.type is GROUND: color = [max(seen*0.1, vis)*col for seen,vis,col in zip(c.seen, color, c.color)] glColor3f(*color) board.font.drawc(c.char) """if c.visible: if opacity_test(None, x, y): d1, d2 = direction((px, py), (x, y)) color = [min(1.0,a+b) for a,b in zip(c.lit[d1], (d2 is None) and c.mid_lit or c.lit[d2])] else: color = c.mid_lit else: color = c.seen if c.seen != (0,0,0): glLoadIdentity() glTranslatef(x*board.font.glyphw, y*board.font.glyphh, 0) # XXX: think of a better way of doing this if (x,y) == (fx,fy) and c.visible: glColor3f(1,0.5,0) board.font.drawc(ord('*')) elif c.type is TREE: #tcolor = (0.4,0.9,0.1) # a light produces so many 'waves' of each color R,G,B. # if the light produces 1.0 red, and the object reflects 90% of the red waves it receives, the final color is 0.9. # thus, final color = light color * object color #color = map((lambda x,y: x*y), tcolor, lcolor) #color = blend((c.seen*0.15*tcolor[0], c.seen*0.15*tcolor[1], c.seen*0.15*tcolor[2]), color, c.lit) color = [max(a*b,x) for a,b,x in zip(color, (0.4,0.9,0.1), c.seen)] glColor3f(*color) board.font.drawc(c.char) elif c.type is GROUND: #tcolor = c.color #color = map((lambda x,y: x*y), list(tcolor), list(lcolor)) #color = blend((c.seen*0.15*c.color[0], c.seen*0.15*c.color[1], c.seen*0.15*c.color[2]), color, c.lit) #color = blend(color, lcolor, c.lit/4.0) color = [max(a*b,x) for a,b,x in zip(color, c.color, c.seen)] glColor3f(*color) board.font.drawc(c.char)""" glLoadIdentity() glTranslatef(px*board.font.glyphw, py*board.font.glyphh, 0) glColor3f(1,1,1) board.font.drawc(ord('@')) pygame.display.flip() moved = 0 def player_move(dx,dy): if board[px+dx,py+dy].type is not TREE and (px+dx,py+dy) in board: moved = 1 px += dx py += dy for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit(0) if event.type == pygame.KEYDOWN: if event.key == pygame.K_DOWN or event.key == pygame.K_t: player_move(0,1) elif event.key == pygame.K_UP or event.key == pygame.K_n: player_move(0,-1) elif event.key == pygame.K_LEFT or event.key == pygame.K_h: player_move(-1,0) elif event.key == pygame.K_RIGHT or event.key == pygame.K_s: player_move(1,0) elif event.key == pygame.K_g: player_move(-1,-1) elif event.key == pygame.K_c: player_move(1,-1) elif event.key == pygame.K_b: player_move(-1,1) elif event.key == pygame.K_m: player_move(1,1) elif event.key == pygame.K_SPACE: if torchdown: torchdown = False else: torchx, torchy = px,py torchdown = True elif event.key == pygame.K_v: board.save('save.pkl') elif event.key == pygame.K_l: if sourcetype is TORCH: sourcetype = ELECTRIC elif sourcetype is ELECTRIC: sourcetype = TORCH for y in xrange(board.height): for x in xrange(board.width): board[x,y].clear_light() board[x,y].visible = False moves.add(moved)if __name__ == "__main__": #prof = hotshot.Profile("prof.log", 1) #prof.runcall(main) #prof.close() main()