Punyverse 0.3: adding Python 3 support.

This commit is contained in:
Quantum 2018-08-22 04:18:29 -04:00
parent bb928b6c55
commit b4dce48fa7
11 changed files with 164 additions and 151 deletions

View file

@ -8,7 +8,7 @@ Python simulator of a puny universe. (How many words can I stick into one?)
Installation Installation
------------ ------------
Currently, only Python 2 on Windows is supported. Currently, only Windows is supported.
To install, run `pip install punyverse`. To install, run `pip install punyverse`.

View file

@ -36,9 +36,9 @@ def main():
raise SystemExit('Graphics configuration not supported.') raise SystemExit('Graphics configuration not supported.')
else: else:
if hasattr(config, '_attribute_names'): if hasattr(config, '_attribute_names'):
print 'OpenGL configuration:' print('OpenGL configuration:')
for key in config._attribute_names: for key in config._attribute_names:
print ' %-17s %s' % (key + ':', getattr(config, key)) print(' %-17s %s' % (key + ':', getattr(config, key)))
world_options = { world_options = {
'normal': args.normal, 'normal': args.normal,

View file

@ -41,11 +41,11 @@ cdef class Face(object):
self.textures = textures self.textures = textures
cdef class Material(object): cdef class Material(object):
cdef public str name, texture cdef public unicode name, texture
cdef public tuple Ka, Kd, Ks cdef public tuple Ka, Kd, Ks
cdef public double shininess cdef public double shininess
def __init__(self, str name, str texture=None, tuple Ka=(0, 0, 0), def __init__(self, unicode name, unicode texture=None, tuple Ka=(0, 0, 0),
tuple Kd=(0, 0, 0), tuple Ks=(0, 0, 0), double shininess=0.0): tuple Kd=(0, 0, 0), tuple Ks=(0, 0, 0), double shininess=0.0):
self.name = name self.name = name
self.texture = texture self.texture = texture
@ -55,15 +55,15 @@ cdef class Material(object):
self.shininess = shininess self.shininess = shininess
cdef class Group(object): cdef class Group(object):
cdef public str name cdef public unicode name
cdef public tuple min cdef public tuple min
cdef public Material material cdef public Material material
cdef public list faces, indices, vertices, normals, textures cdef public list faces, indices, vertices, normals, textures
cdef public int idx_count cdef public int idx_count
def __init__(self, str name=None): def __init__(self, unicode name=None):
if name is None: if name is None:
self.name = str(uuid4()) self.name = unicode(uuid4())
else: else:
self.name = name self.name = name
self.min = () self.min = ()
@ -103,8 +103,9 @@ cdef class WavefrontObject(object):
self.perform_io(self.path) self.perform_io(self.path)
cdef void new_material(self, list words): cdef void new_material(self, list words):
material = Material(words[1]) name = words[1].decode('utf-8')
self.materials[words[1]] = material material = Material(name)
self.materials[name] = material
self.current_material = material self.current_material = material
cdef void Ka(self, list words): cdef void Ka(self, list words):
@ -120,7 +121,7 @@ cdef class WavefrontObject(object):
self.current_material.shininess = min(float(words[1]), 125) self.current_material.shininess = min(float(words[1]), 125)
cdef void material_texture(self, list words): cdef void material_texture(self, list words):
self.current_material.texture = words[-1] self.current_material.texture = words[-1].decode('utf-8')
@cython.nonecheck(False) @cython.nonecheck(False)
cdef void vertex(self, list words): cdef void vertex(self, list words):
@ -157,7 +158,7 @@ cdef class WavefrontObject(object):
cdef list raw_faces, vindices = [], nindices = [], tindices = [] cdef list raw_faces, vindices = [], nindices = [], tindices = []
for i in xrange(1, vertex_count + 1): for i in xrange(1, vertex_count + 1):
raw_faces = words[i].split('/') raw_faces = words[i].split(b'/')
l = len(raw_faces) l = len(raw_faces)
current_value = int(raw_faces[0]) current_value = int(raw_faces[0])
@ -193,10 +194,10 @@ cdef class WavefrontObject(object):
group.faces.append(Face(type, vindices, nindices, tindices, face_vertices, face_normals, face_textures)) group.faces.append(Face(type, vindices, nindices, tindices, face_vertices, face_normals, face_textures))
cdef bint material(self, list words) except False: cdef bint material(self, list words) except False:
return self.perform_io(os.path.join(self.root, words[1])) return self.perform_io(os.path.join(self.root, words[1].decode('utf-8')))
cdef void use_material(self, list words): cdef void use_material(self, list words):
mat = words[1] mat = words[1].decode('utf-8')
try: try:
self.current_group.material = self.materials[mat] self.current_group.material = self.materials[mat]
except KeyError: except KeyError:
@ -205,7 +206,7 @@ cdef class WavefrontObject(object):
print "Warning: no group" print "Warning: no group"
cdef void group(self, list words): cdef void group(self, list words):
name = words[1] name = words[1].decode('utf-8')
group = Group(name) group = Group(name)
if self.groups: if self.groups:
@ -219,10 +220,10 @@ cdef class WavefrontObject(object):
cdef int hash, length cdef int hash, length
ext = os.path.splitext(file)[1].lstrip('.') ext = os.path.splitext(file)[1].lstrip('.')
reader = openers.get(ext, open)(file) reader = openers.get(ext, lambda x: open(x, 'rb'))(file)
with reader: with reader:
for buf in reader: for buf in reader:
if not buf or buf.startswith(('\r', '\n', '#')): if not buf or buf.startswith((b'\r', b'\n', b'#')):
continue # Empty or comment continue # Empty or comment
words = buf.split() words = buf.split()
type = words[0] type = words[0]
@ -267,10 +268,6 @@ model_base = None
def load_model(path): def load_model(path):
global model_base global model_base
if model_base is None: if model_base is None:
import sys
if hasattr(sys, 'frozen'):
model_base = os.path.dirname(sys.executable)
else:
model_base = os.path.join(os.path.dirname(__file__), 'assets', 'models') model_base = os.path.join(os.path.dirname(__file__), 'assets', 'models')
if not os.path.isabs(path): if not os.path.isabs(path):
path = os.path.join(model_base, path) path = os.path.join(model_base, path)

View file

@ -1,8 +1,10 @@
from math import sqrt from math import sqrt
from punyverse.orbit import KeplerOrbit from six.moves import range
from pyglet.gl import * from pyglet.gl import *
from punyverse.orbit import KeplerOrbit
class Entity(object): class Entity(object):
def __init__(self, id, location, rotation=(0, 0, 0), direction=(0, 0, 0), background=False): def __init__(self, id, location, rotation=(0, 0, 0), direction=(0, 0, 0), background=False):
@ -118,7 +120,7 @@ class Satellite(Body):
id = glGenLists(1) id = glGenLists(1)
glNewList(id, GL_COMPILE) glNewList(id, GL_COMPILE)
glBegin(GL_LINE_LOOP) glBegin(GL_LINE_LOOP)
for theta in xrange(360): for theta in range(360):
x, z, y = self.orbit.orbit(theta) x, z, y = self.orbit.orbit(theta)
glVertex3f(x, y, z) glVertex3f(x, y, z)
glEnd() glEnd()

View file

@ -2,11 +2,12 @@
from operator import attrgetter from operator import attrgetter
from math import hypot, sqrt, atan2, degrees from math import hypot, sqrt, atan2, degrees
from time import clock from time import clock
from itertools import izip_longest
import time import time
import random import random
import os import os
import six
from punyverse.camera import Camera from punyverse.camera import Camera
from punyverse.world import World from punyverse.world import World
from punyverse.glgeom import * from punyverse.glgeom import *
@ -18,6 +19,11 @@ try:
except ImportError: except ImportError:
from punyverse.model import model_list, load_model from punyverse.model import model_list, load_model
try:
from itertools import zip_longest
except ImportError:
from itertools import izip_longest as zip_longest
from pyglet.gl import * from pyglet.gl import *
from pyglet.window import key, mouse from pyglet.window import key, mouse
@ -50,7 +56,7 @@ class Applet(pyglet.window.Window):
info = [' %-22s %s' % (key + ':', getattr(self.config, key)) info = [' %-22s %s' % (key + ':', getattr(self.config, key))
for key in self.config._attribute_names] for key in self.config._attribute_names]
info = ['%-30s %-30s' % group for group in info = ['%-30s %-30s' % group for group in
izip_longest(info[::2], info[1::2], fillvalue='')] zip_longest(info[::2], info[1::2], fillvalue='')]
info = 'OpenGL configuration:\n' + '\n'.join(info) info = 'OpenGL configuration:\n' + '\n'.join(info)
else: else:
info = 'Unknown OpenGL configuration' info = 'Unknown OpenGL configuration'
@ -89,7 +95,7 @@ class Applet(pyglet.window.Window):
self.fps = 0 self.fps = 0
self.world = World('world.json', callback, self.world_options) self.world = World('world.json', callback, self.world_options)
phase = 'Initializing game...' phase = 'Initializing game...'
print phase print(phase)
callback(phase, '', 0) callback(phase, '', 0)
self.speed = INITIAL_SPEED self.speed = INITIAL_SPEED
self.keys = set() self.keys = set()
@ -158,7 +164,6 @@ class Applet(pyglet.window.Window):
key.C: attribute_toggler(self, 'cloud'), key.C: attribute_toggler(self, 'cloud'),
key.X: attribute_toggler(self, 'atmosphere'), key.X: attribute_toggler(self, 'atmosphere'),
key.ENTER: attribute_toggler(self, 'running'), key.ENTER: attribute_toggler(self, 'running'),
#key.Q: self.screenshot,
key.INSERT: increment_tick, key.INSERT: increment_tick,
key.DELETE: decrement_tick, key.DELETE: decrement_tick,
key.SPACE: self.launch_meteor, key.SPACE: self.launch_meteor,
@ -203,7 +208,7 @@ class Applet(pyglet.window.Window):
glLightfv(GL_LIGHT1, GL_SPECULAR, fv4(1, 1, 1, 1)) glLightfv(GL_LIGHT1, GL_SPECULAR, fv4(1, 1, 1, 1))
phase = 'Loading asteroids...' phase = 'Loading asteroids...'
print phase print(phase)
def load_asteroids(files): def load_asteroids(files):
for id, file in enumerate(files): for id, file in enumerate(files):
@ -217,12 +222,12 @@ class Applet(pyglet.window.Window):
c.pitch, c.yaw, c.roll = self.world.direction c.pitch, c.yaw, c.roll = self.world.direction
phase = 'Updating entities...' phase = 'Updating entities...'
print phase print(phase)
callback(phase, '', 0) callback(phase, '', 0)
for entity in self.world.tracker: for entity in self.world.tracker:
entity.update() entity.update()
print 'Loaded in %s seconds.' % (clock() - start) print('Loaded in %s seconds.' % (clock() - start))
self.loaded = True self.loaded = True
pyglet.clock.schedule(self.update) pyglet.clock.schedule(self.update)
self.on_resize(self.width, self.height) # On resize handler does nothing unless it's loaded self.on_resize(self.width, self.height) # On resize handler does nothing unless it's loaded
@ -235,13 +240,13 @@ class Applet(pyglet.window.Window):
import tempfile import tempfile
CF_BITMAP = 2 CF_BITMAP = 2
image = Image.fromstring(image.format, (image.width, image.height), image.get_image_data().data) image = Image.frombytes(image.format, (image.width, image.height), image.get_image_data().data)
image = image.convert('RGB').transpose(Image.FLIP_TOP_BOTTOM) image = image.convert('RGB').transpose(Image.FLIP_TOP_BOTTOM)
fd, filename = tempfile.mkstemp('.bmp') fd, filename = tempfile.mkstemp('.bmp')
try: try:
with os.fdopen(fd, 'w') as file: with os.fdopen(fd, 'wb') as file:
image.save(file, 'BMP') image.save(file, 'BMP')
if not isinstance(filename, unicode): if isinstance(filename, six.binary_type):
filename = filename.decode('mbcs') filename = filename.decode('mbcs')
image = windll.user32.LoadImageW(None, filename, 0, 0, 0, 0x10) image = windll.user32.LoadImageW(None, filename, 0, 0, 0, 0x10)
windll.user32.OpenClipboard(self._hwnd) windll.user32.OpenClipboard(self._hwnd)

View file

@ -1,6 +1,8 @@
from math import * from math import *
from pyglet.gl import *
from random import random, gauss, choice from random import random, gauss, choice
from six.moves import range
from pyglet.gl import *
from pyglet.gl.gl_info import have_extension from pyglet.gl.gl_info import have_extension
TWOPI = pi * 2 TWOPI = pi * 2
@ -68,7 +70,8 @@ def frustrum():
glEnable(GL_DEPTH_TEST) glEnable(GL_DEPTH_TEST)
def crosshair(size, (cx, cy)): def crosshair(size, coords):
cx, cy = coords
with glSection(GL_LINES): with glSection(GL_LINES):
glVertex2f(cx - size, cy) glVertex2f(cx - size, cy)
glVertex2f(cx + size, cy) glVertex2f(cx + size, cy)
@ -76,9 +79,10 @@ def crosshair(size, (cx, cy)):
glVertex2f(cx, cy + size) glVertex2f(cx, cy + size)
def circle(r, seg, (cx, cy)): def circle(r, seg, coords):
cx, cy = coords
with glSection(GL_LINE_LOOP): with glSection(GL_LINE_LOOP):
for i in xrange(seg): for i in range(seg):
theta = TWOPI * i / seg theta = TWOPI * i / seg
glVertex2f(cx + cos(theta) * r, cy + sin(theta) * r) glVertex2f(cx + cos(theta) * r, cy + sin(theta) * r)
@ -95,7 +99,7 @@ def disk(rinner, router, segs, tex):
with glSection(GL_TRIANGLE_STRIP): with glSection(GL_TRIANGLE_STRIP):
factor = TWOPI / res factor = TWOPI / res
theta = 0 theta = 0
for n in xrange(res + 1): for n in range(res + 1):
theta += factor theta += factor
x = cos(theta) x = cos(theta)
y = sin(theta) y = sin(theta)
@ -117,7 +121,7 @@ def flare(rinner, router, res, prob, tex):
factor = TWOPI / res factor = TWOPI / res
rdelta = (router - rinner) rdelta = (router - rinner)
with glSection(GL_QUADS): with glSection(GL_QUADS):
for i in xrange(res + 1): for i in range(res + 1):
theta = last_theta + factor theta = last_theta + factor
x = cos(theta) x = cos(theta)
y = sin(theta) y = sin(theta)
@ -192,7 +196,7 @@ def normal_sphere(r, divide, tex, normal, lighting=True, fv4=GLfloat * 4):
if (not have_extension('GL_ARB_multitexture') or not if (not have_extension('GL_ARB_multitexture') or not
have_extension('GL_ARB_texture_env_combine') or not have_extension('GL_ARB_texture_env_combine') or not
have_extension('GL_EXT_texture_env_dot3')): have_extension('GL_EXT_texture_env_dot3')):
print 'No hardware normal mapping support. No bumping for you.' print('No hardware normal mapping support. No bumping for you.')
return sphere(r, divide, divide, tex, lighting) return sphere(r, divide, divide, tex, lighting)
from texture import load_texture from texture import load_texture
@ -228,11 +232,11 @@ def normal_sphere(r, divide, tex, normal, lighting=True, fv4=GLfloat * 4):
twopi_divide = TWOPI / divide twopi_divide = TWOPI / divide
pi_divide = pi / divide pi_divide = pi / divide
with glSection(GL_TRIANGLE_STRIP): with glSection(GL_TRIANGLE_STRIP):
for j in xrange(divide + 1): for j in range(divide + 1):
phi1 = j * twopi_divide phi1 = j * twopi_divide
phi2 = (j + 1) * twopi_divide phi2 = (j + 1) * twopi_divide
for i in xrange(divide + 1): for i in range(divide + 1):
theta = i * pi_divide theta = i * pi_divide
s = phi2 / TWOPI s = phi2 / TWOPI
@ -252,7 +256,7 @@ def normal_sphere(r, divide, tex, normal, lighting=True, fv4=GLfloat * 4):
def belt(radius, cross, object, count): def belt(radius, cross, object, count):
for i in xrange(count): for i in range(count):
theta = TWOPI * random() theta = TWOPI * random()
r = gauss(radius, cross) r = gauss(radius, cross)
x, y, z = cos(theta) * r, gauss(0, cross), sin(theta) * r x, y, z = cos(theta) * r, gauss(0, cross), sin(theta) * r
@ -285,7 +289,7 @@ except ImportError:
m = 1.0 / sqrt(x * x + y * y + z * z) m = 1.0 / sqrt(x * x + y * y + z * z)
return x * m, y * m, z * m return x * m, y * m, z * m
for i in xrange(n_major): for i in range(n_major):
a0 = i * major_s a0 = i * major_s
a1 = a0 + major_s a1 = a0 + major_s
x0 = cos(a0) x0 = cos(a0)
@ -294,7 +298,7 @@ except ImportError:
y1 = sin(a1) y1 = sin(a1)
with glSection(GL_TRIANGLE_STRIP): with glSection(GL_TRIANGLE_STRIP):
for j in xrange(n_minor + 1): for j in range(n_minor + 1):
b = j * minor_s b = j * minor_s
c = cos(b) c = cos(b)
r = minor_radius * c + major_radius r = minor_radius * c + major_radius

View file

@ -1,12 +1,15 @@
from punyverse.texture import load_texture
from pyglet.gl import *
from uuid import uuid4 from uuid import uuid4
import os import os
import gzip import gzip
import bz2 import bz2
import zipfile import zipfile
import six
from six.moves import range
from pyglet.gl import *
from punyverse.texture import load_texture
def zip_open(file): def zip_open(file):
zip = zipfile.ZipFile(file) zip = zipfile.ZipFile(file)
@ -82,8 +85,9 @@ class WavefrontObject(object):
self.perform_io(self.path) self.perform_io(self.path)
def new_material(self, words): def new_material(self, words):
material = Material(words[1]) name = words[1].decode('utf-8')
self.materials[words[1]] = material material = Material(name)
self.materials[name] = material
self.current_material = material self.current_material = material
def Ka(self, words): def Ka(self, words):
@ -99,7 +103,7 @@ class WavefrontObject(object):
self.current_material.shininess = min(float(words[1]), 125) self.current_material.shininess = min(float(words[1]), 125)
def material_texture(self, words): def material_texture(self, words):
self.current_material.texture = words[-1] self.current_material.texture = words[-1].decode('utf-8')
def vertex(self, words): def vertex(self, words):
self.vertices.append((float(words[1]), float(words[2]), float(words[3]))) self.vertices.append((float(words[1]), float(words[2]), float(words[3])))
@ -138,8 +142,8 @@ class WavefrontObject(object):
nindices = [] nindices = []
tindices = [] tindices = []
for i in xrange(1, vertex_count + 1): for i in range(1, vertex_count + 1):
raw_faces = words[i].split('/') raw_faces = words[i].split(b'/')
l = len(raw_faces) l = len(raw_faces)
current_value = int(raw_faces[0]) current_value = int(raw_faces[0])
@ -174,19 +178,19 @@ class WavefrontObject(object):
group.faces.append(Face(type, vindices, nindices, tindices, face_vertices, face_normals, face_textures)) group.faces.append(Face(type, vindices, nindices, tindices, face_vertices, face_normals, face_textures))
def material(self, words): def material(self, words):
self.perform_io(os.path.join(self.root, words[1])) self.perform_io(os.path.join(self.root, words[1].decode('utf-8')))
def use_material(self, words): def use_material(self, words):
mat = words[1] mat = words[1].decode('utf-8')
try: try:
self.current_group.material = self.materials[mat] self.current_group.material = self.materials[mat]
except KeyError: except KeyError:
print "Warning: material %s undefined, only %s defined." % (mat, self.materials) print("Warning: material %s undefined, only %s defined." % (mat, self.materials))
except AttributeError: except AttributeError:
print "Warning: no group" print("Warning: no group")
def group(self, words): def group(self, words):
name = words[1] name = words[1].decode('utf-8')
group = Group(name) group = Group(name)
if self.groups: if self.groups:
@ -196,29 +200,29 @@ class WavefrontObject(object):
def perform_io(self, file): def perform_io(self, file):
ext = os.path.splitext(file)[1].lstrip('.') ext = os.path.splitext(file)[1].lstrip('.')
reader = openers.get(ext, open)(file) reader = openers.get(ext, lambda x: open(x, 'rb'))(file)
dispatcher = { dispatcher = {
'v': self.vertex, b'v': self.vertex,
'vn': self.normal, b'vn': self.normal,
'vt': self.texture, b'vt': self.texture,
'f': self.face, b'f': self.face,
'mtllib': self.material, b'mtllib': self.material,
'usemtl': self.use_material, b'usemtl': self.use_material,
'g': self.group, b'g': self.group,
'o': self.group, b'o': self.group,
'newmtl': self.new_material, b'newmtl': self.new_material,
'Ka': self.Ka, b'Ka': self.Ka,
'Kd': self.Kd, b'Kd': self.Kd,
'Ks': self.Ks, b'Ks': self.Ks,
'Ns': self.material_shininess, b'Ns': self.material_shininess,
'map_Kd': self.material_texture, b'map_Kd': self.material_texture,
} }
default = lambda words: None default = lambda words: None
with reader: with reader:
for buf in reader: for buf in reader:
if not buf or buf.startswith(('\r', '\n', '#')): if not buf or buf.startswith((b'\r', b'\n', b'#')):
continue # Empty or comment continue # Empty or comment
words = buf.split() words = buf.split()
type = words[0] type = words[0]
@ -236,13 +240,13 @@ else:
def load_model(path): def load_model(path):
if not os.path.isabs(path): if not os.path.isabs(path):
path = os.path.join(model_base, path) path = os.path.join(model_base, path)
if not isinstance(path, unicode): if isinstance(path, six.binary_type):
path = path.decode('mbcs') path = path.decode('mbcs')
return WavefrontObject(path) return WavefrontObject(path)
def model_list(model, sx=1, sy=1, sz=1, rotation=(0, 0, 0)): def model_list(model, sx=1, sy=1, sz=1, rotation=(0, 0, 0)):
for m, text in model.materials.iteritems(): for m, text in six.iteritems(model.materials):
if text.texture: if text.texture:
load_texture(os.path.join(model.root, text.texture)) load_texture(os.path.join(model.root, text.texture))
@ -300,18 +304,13 @@ def model_list(model, sx=1, sy=1, sz=1, rotation=(0, 0, 0)):
x, y, z = vertices[f.verts[n]] x, y, z = vertices[f.verts[n]]
glVertex3f(x * sx, y * sy, z * sz) glVertex3f(x * sx, y * sy, z * sz)
for f in g.faces:
if type != f.type:
if type != -1:
glEnd()
glBegin(GL_TRIANGLES) glBegin(GL_TRIANGLES)
type = f.type for f in g.faces:
point(f, vertices, normals, textures, 0) point(f, vertices, normals, textures, 0)
point(f, vertices, normals, textures, 1) point(f, vertices, normals, textures, 1)
point(f, vertices, normals, textures, 2) point(f, vertices, normals, textures, 2)
if type == FACE_QUADS: if f.type == FACE_QUADS:
point(f, vertices, normals, textures, 2) point(f, vertices, normals, textures, 2)
point(f, vertices, normals, textures, 3) point(f, vertices, normals, textures, 3)
point(f, vertices, normals, textures, 0) point(f, vertices, normals, textures, 0)

View file

@ -1,3 +1,5 @@
from __future__ import print_function
import sys import sys
import os import os
@ -60,7 +62,7 @@ def shrink(file):
image = get_image(file) image = get_image(file)
width, height = get_size(image) width, height = get_size(image)
if fits(width, height): if fits(width, height):
print 'no need' print('no need')
return return
width, height = resize(width, height, 2048) width, height = resize(width, height, 2048)
if fits(width, height): if fits(width, height):
@ -68,14 +70,14 @@ def shrink(file):
else: else:
width, height = resize(width, height, 1024) # 1024 is minimum width, height = resize(width, height, 1024) # 1024 is minimum
size = 'small' size = 'small'
print 'size %s, %dx%d...' % (size, width, height), print('size %s, %dx%d...' % (size, width, height), end=' ')
name = make_name(file, size) name = make_name(file, size)
if not os.path.exists(name): if not os.path.exists(name):
image = scale(image, width, height) image = scale(image, width, height)
print 'saved to:', os.path.basename(name) print('saved to:', os.path.basename(name))
save(image, name) save(image, name)
else: else:
print 'alrady there' print('alrady there')
textures = [ textures = [
'mercury.jpg', 'mercury.jpg',
@ -106,12 +108,12 @@ def main():
files = textures files = textures
texture = os.path.join(punyverse, 'assets', 'textures') texture = os.path.join(punyverse, 'assets', 'textures')
for file in files: for file in files:
print 'Resizing %s:' % file, print('Resizing %s:' % file, end=' ')
file = os.path.join(texture, file.replace('/', os.sep)) file = os.path.join(texture, file.replace('/', os.sep))
if os.path.exists(file): if os.path.exists(file):
shrink(file) shrink(file)
else: else:
print 'exists not' print('exists not')
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -1,12 +1,18 @@
from __future__ import print_function
from pyglet import image from pyglet import image
from pyglet.gl import * from pyglet.gl import *
from ctypes import c_int, byref, c_ulong from ctypes import c_int, byref, c_ulong
import os.path import os.path
import struct import struct
import itertools import itertools
from io import BytesIO
import six
from six.moves import zip
try: try:
from _glgeom import bgr_to_rgb from punyverse._glgeom import bgr_to_rgb
except ImportError: except ImportError:
import warnings import warnings
warnings.warn('Compile _glgeom.c, or double the start up time.') warnings.warn('Compile _glgeom.c, or double the start up time.')
@ -19,17 +25,19 @@ except ImportError:
else: else:
magick = True magick = True
from six.moves import range
def bgr_to_rgb(source, width, height, alpha=False, bottom_up=True): def bgr_to_rgb(source, width, height, alpha=False, bottom_up=True):
length = len(source) length = len(source)
depth = length / (width * height) depth = length // (width * height)
depth2 = depth - alpha depth2 = depth - alpha
result = bytearray(length) result = bytearray(length)
row = width * depth row = width * depth
for y in xrange(height): for y in range(height):
for x in xrange(width): for x in range(width):
ioffset = y * width * depth + x * depth ioffset = y * width * depth + x * depth
ooffset = (height - y - 1 if bottom_up else y) * row + x * depth ooffset = (height - y - 1 if bottom_up else y) * row + x * depth
for i in xrange(depth2): for i in range(depth2):
result[ooffset+i] = source[ioffset+depth2-i-1] result[ooffset+i] = source[ioffset+depth2-i-1]
if alpha: if alpha:
result[ooffset+depth2] = source[ioffset+depth2] result[ooffset+depth2] = source[ioffset+depth2]
@ -37,11 +45,6 @@ except ImportError:
else: else:
magick = False magick = False
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
__all__ = ['load_texture', 'load_clouds', 'load_image', 'pil_load'] __all__ = ['load_texture', 'load_clouds', 'load_image', 'pil_load']
id = 0 id = 0
@ -64,10 +67,8 @@ def init():
if badcard: if badcard:
import warnings import warnings
warnings.warn('Please update your graphics drivers if possible') warnings.warn('Please update your graphics drivers if possible')
#extensions = gl_info.get_extensions() # Currently, BGRA images are flipped.
#bgra = 'GL_EXT_bgra' in extensions # bgra = gl_info.have_extension('GL_EXT_bgra')
#if bgra and magick:
# magick = False # Disable magick because BGRA needs it not
if power_of_two is None: if power_of_two is None:
power_of_two = gl_info.have_version(2) or gl_info.have_extension('GL_ARB_texture_non_power_of_two') power_of_two = gl_info.have_version(2) or gl_info.have_extension('GL_ARB_texture_non_power_of_two')
@ -111,7 +112,7 @@ def image_info(data):
# handle JPEGs # handle JPEGs
elif (size >= 2) and data.startswith('\377\330'): elif (size >= 2) and data.startswith('\377\330'):
content_type = 'image/jpeg' content_type = 'image/jpeg'
jpeg = StringIO(data) jpeg = BytesIO(data)
jpeg.read(2) jpeg.read(2)
b = jpeg.read(1) b = jpeg.read(1)
try: try:
@ -140,21 +141,21 @@ def image_info(data):
def check_size(width, height): def check_size(width, height):
init() init()
if width > max_texture or height > max_texture: if width > max_texture or height > max_texture:
print 'too large' print('too large')
raise ValueError('Texture too large') raise ValueError('Texture too large')
elif not power_of_two: elif not power_of_two:
if not is_power2(width) or not is_power2(height): if not is_power2(width) or not is_power2(height):
print 'not power of two' print('not power of two')
raise ValueError('Texture not power of two') raise ValueError('Texture not power of two')
def load_image(file, path): def load_image(file, path):
print "Loading image %s..." % file, print('Loading image %s...' % file, end=' ')
try: try:
file = open(path, 'rb') file = open(path, 'rb')
except IOError: except IOError:
print 'exists not' print('exists not')
raise ValueError('Texture exists not') raise ValueError('Texture exists not')
type, width, height = image_info(file.read(65536)) type, width, height = image_info(file.read(65536))
file.seek(0, 0) file.seek(0, 0)
@ -166,7 +167,7 @@ def load_image(file, path):
file = Image(path.encode('mbcs' if os.name == 'nt' else 'utf8')) file = Image(path.encode('mbcs' if os.name == 'nt' else 'utf8'))
geo = file.size() geo = file.size()
check_size(geo.width(), geo.height()) check_size(geo.width(), geo.height())
print print()
blob = Blob() blob = Blob()
file.flip() file.flip()
file.write(blob, 'RGBA') file.write(blob, 'RGBA')
@ -176,12 +177,12 @@ def load_image(file, path):
try: try:
raw = image.load(path, file=file) raw = image.load(path, file=file)
except IOError: except IOError:
print 'exists not' print('exists not')
raise ValueError('Texture exists not') raise ValueError('Texture exists not')
width, height = raw.width, raw.height width, height = raw.width, raw.height
check_size(width, height) check_size(width, height)
print print()
mode = GL_RGBA if 'A' in raw.format else GL_RGB mode = GL_RGBA if 'A' in raw.format else GL_RGB
# Flip from BGR to RGB # Flip from BGR to RGB
@ -252,17 +253,16 @@ def load_clouds(file):
id = buffer.value id = buffer.value
pixels = bytearray(len(texture) * 4) pixels = bytearray(len(texture) * 4)
white = chr(255) white = b'\xff'[0]
pixels[:] = itertools.chain.from_iterable(itertools.izip(itertools.repeat(white), itertools.repeat(white), pixels[:] = itertools.chain.from_iterable(zip(itertools.repeat(white), itertools.repeat(white),
itertools.repeat(white), itertools.repeat(white),
itertools.islice(texture, 0, None, depth))) itertools.islice(texture, 0, None, depth)))
glBindTexture(GL_TEXTURE_2D, id) glBindTexture(GL_TEXTURE_2D, id)
filter = GL_LINEAR glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, six.binary_type(pixels))
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, str(pixels))
cache[path] = id cache[path] = id

View file

@ -1,5 +1,7 @@
from __future__ import print_function
from collections import OrderedDict from collections import OrderedDict
import os.path import os
try: try:
import json import json
@ -9,6 +11,8 @@ except ImportError:
except ImportError: except ImportError:
raise SystemExit('No JSON module found') raise SystemExit('No JSON module found')
import six
try: try:
from punyverse._model import model_list, load_model from punyverse._model import model_list, load_model
except ImportError: except ImportError:
@ -97,11 +101,11 @@ class World(object):
self._current_object = 0 self._current_object = 0
def count_objects(bodies): def count_objects(bodies):
for body in bodies.itervalues(): for body in six.itervalues(bodies):
self._objects += 1 self._objects += 1
count_objects(body.get('satellites', {})) count_objects(body.get('satellites', {}))
count_objects(root['bodies']) count_objects(root['bodies'])
print self._objects, 'objects to be loaded...' print(self._objects, 'objects to be loaded...')
if 'start' in root: if 'start' in root:
info = root['start'] info = root['start']
@ -114,9 +118,9 @@ class World(object):
self.start = (x, y, z) self.start = (x, y, z)
self.direction = (pitch, yaw, roll) self.direction = (pitch, yaw, roll)
for planet, info in root['bodies'].iteritems(): for planet, info in six.iteritems(root['bodies']):
message = 'Loading %s.' % planet message = 'Loading %s.' % planet
print message print(message)
self.callback('Loading objects (%d of %d)...' % (self._current_object, self._objects), self.callback('Loading objects (%d of %d)...' % (self._current_object, self._objects),
message, float(self._current_object) / self._objects) message, float(self._current_object) / self._objects)
self._body(planet, info) self._body(planet, info)
@ -125,9 +129,9 @@ class World(object):
if 'belts' in root: if 'belts' in root:
self._phase = 'Loading belts...' self._phase = 'Loading belts...'
self._current_object = 0 self._current_object = 0
for name, info in root['belts'].iteritems(): for name, info in six.iteritems(root['belts']):
message = 'Loading %s.' % name message = 'Loading %s.' % name
print message print(message)
self.callback(self._phase, message, float(self._current_object) / len(root['belts'])) self.callback(self._phase, message, float(self._current_object) / len(root['belts']))
self._belt(name, info) self._belt(name, info)
@ -189,7 +193,7 @@ class World(object):
object_id = model_list(load_model(info['model']), info.get('sx', scale), info.get('sy', scale), object_id = model_list(load_model(info['model']), info.get('sx', scale), info.get('sy', scale),
info.get('sz', scale), (0, 0, 0)) info.get('sz', scale), (0, 0, 0))
else: else:
print 'Nothing to load for %s.' % name print('Nothing to load for %s.' % name)
return return
params = {'world': self, 'orbit_distance': orbit_distance, 'radius': None if background else radius} params = {'world': self, 'orbit_distance': orbit_distance, 'radius': None if background else radius}
@ -243,7 +247,7 @@ class World(object):
if not cheap: if not cheap:
atmosphere_id = compile(disk, radius, radius + atm_size, 30, atm_texture) atmosphere_id = compile(disk, radius, radius + atm_size, 30, atm_texture)
theta = 360 / (rotation + .0) if rotation else 0 theta = 360.0 / rotation if rotation else 0
object = type(object_id, (x, y, z), (pitch, yaw, roll), rotation_angle=theta, object = type(object_id, (x, y, z), (pitch, yaw, roll), rotation_angle=theta,
atmosphere=atmosphere_id, cloudmap=cloudmap_id, background=background, atmosphere=atmosphere_id, cloudmap=cloudmap_id, background=background,
corona=corona_id, **params) corona=corona_id, **params)
@ -264,9 +268,9 @@ class World(object):
type(compile(disk, distance, distance + size, 30, texture), (x, y, z), type(compile(disk, distance, distance + size, 30, texture), (x, y, z),
(pitch, yaw, roll), **params)) (pitch, yaw, roll), **params))
for satellite, info in info.get('satellites', {}).iteritems(): for satellite, info in six.iteritems(info.get('satellites', {})):
message = 'Loading %s, satellite of %s.' % (satellite, name) message = 'Loading %s, satellite of %s.' % (satellite, name)
print message print(message)
self.callback('Loading objects (%d of %d)...' % (self._current_object, self._objects), self.callback('Loading objects (%d of %d)...' % (self._current_object, self._objects),
message, float(self._current_object) / self._objects) message, float(self._current_object) / self._objects)
self._body(satellite, info, object) self._body(satellite, info, object)

View file

@ -28,7 +28,7 @@ with open(os.path.join(os.path.dirname(__file__), 'README.md')) as f:
setup( setup(
name='punyverse', name='punyverse',
version='0.2', version='0.3',
packages=['punyverse'], packages=['punyverse'],
package_data={ package_data={
'punyverse': [ 'punyverse': [
@ -60,7 +60,7 @@ setup(
] ]
}, },
install_requires=['pyglet', 'Pillow'], install_requires=['pyglet', 'Pillow', 'six'],
author='quantum', author='quantum',
author_email='quantum2048@gmail.com', author_email='quantum2048@gmail.com',