diff --git a/punyverse/assets/textures/sun_corona.png b/punyverse/assets/textures/sun_corona.png deleted file mode 100644 index 31fa445..0000000 Binary files a/punyverse/assets/textures/sun_corona.png and /dev/null differ diff --git a/punyverse/entity.py b/punyverse/entity.py index 6cfb67c..7ec8cc7 100644 --- a/punyverse/entity.py +++ b/punyverse/entity.py @@ -5,7 +5,7 @@ from pyglet.gl import * # noinspection PyUnresolvedReferences from six.moves import range -from punyverse.glgeom import compile, flare, disk, glMatrix, glRestore, belt, Sphere +from punyverse.glgeom import compile, glMatrix, glRestore, belt, Sphere, Disk from punyverse.orbit import KeplerOrbit from punyverse.texture import get_best_texture, load_clouds @@ -266,32 +266,22 @@ class SphericalBody(Body): self.texture = get_best_texture(info['texture']) self.sphere = Sphere(self.radius, division, division) - self.atmosphere_id = 0 + self.atmosphere = None self.clouds = None - self.corona_id = 0 - self.ring_id = 0 + self.ring = 0 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) cloud_texture = atmosphere_data.get('cloud_texture', None) - corona_texture = atmosphere_data.get('corona_texture', None) if cloud_texture is not None: self.cloud_texture = get_best_texture(cloud_texture, loader=load_clouds) self.clouds = Sphere(self.radius + 2, division, division) - if corona_texture is not None: - corona = get_best_texture(corona_texture, clamp=True) - corona_size = atmosphere_data.get('corona_size', self.radius / 2) - corona_division = atmosphere_data.get('corona_division', 100) - corona_ratio = atmosphere_data.get('corona_ratio', 0.5) - self.corona_id = compile(flare, self.radius, self.radius + corona_size, corona_division, - corona_ratio, corona) - if atm_texture is not None: - atm_texture = get_best_texture(atm_texture, clamp=True) - self.atmosphere_id = compile(disk, self.radius, self.radius + atm_size, 30, atm_texture) + self.atm_texture = get_best_texture(atm_texture, clamp=True) + self.atmosphere = Disk(self.radius, self.radius + atm_size, 30) if 'ring' in info: distance = world.evaluate(info['ring'].get('distance', self.radius * 1.2)) @@ -303,8 +293,8 @@ class SphericalBody(Body): roll = world.evaluate(info['ring'].get('roll', roll)) self.ring_rotation = pitch, yaw, roll - self.ring_id = compile(disk, distance, distance + size, 30, - get_best_texture(info['ring'].get('texture', None), clamp=True)) + self.ring_texture = get_best_texture(info['ring'].get('texture', None), clamp=True) + self.ring = Disk(distance, distance + size, 30) def _draw_sphere(self, fv4=GLfloat * 4): with glMatrix(self.location, self.rotation), glRestore(GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT): @@ -325,7 +315,7 @@ class SphericalBody(Body): self.sphere.draw() def _draw_atmosphere(self, glMatrixBuffer=GLfloat * 16): - with glMatrix(self.location), glRestore(GL_ENABLE_BIT | GL_CURRENT_BIT): + with glMatrix(self.location), glRestore(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_TEXTURE_BIT): matrix = glMatrixBuffer() glGetFloatv(GL_MODELVIEW_MATRIX, matrix) matrix[0: 3] = [1, 0, 0] @@ -333,14 +323,13 @@ class SphericalBody(Body): matrix[8:11] = [0, 0, 1] glLoadMatrixf(matrix) - if self.atmosphere_id: - glCallList(self.atmosphere_id) + glDisable(GL_LIGHTING) + glEnable(GL_TEXTURE_2D) + glEnable(GL_BLEND) + glDisable(GL_CULL_FACE) - if self.corona_id: - x, y, z = self.world.cam.direction() - glTranslatef(-x, -y, -z) - glEnable(GL_BLEND) - glCallList(self.corona_id) + glBindTexture(GL_TEXTURE_2D, self.atm_texture) + self.atmosphere.draw() def _draw_clouds(self): with glMatrix(self.location, self.rotation), glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT): @@ -355,19 +344,25 @@ class SphericalBody(Body): self.clouds.draw() def _draw_rings(self): - with glMatrix(self.location, self.ring_rotation), glRestore(GL_CURRENT_BIT): - glCallList(self.ring_id) + with glMatrix(self.location, self.ring_rotation), glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT): + glDisable(GL_LIGHTING) + glEnable(GL_TEXTURE_2D) + glEnable(GL_BLEND) + glDisable(GL_CULL_FACE) + + glBindTexture(GL_TEXTURE_2D, self.ring_texture) + self.ring.draw() def _draw(self, options): self._draw_sphere() - if options.atmosphere and (self.atmosphere_id or self.corona_id): + if options.atmosphere and self.atmosphere: self._draw_atmosphere() if options.cloud and self.clouds: self._draw_clouds() - if self.ring_id: + if self.ring: self._draw_rings() def _collides(self, x, y, z): diff --git a/punyverse/glgeom.py b/punyverse/glgeom.py index 45d9bbe..b060d2d 100644 --- a/punyverse/glgeom.py +++ b/punyverse/glgeom.py @@ -9,8 +9,8 @@ from six.moves import range TWOPI = pi * 2 -__all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'disk', 'Sphere', 'belt', - 'flare', 'glSection', 'glMatrix', 'glRestore', 'progress_bar'] +__all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'Sphere', 'belt', + 'glSection', 'glMatrix', 'glRestore', 'progress_bar'] class glContext(object): @@ -79,6 +79,24 @@ class glMatrix(object): glPopMatrix() +def array_to_ctypes(arr): + return cast(arr.buffer_info()[0], POINTER({ + 'f': c_float, + 'i': c_int, + 'I': c_uint, + }[arr.typecode])) + + +def array_to_gl_buffer(buffer, array_type='f'): + vbo = c_uint() + glGenBuffers(1, byref(vbo)) + glBindBuffer(GL_ARRAY_BUFFER, vbo.value) + buffer = array(array_type, buffer) + glBufferData(GL_ARRAY_BUFFER, buffer.itemsize * len(buffer), array_to_ctypes(buffer), GL_STATIC_DRAW) + glBindBuffer(GL_ARRAY_BUFFER, 0) + return vbo.value + + def compile(pointer, *args, **kwargs): display = glGenLists(1) glNewList(display, GL_COMPILE) @@ -125,69 +143,29 @@ def circle(r, seg, coords): glVertex2f(cx + cos(theta) * r, cy + sin(theta) * r) -def disk(rinner, router, segs, tex): - with glRestore(GL_ENABLE_BIT): - glEnable(GL_TEXTURE_2D) - glEnable(GL_BLEND) - glDisable(GL_LIGHTING) - glDisable(GL_CULL_FACE) - glBindTexture(GL_TEXTURE_2D, tex) +class Disk(object): + def __init__(self, rinner, router, segs): res = segs * 5 + delta = 2 * pi / res + self.vertex_count = (res + 1) * 2 + # Need padding to make the last vertex render correctly... why? + buffer = self.vertex_count * 3 * [0] + for i in range(res): + theta = delta * i + x, y = cos(theta), sin(theta) + buffer[6*i:6*i+6] = [rinner * x, rinner * y, 0, router * x, router * y, 1] + buffer[6*res:6*res+6] = buffer[:6] + self.vbo = array_to_gl_buffer(buffer) - with glSection(GL_TRIANGLE_STRIP): - factor = TWOPI / res - theta = 0 - for n in range(res + 1): - theta += factor - x = cos(theta) - y = sin(theta) - glTexCoord2f(0, 0) - glVertex2f(rinner * x, rinner * y) - glTexCoord2f(1, 0) - glVertex2f(router * x, router * y) - - -def flare(rinner, router, res, prob, tex): - with glRestore(GL_ENABLE_BIT): - glEnable(GL_TEXTURE_2D) - glDisable(GL_CULL_FACE) - glDisable(GL_LIGHTING) - glBindTexture(GL_TEXTURE_2D, tex) - last_x = 1 - last_y = 0 - last_theta = 0 - factor = TWOPI / res - rdelta = (router - rinner) - with glSection(GL_QUADS): - for i in range(res + 1): - theta = last_theta + factor - x = cos(theta) - y = sin(theta) - if random() > prob: - distance = rinner + rdelta * random() - avg_theta = (last_theta + theta) / 2 - x0, y0 = rinner * last_x, rinner * last_y - x1, y1 = rinner * x, rinner * y - x2, y2 = distance * cos(avg_theta), distance * sin(avg_theta) - glTexCoord2f(0, 0) - glVertex2f(x0, y0) - glTexCoord2f(0, 1) - glVertex2f(x1, y1) - glTexCoord2f(1, 0) - glVertex2f(x2, y2) - glTexCoord2f(1, 1) - glVertex2f(x2, y2) - last_theta = theta - last_x = x - last_y = y - - -def array_to_ctypes(arr): - return cast(arr.buffer_info()[0], POINTER({ - 'f': c_float, - 'i': c_int, - 'I': c_uint, - }[arr.typecode])) + def draw(self): + with glRestoreClient(GL_CLIENT_VERTEX_ARRAY_BIT): + glBindBuffer(GL_ARRAY_BUFFER, self.vbo) + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_TEXTURE_COORD_ARRAY) + glVertexPointer(3, GL_FLOAT, 12, 0) + glTexCoordPointer(1, GL_FLOAT, 12, 8) + glDrawArrays(GL_TRIANGLE_STRIP, 0, self.vertex_count) + glBindBuffer(GL_ARRAY_BUFFER, 0) class Sphere(object): @@ -214,13 +192,7 @@ class Sphere(object): r * dx2, r * dy2, r * dz, dx2, dy2, dz, phi1 / tau, t] index += 16 - vbo = c_uint() - glGenBuffers(1, byref(vbo)) - self.vbo = vbo.value - glBindBuffer(GL_ARRAY_BUFFER, self.vbo) - buffer = array('f', buffer) - glBufferData(GL_ARRAY_BUFFER, buffer.itemsize * len(buffer), array_to_ctypes(buffer), GL_STATIC_DRAW) - glBindBuffer(GL_ARRAY_BUFFER, 0) + self.vbo = array_to_gl_buffer(buffer) def draw(self): with glRestoreClient(GL_CLIENT_VERTEX_ARRAY_BIT): diff --git a/punyverse/texture.py b/punyverse/texture.py index 80c3902..274ad70 100644 --- a/punyverse/texture.py +++ b/punyverse/texture.py @@ -257,5 +257,5 @@ def get_best_texture(info, loader=load_texture, **kwargs): except ValueError: pass else: - return loader(info) + return loader(info, **kwargs) raise ValueError('No texture found') diff --git a/punyverse/world.json b/punyverse/world.json index c68a76e..b3a2b5b 100644 --- a/punyverse/world.json +++ b/punyverse/world.json @@ -23,10 +23,6 @@ "rotation": 2164320, "light_source": true, "atmosphere": { - "corona_texture": "sun_corona.png", - "corona_size": 1500, - "corona_division": 100, - "corona_prob": 0.5, "diffuse_texture": "sun_diffuse.png", "diffuse_size": 300 }