mirror of
https://github.com/quantum5/punyverse.git
synced 2025-04-24 13:11:57 -04:00
Added hardware normal mapping, usable with -n/--normal option.
This commit is contained in:
parent
83d8baeb8e
commit
2348e1d275
|
@ -16,6 +16,8 @@ def main():
|
||||||
type=int)
|
type=int)
|
||||||
parser.add_argument('-v', '--no-vsync', help='Disables vsync',
|
parser.add_argument('-v', '--no-vsync', help='Disables vsync',
|
||||||
action='store_false', dest='vsync')
|
action='store_false', dest='vsync')
|
||||||
|
parser.add_argument('-n', '--normal', help='Enables the use of normal maps',
|
||||||
|
action='store_true')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
import pyglet
|
import pyglet
|
||||||
|
@ -38,10 +40,14 @@ def main():
|
||||||
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 = {
|
||||||
|
'normal': args.normal,
|
||||||
|
}
|
||||||
|
|
||||||
from punyverse import game
|
from punyverse import game
|
||||||
game.Applet(width=INITIAL_WIN_WIDTH, height=INITIAL_WIN_HEIGHT,
|
game.Applet(width=INITIAL_WIN_WIDTH, height=INITIAL_WIN_HEIGHT,
|
||||||
caption=WIN_TITLE, resizable=True, vsync=args.vsync,
|
caption=WIN_TITLE, resizable=True, vsync=args.vsync,
|
||||||
config=config)
|
config=config, world_options=world_options)
|
||||||
pyglet.app.run()
|
pyglet.app.run()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ def entity_distance(x0, y0, z0):
|
||||||
|
|
||||||
class Applet(pyglet.window.Window):
|
class Applet(pyglet.window.Window):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.world_options = kwargs.pop('world_options', {})
|
||||||
|
|
||||||
super(Applet, self).__init__(*args, **kwargs)
|
super(Applet, self).__init__(*args, **kwargs)
|
||||||
texture.init()
|
texture.init()
|
||||||
|
|
||||||
|
@ -79,7 +81,7 @@ class Applet(pyglet.window.Window):
|
||||||
|
|
||||||
start = clock()
|
start = clock()
|
||||||
self.fps = 0
|
self.fps = 0
|
||||||
self.world = World('world.json', callback)
|
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)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from math import *
|
from math import *
|
||||||
from pyglet.gl import *
|
from pyglet.gl import *
|
||||||
from random import random, gauss, choice
|
from random import random, gauss, choice
|
||||||
|
from pyglet.gl.gl_info import have_extension
|
||||||
|
|
||||||
TWOPI = pi * 2
|
TWOPI = pi * 2
|
||||||
|
|
||||||
|
@ -181,71 +182,64 @@ def colourball(r, lats, longs, colour, fv4=GLfloat * 4):
|
||||||
gluDeleteQuadric(sphere)
|
gluDeleteQuadric(sphere)
|
||||||
|
|
||||||
|
|
||||||
try:
|
def normal_sphere(r, divide, tex, normal, lighting=True, fv4=GLfloat * 4):
|
||||||
from _glgeom import normal_sphere
|
if (not have_extension('GL_ARB_multitexture') or not
|
||||||
except ImportError:
|
have_extension('GL_ARB_texture_env_combine') or not
|
||||||
import warnings
|
have_extension('GL_EXT_texture_env_dot3')):
|
||||||
warnings.warn('Large sphere drawing in Python is slow')
|
print 'No hardware normal mapping support. No bumping for you.'
|
||||||
|
return sphere(r, divide, divide, tex, lighting)
|
||||||
|
|
||||||
def normal_sphere(r, divide, tex, normal, lighting=True, fv4=GLfloat * 4):
|
from texture import load_texture
|
||||||
from texture import pil_load
|
normal = load_texture(normal)
|
||||||
print 'Loading normal map: %s...' % normal,
|
|
||||||
normal_map = pil_load(normal)
|
|
||||||
normal = normal_map.load()
|
|
||||||
print
|
|
||||||
width, height = normal_map.size
|
|
||||||
gray_scale = len(normal[0, 0]) == 1
|
|
||||||
|
|
||||||
with glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT):
|
with glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT):
|
||||||
glEnable(GL_TEXTURE_2D)
|
glActiveTextureARB(GL_TEXTURE0_ARB)
|
||||||
if lighting:
|
glBindTexture(GL_TEXTURE_2D, normal)
|
||||||
glDisable(GL_BLEND)
|
glEnable(GL_TEXTURE_2D)
|
||||||
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, fv4(1, 1, 1, 0))
|
|
||||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, fv4(1, 1, 1, 0))
|
|
||||||
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 125)
|
|
||||||
else:
|
|
||||||
glDisable(GL_LIGHTING)
|
|
||||||
glBindTexture(GL_TEXTURE_2D, tex)
|
|
||||||
|
|
||||||
twopi_divide = TWOPI / divide
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB)
|
||||||
pi_divide = pi / divide
|
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGBA_ARB)
|
||||||
with glSection(GL_TRIANGLE_STRIP):
|
|
||||||
for j in xrange(divide + 1):
|
|
||||||
phi1 = j * twopi_divide
|
|
||||||
phi2 = (j + 1) * twopi_divide
|
|
||||||
|
|
||||||
for i in xrange(divide + 1):
|
glActiveTextureARB(GL_TEXTURE1_ARB)
|
||||||
theta = i * pi_divide
|
glBindTexture(GL_TEXTURE_2D, tex)
|
||||||
|
glEnable(GL_TEXTURE_2D)
|
||||||
|
|
||||||
s = phi2 / TWOPI
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB)
|
||||||
u = min(int(s * width), width - 1)
|
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE)
|
||||||
t = theta / pi
|
|
||||||
v = min(int(t * height), height - 1)
|
|
||||||
if gray_scale:
|
|
||||||
x = y = z = normal[u, v]
|
|
||||||
else:
|
|
||||||
x, y, z = normal[u, v]
|
|
||||||
dx, dy, dz = sin(theta) * cos(phi2), sin(theta) * sin(phi2), cos(theta)
|
|
||||||
nx, ny, nz = x / 127.5 - 1, y / 127.5 - 1, z / 127.5 - 1 # Make into [-1, 1]
|
|
||||||
nx, nz = cos(theta) * nx + sin(theta) * nz, -sin(theta) * nx + cos(theta) * nz
|
|
||||||
nx, ny = cos(phi2) * nx - sin(phi2) * ny, sin(phi2) * nx + cos(phi2) * ny
|
|
||||||
glNormal3f(nx, ny, nz)
|
|
||||||
glTexCoord2f(s, 1 - t) # GL is bottom up
|
|
||||||
glVertex3f(r * dx, r * dy, r * dz)
|
|
||||||
|
|
||||||
s = phi1 / TWOPI # x
|
if lighting:
|
||||||
u = min(int(s * width), width - 1)
|
glDisable(GL_BLEND)
|
||||||
if gray_scale:
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, fv4(1, 1, 1, 0))
|
||||||
x = y = z = normal[u, v]
|
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, fv4(1, 1, 1, 0))
|
||||||
else:
|
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 125)
|
||||||
x, y, z = normal[u, v]
|
else:
|
||||||
dx, dy = sin(theta) * cos(phi1), sin(theta) * sin(phi1)
|
glDisable(GL_LIGHTING)
|
||||||
nx, ny, nz = x / 127.5 - 1, y / 127.5 - 1, z / 127.5 - 1
|
glBindTexture(GL_TEXTURE_2D, tex)
|
||||||
nx, nz = cos(theta) * nx + sin(theta) * nz, -sin(theta) * nx + cos(theta) * nz
|
|
||||||
nx, ny = cos(phi1) * nx - sin(phi1) * ny, sin(phi1) * nx + cos(phi1) * ny
|
twopi_divide = TWOPI / divide
|
||||||
glNormal3f(nx, ny, nz)
|
pi_divide = pi / divide
|
||||||
glTexCoord2f(s, 1 - t)
|
with glSection(GL_TRIANGLE_STRIP):
|
||||||
glVertex3f(r * dx, r * dy, r * dz)
|
for j in xrange(divide + 1):
|
||||||
|
phi1 = j * twopi_divide
|
||||||
|
phi2 = (j + 1) * twopi_divide
|
||||||
|
|
||||||
|
for i in xrange(divide + 1):
|
||||||
|
theta = i * pi_divide
|
||||||
|
|
||||||
|
s = phi2 / TWOPI
|
||||||
|
t = theta / pi
|
||||||
|
dx, dy, dz = sin(theta) * cos(phi2), sin(theta) * sin(phi2), cos(theta)
|
||||||
|
glNormal3f(dx, dy, dz)
|
||||||
|
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, s, 1 - t)
|
||||||
|
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, s, 1 - t)
|
||||||
|
glVertex3f(r * dx, r * dy, r * dz)
|
||||||
|
|
||||||
|
s = phi1 / TWOPI # x
|
||||||
|
dx, dy = sin(theta) * cos(phi1), sin(theta) * sin(phi1)
|
||||||
|
glNormal3f(dx, dy, dz)
|
||||||
|
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, s, 1 - t)
|
||||||
|
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, s, 1 - t)
|
||||||
|
glVertex3f(r * dx, r * dy, r * dz)
|
||||||
|
|
||||||
|
|
||||||
def belt(radius, cross, object, count):
|
def belt(radius, cross, object, count):
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
"mass": 5.97219e+24,
|
"mass": 5.97219e+24,
|
||||||
"rotation": 86400,
|
"rotation": 86400,
|
||||||
"division": 90,
|
"division": 90,
|
||||||
|
"normal": "earth_normal.jpg",
|
||||||
"atmosphere": {
|
"atmosphere": {
|
||||||
"cloud_texture": ["cloudmap.jpg", "cloudmap_small.jpg"],
|
"cloud_texture": ["cloudmap.jpg", "cloudmap_small.jpg"],
|
||||||
"diffuse_texture": "atmosphere_earth.png",
|
"diffuse_texture": "atmosphere_earth.png",
|
||||||
|
|
|
@ -62,7 +62,7 @@ def load_world(file, callback=lambda message, completion: None):
|
||||||
|
|
||||||
|
|
||||||
class World(object):
|
class World(object):
|
||||||
def __init__(self, file, callback):
|
def __init__(self, file, callback, options=None):
|
||||||
self.tracker = []
|
self.tracker = []
|
||||||
self.start = (0, 0, 0)
|
self.start = (0, 0, 0)
|
||||||
self.direction = (0, 0, 0)
|
self.direction = (0, 0, 0)
|
||||||
|
@ -73,6 +73,7 @@ class World(object):
|
||||||
self.tick = 0
|
self.tick = 0
|
||||||
|
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
|
self.options = options or {}
|
||||||
self._phase = 'Parsing configuration...'
|
self._phase = 'Parsing configuration...'
|
||||||
self._parse(file)
|
self._parse(file)
|
||||||
del self.callback # So it can't be used after loading finishes
|
del self.callback # So it can't be used after loading finishes
|
||||||
|
@ -177,7 +178,7 @@ class World(object):
|
||||||
if cheap:
|
if cheap:
|
||||||
object_id = compile(colourball, radius, division, division, texture)
|
object_id = compile(colourball, radius, division, division, texture)
|
||||||
else:
|
else:
|
||||||
if 'normal' in info:
|
if self.options.get('normal', False) and 'normal' in info:
|
||||||
object_id = compile(normal_sphere, radius, division, texture, info['normal'], lighting=lighting)
|
object_id = compile(normal_sphere, radius, division, texture, info['normal'], lighting=lighting)
|
||||||
else:
|
else:
|
||||||
object_id = compile(sphere, radius, division, division, texture, lighting=lighting)
|
object_id = compile(sphere, radius, division, division, texture, lighting=lighting)
|
||||||
|
|
Loading…
Reference in a new issue