Compare commits

...

7 commits
v1.0 ... master

Author SHA1 Message Date
Quantum e77d4661cc Require pyglet<1.4 for now 2020-05-01 02:38:44 -04:00
Quantum 7cb34c9142 Release punyverse 1.2 with better cross platform support 2018-12-01 01:27:56 -05:00
Quantum e72a3bc623 Make sky disablable, and disable by default on macOS 2018-11-27 01:44:06 -05:00
Quantum 9cdf3b8513 Make punyverse runnable on macOS 2018-11-27 01:27:59 -05:00
Guanzhong Chen 885194c7a0
Update README.md 2018-09-26 11:06:23 -04:00
Quantum 8739120036 So much legacy texture stuff can go. 2018-08-30 16:47:10 -04:00
Quantum d5297d3619 Release 1.1 with higher resolution textures.
After all, it doesn't exactly make sense for saturn's moons and mercury to have more detailed textures than larger objects like the sun or venus.

Also used one single texture to do the transparency mask for the glow, instead of having separate textures for each glowy object.
2018-08-29 17:55:06 -04:00
28 changed files with 84 additions and 55 deletions

4
.gitignore vendored
View file

@ -62,3 +62,7 @@ library.zip
# Our special launcher
!/punyverse/launcher.c
# macOS
.DS_Store
._.DS_Store

View file

@ -5,4 +5,5 @@ include punyverse/world.json
graft punyverse/assets
include punyverse/shaders/*.glsl
include punyverse/*.c
include punyverse/*.h
exclude punyverse/*.pyx

View file

@ -1,4 +1,4 @@
# punyverse [![Linux Build Status](https://img.shields.io/travis/quantum5/punyverse.svg?logo=linux)](https://travis-ci.org/quantum5/punyverse) [![Windows Build Status](https://img.shields.io/appveyor/ci/quantum5/punyverse.svg?logo=windows)](https://ci.appveyor.com/project/quantum5/punyverse) [![PyPI](https://img.shields.io/pypi/v/punyverse.svg)](https://pypi.org/project/punyverse/) [![PyPI - Format](https://img.shields.io/pypi/format/punyverse.svg)](https://pypi.org/project/punyverse/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/punyverse.svg)](https://pypi.org/project/punyverse/)
# punyverse [![Linux Build Status](https://img.shields.io/travis/quantum5/punyverse.svg?logo=linux&logoColor=white)](https://travis-ci.org/quantum5/punyverse) [![Windows Build Status](https://img.shields.io/appveyor/ci/quantum5/punyverse.svg?logo=windows)](https://ci.appveyor.com/project/quantum5/punyverse) [![PyPI](https://img.shields.io/pypi/v/punyverse.svg)](https://pypi.org/project/punyverse/) [![PyPI - Format](https://img.shields.io/pypi/format/punyverse.svg)](https://pypi.org/project/punyverse/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/punyverse.svg)](https://pypi.org/project/punyverse/)
Python simulator of a puny universe. (How many words can I stick into one?)

View file

@ -1,8 +1,4 @@
IF UNAME_SYSNAME == "Windows":
cdef extern from "windows.h":
pass
cdef extern from "GL/gl.h":
cdef extern from "glwrapper.h":
ctypedef unsigned int GLenum
ctypedef unsigned char GLboolean
ctypedef unsigned int GLbitfield

View file

@ -1,7 +1,9 @@
# This file contains all the textures that is bigger than the minimum OpenGL texture size
# and hence may need to be resized depending on the machine
sun.jpg
mercury.jpg
venus.jpg
earth.jpg
earth_normal.jpg
earth_emission.jpg
@ -11,6 +13,8 @@ moon.jpg
mars.jpg
jupiter.jpg
saturn.jpg
uranus.jpg
neptune.jpg
sky_px.jpg
sky_py.jpg
sky_pz.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 981 KiB

View file

@ -388,8 +388,9 @@ class SphericalBody(Body):
if 'atmosphere' in info:
atmosphere_data = info['atmosphere']
atm_size = world.evaluate(atmosphere_data.get('diffuse_size', None))
atm_texture = atmosphere_data.get('diffuse_texture', None)
atm_size = world.evaluate(atmosphere_data.get('glow_size', None))
atm_texture = atmosphere_data.get('glow_texture', None)
atm_color = atmosphere_data.get('glow_color', None)
cloud_texture = atmosphere_data.get('cloud_texture', None)
if cloud_texture is not None:
self.cloud_transparency = get_best_texture(cloud_texture, loader=load_alpha_mask)
@ -405,8 +406,9 @@ class SphericalBody(Body):
self.clouds.stride, self.clouds.uv_offset)
glBindBuffer(GL_ARRAY_BUFFER, 0)
if atm_texture is not None:
if atm_texture is not None and atm_color is not None:
self.atm_texture = load_texture_1d(atm_texture, clamp=True)
self.atm_color = atm_color
self.atmosphere = Disk(self.radius, self.radius + atm_size, 30)
self.atmosphere_vao = VAO()
shader = self.world.activate_shader('atmosphere')
@ -513,7 +515,8 @@ class SphericalBody(Body):
shader.uniform_mat4('u_mvpMatrix', self.world.projection_matrix() * matrix)
glBindTexture(GL_TEXTURE_1D, self.atm_texture)
shader.uniform_texture('u_texture', 0)
shader.uniform_texture('u_transparency', 0)
shader.uniform_vec3('u_color', *self.atm_color)
with self.atmosphere_vao:
glDrawArrays(GL_TRIANGLE_STRIP, 0, self.atmosphere.vertex_count)

9
punyverse/glwrapper.h Normal file
View file

@ -0,0 +1,9 @@
#ifdef _MSC_VER
# include <windows.h>
#endif
#ifdef __APPLE__
# include <OpenGL/gl.h>
#else
# include <GL/gl.h>
#endif

View file

@ -134,10 +134,10 @@ class LoaderWindow(pyglet.window.Window):
self.flip()
self.dispatch_events()
def load(self):
def load(self, **kwargs):
start = time.clock()
with glContext(self._main_context):
world = World('world.json', self._load_callback)
world = World('world.json', self._load_callback, **kwargs)
print('Loaded in %s seconds.' % (time.clock() - start))
return world
@ -167,10 +167,10 @@ class LoaderConsole(object):
def _load_callback(self, phase, message, progress):
print(message, file=self._output)
def load(self):
def load(self, **kwargs):
start = time.clock()
with glContext(self._main_context):
world = World('world.json', self._load_callback)
world = World('world.json', self._load_callback, **kwargs)
print('Loaded in %s seconds.' % (time.clock() - start), file=self._output)
return world

View file

@ -1,4 +1,5 @@
import argparse
import sys
import pyglet
@ -8,9 +9,12 @@ DEBUG = False
def main():
macos = sys.platform == 'darwin'
parser = argparse.ArgumentParser(prog='punyverse', description='''
Python simulator of a puny universe.
''')
parser.set_defaults(sky=not macos)
parser.add_argument('-D', '--debug', help='Enable pyglet OpenGL debugging', action='store_true')
parser.add_argument('-d', '--high-depth', help='Use a larger depth buffer',
const=32, default=24, dest='depth', nargs='?', type=int)
@ -20,14 +24,21 @@ def main():
action='store_false', dest='vsync')
parser.add_argument('-n', '--normal', help='Enables the use of normal maps',
action='store_true')
parser.add_argument('-s', '--sky', help='Enables the sky', dest='sky',
action='store_true')
parser.add_argument('-S', '--no-sky', help='Disables the sky', dest='sky',
action='store_false')
args = parser.parse_args()
versioning = dict(major_version=3, minor_version=3)
pyglet.options['debug_gl'] = args.debug
if macos:
pyglet.options['shadow_window'] = False
versioning = dict(major_version=4, minor_version=1, forward_compatible=True)
template = pyglet.gl.Config(depth_size=args.depth, double_buffer=True,
sample_buffers=args.multisample > 1,
samples=args.multisample,
major_version=3, minor_version=3)
samples=args.multisample, **versioning)
platform = pyglet.window.get_platform()
display = platform.get_default_display()
@ -64,7 +75,7 @@ def main():
loader.context.set_current()
loader.set_main_context(punyverse.context)
world = loader.load()
world = loader.load(sky=args.sky)
punyverse.context.set_current()
punyverse.initialize(world)
loader.close()

View file

@ -3,8 +3,10 @@
in float v_u;
out vec4 o_fragColor;
uniform sampler1D u_texture;
uniform vec3 u_color;
uniform sampler1D u_transparency;
void main() {
o_fragColor = texture(u_texture, v_u);
o_fragColor = vec4(u_color, texture(u_transparency, v_u).r);
}

View file

@ -34,7 +34,7 @@ void main() {
float diffuseIntensity = max(dot(v_normal, incident), 0.0);
float shininess = pow(max(dot(normalize(v_camDirection), reflected), 0), u_material.shininess);
vec3 diffuse = u_material.hasDiffuse ? texture2D(u_material.diffuseMap, v_uv).rgb : vec3(1);
vec3 diffuse = u_material.hasDiffuse ? texture(u_material.diffuseMap, v_uv).rgb : vec3(1);
vec3 ambient = u_material.ambient * u_sun.ambient * diffuse;
vec3 specular = u_material.specular * u_sun.specular * max(shininess, 0) * diffuseIntensity;
diffuse *= u_material.diffuse * u_sun.diffuse * diffuseIntensity;

View file

@ -35,10 +35,10 @@ uniform Sun u_sun;
uniform Surface u_planet;
void main() {
vec3 normal = u_planet.hasNormal ? normalize(v_TBN * texture2D(u_planet.normalMap, v_uv).rgb * 2 - 1) : v_normal;
vec3 diffuse = texture2D(u_planet.diffuseMap, v_uv).rgb;
vec3 specular = u_planet.hasSpecular ? texture2D(u_planet.specularMap, v_uv).rgb : vec3(1);
vec3 emission = u_planet.hasEmission ? texture2D(u_planet.emissionMap, v_uv).rgb : vec3(1);
vec3 normal = u_planet.hasNormal ? normalize(v_TBN * texture(u_planet.normalMap, v_uv).rgb * 2 - 1) : v_normal;
vec3 diffuse = texture(u_planet.diffuseMap, v_uv).rgb;
vec3 specular = u_planet.hasSpecular ? texture(u_planet.specularMap, v_uv).rgb : vec3(1);
vec3 emission = u_planet.hasEmission ? texture(u_planet.emissionMap, v_uv).rgb : vec3(1);
vec3 incident = normalize(u_sun.position - v_position);
vec3 reflected = normalize(reflect(-incident, normal));

View file

@ -131,10 +131,6 @@ def check_size(width, height):
if width > max_texture or height > max_texture:
print('too large')
raise ValueError('Texture too large')
elif not gl_info.have_version(2) and not gl_info.have_extension('GL_ARB_texture_non_power_of_two'):
if not is_power2(width) or not is_power2(height):
print('not power of two')
raise ValueError('Texture not power of two')
def load_image(file, path):
@ -217,12 +213,8 @@ def load_texture(file, clamp=False):
id = create_texture()
glBindTexture(GL_TEXTURE_2D, id)
if gl_info.have_version(3) or gl_info.have_extension('GL_ARB_framebuffer_object'):
glTexImage2D(GL_TEXTURE_2D, 0, get_internal_mode(mode), width, height, 0, mode, GL_UNSIGNED_BYTE, texture)
glGenerateMipmap(GL_TEXTURE_2D)
else:
gluBuild2DMipmaps(GL_TEXTURE_2D, depth, width, height, mode, GL_UNSIGNED_BYTE, texture)
glTexImage2D(GL_TEXTURE_2D, 0, get_internal_mode(mode), width, height, 0, mode, GL_UNSIGNED_BYTE, texture)
glGenerateMipmap(GL_TEXTURE_2D)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
@ -245,11 +237,8 @@ def load_texture_1d(file, clamp=False):
id = create_texture()
glBindTexture(GL_TEXTURE_1D, id)
if gl_info.have_version(3) or gl_info.have_extension('GL_ARB_framebuffer_object'):
glTexImage1D(GL_TEXTURE_1D, 0, get_internal_mode(mode), width, 0, mode, GL_UNSIGNED_BYTE, texture)
glGenerateMipmap(GL_TEXTURE_1D)
else:
gluBuild1DMipmaps(GL_TEXTURE_1D, depth, width, mode, GL_UNSIGNED_BYTE, texture)
glTexImage1D(GL_TEXTURE_1D, 0, get_internal_mode(mode), width, 0, mode, GL_UNSIGNED_BYTE, texture)
glGenerateMipmap(GL_TEXTURE_1D)
if clamp:
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
@ -272,12 +261,8 @@ def load_alpha_mask(file, clamp=False):
id = buffer.value
glBindTexture(GL_TEXTURE_2D, id)
if gl_info.have_version(3) or gl_info.have_extension('GL_ARB_framebuffer_object'):
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, texture)
glGenerateMipmap(GL_TEXTURE_2D)
else:
gluBuild2DMipmaps(GL_TEXTURE_2D, 1, width, height, GL_RED, GL_UNSIGNED_BYTE, texture)
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, texture)
glGenerateMipmap(GL_TEXTURE_2D)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)

View file

@ -199,6 +199,8 @@ class Punyverse(pyglet.window.Window):
if not width or not height:
# Sometimes this happen for no reason?
return
if hasattr(self, 'get_viewport_size'):
width, height = self.get_viewport_size()
glViewport(0, 0, width, height)
self.world.resize(width, height)

View file

@ -7,7 +7,7 @@
"distance": "virtual distance to look better, in km",
"sma": "semi-major axis used with mass of parent to calculate orbit, in km",
"mass": "mass in kg",
"texture": "a group of texture to use, tried in that order. a list means a colour",
"texture": "a group of texture to use, tried in that order",
"model": "used to load a wavefront object instead of a textured sphere"
},
"au": 10000,
@ -24,8 +24,9 @@
"light_source": true,
"type": "star",
"atmosphere": {
"diffuse_texture": "sun_diffuse.png",
"diffuse_size": 300
"glow_color": [0.92, 0.92, 0.82],
"glow_texture": "glow.png",
"glow_size": 300
}
},
"mercury": {
@ -61,8 +62,9 @@
"emission_map": ["earth_emission.jpg", "earth_emission_medium.jpg", "earth_emission_small.jpg"],
"atmosphere": {
"cloud_texture": ["cloudmap.jpg", "cloudmap_small.jpg"],
"diffuse_texture": "atmosphere_earth.png",
"diffuse_size": 30
"glow_color": [0.11, 0.32, 0.43],
"glow_texture": "glow.png",
"glow_size": 30
},
"orbit_distance": "AU",
"satellites": {

View file

@ -30,7 +30,7 @@ class World(object):
'belt': ('belt.vertex.glsl', 'model.fragment.glsl'),
}
def __init__(self, file, callback):
def __init__(self, file, callback, sky=True):
self.tracker = []
self.x = None
self.y = None
@ -40,6 +40,8 @@ class World(object):
self.asteroids = AsteroidManager(self)
self.cam = Camera()
self._sky = sky
self._program = None
self.callback = callback
self.programs = self._load_programs()
@ -127,7 +129,7 @@ class World(object):
'Loading %s.' % name, i / belt_count)
self.tracker.append(Belt(name, self, info))
if 'sky' in root:
if 'sky' in root and self._sky:
def callback(index, file):
self.callback('Loading sky...', 'Loading %s.' % file, index / 6)
self.tracker.append(Sky(self, root['sky'], callback))

View file

@ -26,9 +26,16 @@ else:
if os.name == 'nt':
gl_libs = ['opengl32']
elif sys.platform == 'darwin':
gl_libs = []
else:
gl_libs = ['GL']
if sys.platform == 'darwin':
extra_compile_args = extra_link_args = ['-framework', 'OpenGL']
else:
extra_compile_args = extra_link_args = []
with open(os.path.join(os.path.dirname(__file__), 'README.md')) as f:
long_description = f.read()
@ -105,7 +112,7 @@ else:
setup(
name='punyverse',
version='1.0',
version='1.2',
packages=['punyverse'],
package_data={
'punyverse': [
@ -124,7 +131,8 @@ setup(
],
},
ext_modules=cythonize([
Extension('punyverse._glgeom', sources=[pyx_path('punyverse/_glgeom.pyx')], libraries=gl_libs),
Extension('punyverse._glgeom', sources=[pyx_path('punyverse/_glgeom.pyx')], libraries=gl_libs,
extra_compile_args=extra_compile_args, extra_link_args=extra_link_args),
]) + extra_libs,
cmdclass={'build_ext': build_ext},
@ -139,7 +147,7 @@ setup(
]
},
install_requires=['pyglet', 'Pillow', 'six'],
install_requires=['pyglet<1.4', 'Pillow', 'six'],
author='quantum',
author_email='quantum2048@gmail.com',