specific hacks in video.py Added a config file (settings.cfg) Added functionality for saving last used window position! Added displaylists to models.py Broke fonts (temporarily)
376 lines
9.6 KiB
Python
Executable file
376 lines
9.6 KiB
Python
Executable file
import enums
|
|
import files
|
|
import gamedata
|
|
import pygame
|
|
from OpenGL.GL import *
|
|
from py3dutil import vect
|
|
|
|
class Vertex(object):
|
|
__slots__ = [
|
|
'v', # vertex coordinates
|
|
'n', # normal
|
|
't', # texture coordinates
|
|
'c', # color
|
|
]
|
|
|
|
def __init__(self, v, n, t, c):
|
|
self.v = v
|
|
self.n = n
|
|
self.t = t
|
|
self.c = c
|
|
|
|
class Model_Manager(object):
|
|
def __init__(self):
|
|
pass
|
|
|
|
def create(self, mname):
|
|
return self.models[mname].instance()
|
|
|
|
|
|
def get_textype(self, textype):
|
|
if isinstance(textype, TextureType):
|
|
return textype
|
|
return self.textypes[textype]
|
|
|
|
def load(self):
|
|
self.load_textypes()
|
|
self.load_textures()
|
|
self.load_materials()
|
|
self.load_models()
|
|
|
|
def load_textypes(self):
|
|
self.textypes = {}
|
|
self.textypes[enums.tt.diffuse] = TextureType(GL_TEXTURE0, GL_TEXTURE_2D, GL_CLAMP, GL_CLAMP, GL_NEAREST, GL_NEAREST)
|
|
self.textypes[enums.tt.emissive] = TextureType(GL_TEXTURE1, GL_TEXTURE_2D)
|
|
self.textypes[enums.tt.specular] = TextureType(GL_TEXTURE2, GL_TEXTURE_2D)
|
|
self.textypes[enums.tt.normal] = TextureType(GL_TEXTURE3, GL_TEXTURE_2D)
|
|
|
|
for tt in self.textypes.values():
|
|
tt.initialize()
|
|
|
|
|
|
def load_textures(self):
|
|
texdata = gamedata.get('textures')
|
|
self.texture_files = {}
|
|
self.texture_ids = {}
|
|
self.textures = {}
|
|
self.materials = {}
|
|
for texd in texdata.texture:
|
|
fp = files.mgr.canonize_path(texd['file'])
|
|
if not fp in self.texture_files:
|
|
tf = TextureFile()
|
|
tf.load(fp)
|
|
self.texture_files[fp] = tf
|
|
self.texture_ids[tf.id] = tf
|
|
else:
|
|
tf = self.texture_files[fp]
|
|
to = Texture()
|
|
to.load(texd, tf)
|
|
self.textures[to.id] = to
|
|
|
|
for matd in texdata.material:
|
|
mo = Material()
|
|
mo.load(matd)
|
|
self.materials[mo.id] = mo
|
|
|
|
|
|
def load_meshes(self):
|
|
"ignored!!! meshes are contained in models.xml for now"
|
|
return
|
|
gamedata.get('meshes')
|
|
|
|
def load_materials(self):
|
|
"ignored!!! materials are contained in textures.xml for now"
|
|
return
|
|
gamedata.get('materials')
|
|
|
|
|
|
def load_models(self):
|
|
mdldata = gamedata.get('models')
|
|
self.meshes = {}
|
|
self.models = {}
|
|
for meshdata in mdldata.mesh:
|
|
if meshdata['sprite']:
|
|
mesh = SpriteMesh.singleton()
|
|
elif meshdata['centered_sprite']:
|
|
mesh = SpriteMeshCentered.singleton()
|
|
else:
|
|
mesh = Mesh.factory(meshdata)
|
|
mgr.meshes[meshdata['id']] = mesh
|
|
|
|
for modeldata in mdldata.model:
|
|
model = Model()
|
|
model.load(modeldata)
|
|
mgr.models[modeldata['id']] = model
|
|
|
|
class TextureType(object):
|
|
def __init__(self, texunit, texdim, wrap_s=GL_CLAMP, wrap_t=GL_CLAMP, mag=GL_LINEAR, min=GL_LINEAR):
|
|
self.texunit = texunit
|
|
self.texdim = texdim
|
|
self.wrap_s = wrap_s
|
|
self.wrap_t = wrap_t
|
|
self.mag = mag
|
|
self.min = min
|
|
|
|
def initialize(self):
|
|
glActiveTexture(self.texunit)
|
|
glTexParameterf(self.texdim, GL_TEXTURE_WRAP_S, self.wrap_s)
|
|
glTexParameterf(self.texdim, GL_TEXTURE_WRAP_T, self.wrap_t)
|
|
glTexParameterf(self.texdim, GL_TEXTURE_MAG_FILTER, self.mag)
|
|
glTexParameterf(self.texdim, GL_TEXTURE_MIN_FILTER, self.min)
|
|
|
|
def get_dimension(self):
|
|
return self.texdim
|
|
|
|
def activate(self):
|
|
glActiveTexture(self.texunit)
|
|
|
|
|
|
class Texture(object):
|
|
def __init__(self):
|
|
self.id = None
|
|
self.texid = None
|
|
self.uniform = False
|
|
self.x = None
|
|
self.y = None
|
|
self.h = None
|
|
self.w = None
|
|
|
|
|
|
def texcoords_subset(self, u, v):
|
|
tf = mgr.texture_ids[self.texid]
|
|
dest_x = (float(self.x)-0.0) / float(tf.w)
|
|
dest_w = ((float(self.x + self.w)+0.3) / float(tf.w)) - dest_x
|
|
dest_y = (float(self.y)-0.3) / float(tf.h)
|
|
dest_h = ((float(self.y + self.h)+0.0) / float(tf.h)) - dest_y
|
|
return (dest_x + (u * dest_w), dest_y + (v * dest_h))
|
|
|
|
def texcoords_direct(self, u, v):
|
|
return (u, v)
|
|
|
|
def load(self, data, tf):
|
|
self.id = data['id']
|
|
self.texid = tf.id
|
|
self.uniform = data['uniform']
|
|
c = data.coords
|
|
if c['x'] != -1 and c['y'] != -1 and c['h'] != -1 and c['w'] != -1:
|
|
self.x = c['x']
|
|
self.y = c['y']
|
|
self.w = c['w']
|
|
self.h = c['h']
|
|
assert self.x < tf.w and self.w < tf.w and self.y < tf.h and self.h < tf.h
|
|
self.texcoords = self.texcoords_subset
|
|
elif c['x1'] != -1 and c['y1'] != -1 and c['x2'] != -1 and c['y2'] != -1:
|
|
self.x = c['x1']
|
|
self.y = c['y1']
|
|
self.w = c['x2'] - self.x
|
|
self.h = c['y2'] - self.y
|
|
assert self.x < tf.w and self.w < tf.w and self.y < tf.h and self.h < tf.h
|
|
self.texcoords = self.texcoords_subset
|
|
else:
|
|
self.x = 0
|
|
self.y = 0
|
|
self.w = tf.w
|
|
self.h = tf.h
|
|
self.texcoords = self.texcoords_direct
|
|
#self.texcoords = self.texcoords_subset
|
|
|
|
def bind(self):
|
|
glBindTexture(GL_TEXTURE_2D, self.texid)
|
|
|
|
class TextureFile(object):
|
|
def __init__(self):
|
|
self.id = None
|
|
self.filename = None
|
|
self.h = None
|
|
self.w = None
|
|
|
|
def load(self, filename):
|
|
self.filename = filename
|
|
img = files.mgr.png(filename)
|
|
texid = glGenTextures(1)
|
|
print "Generated texture id %s" % (texid,)
|
|
|
|
self.id = texid
|
|
|
|
imgdata = pygame.image.tostring(img, "RGBA")
|
|
imgr = img.get_rect()
|
|
self.h = imgr.h
|
|
self.w = imgr.w
|
|
|
|
dimension = GL_TEXTURE_2D
|
|
glBindTexture(dimension, texid)
|
|
glTexImage2D(dimension, 0, GL_RGBA8, imgr.w, imgr.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgdata)
|
|
glBindTexture(dimension, 0)
|
|
|
|
|
|
|
|
class Material(object):
|
|
def __init__(self):
|
|
self.id = None
|
|
self.textures = {}
|
|
self.texcoords = self.texcoords_notimpl
|
|
self.texcoords_uniform = self.texcoords_notimpl
|
|
|
|
def texcoords_notimpl(self, u, v):
|
|
raise NotImplementedError("No textures were associated with this material.")
|
|
|
|
def bind(self):
|
|
for tt in enums.tt:
|
|
if tt in self.textures:
|
|
tto = mgr.get_textype(tt)
|
|
tto.initialize()
|
|
tex = self.textures[tt]
|
|
tex.bind()
|
|
|
|
def load(self, data):
|
|
self.id = data['id']
|
|
prevtex = None
|
|
for tex in data.texture:
|
|
try:
|
|
texobj = mgr.textures[tex['ref']]
|
|
except KeyError:
|
|
raise KeyError("""Material "%s" references invalid %s texture "%s".""" % (self.id, tex['type'], tex['ref']))
|
|
|
|
typeidx = enums.index(enums.tt, tex['type'])
|
|
self.textures[typeidx] = texobj
|
|
|
|
if texobj.uniform:
|
|
if self.texcoords_uniform == self.texcoords_notimpl:
|
|
self.texcoords_uniform = texobj.texcoords
|
|
else:
|
|
if prevtex:
|
|
assert texobj.texcoords(0.0, 0.0) == prevtex.texcoords(0.0, 0.0) and texobj.texcoords(1.0, 1.0) == prevtex.texcoords(1.0, 1.0)
|
|
if self.texcoords == self.texcoords_notimpl:
|
|
self.texcoords = texobj.texcoords
|
|
prevtex = texobj
|
|
|
|
print self.textures
|
|
|
|
|
|
|
|
class Mesh(object):
|
|
def __init__(self):
|
|
self.vertexes = []
|
|
|
|
def set_rotation(self):
|
|
glPushMatrix()
|
|
glMultMatrixf(self.rot.get_matrix())
|
|
|
|
def unset_rotation(self):
|
|
glPopMatrix()
|
|
|
|
def draw(self, texcoord):
|
|
glBegin(GL_TRIANGLES)
|
|
for v in self.vertexes:
|
|
self.draw_vertex(v, texcoord)
|
|
glEnd()
|
|
|
|
def draw_vertex(self, v, texcoord):
|
|
glColor3f(v.c[0], v.c[1], v.c[2])
|
|
glNormal3f(v.n.x, v.n.y, v.n.z)
|
|
glTexCoord2f(*texcoord(v.t[0], v.t[1]))
|
|
glVertex3f(v.v.x, v.v.y, v.v.z)
|
|
|
|
|
|
|
|
class SpriteMesh(Mesh):
|
|
_SINGLETON = None
|
|
|
|
def __init__(self):
|
|
Mesh.__init__(self)
|
|
self.vertexes = [
|
|
Vertex(vect(0.0, 0.0, 0.0), vect(0.0, 0.0, 1.0), (0.0, 0.0), (1.0, 1.0, 1.0)),
|
|
Vertex(vect(0.0, 1.0, 0.0), vect(0.0, 0.0, 1.0), (0.0, 1.0), (1.0, 1.0, 1.0)),
|
|
Vertex(vect(1.0, 0.0, 0.0), vect(0.0, 0.0, 1.0), (1.0, 0.0), (1.0, 1.0, 1.0)),
|
|
Vertex(vect(1.0, 0.0, 0.0), vect(0.0, 0.0, 1.0), (1.0, 0.0), (1.0, 1.0, 1.0)),
|
|
Vertex(vect(0.0, 1.0, 0.0), vect(0.0, 0.0, 1.0), (0.0, 1.0), (1.0, 1.0, 1.0)),
|
|
Vertex(vect(1.0, 1.0, 0.0), vect(0.0, 0.0, 1.0), (1.0, 1.0), (1.0, 1.0, 1.0)),
|
|
]
|
|
|
|
@classmethod
|
|
def return_singleton(cls):
|
|
return cls._SINGLETON
|
|
|
|
@classmethod
|
|
def singleton(cls):
|
|
cls._SINGLETON = cls()
|
|
cls.singleton = cls.return_singleton
|
|
return cls._SINGLETON
|
|
|
|
|
|
class SpriteMeshCentered(SpriteMesh):
|
|
def __init__(self):
|
|
SpriteMesh.__init__(self)
|
|
self.vertexes = [
|
|
Vertex(vect(-0.5, -0.5, 0.0), vect(0.0, 0.0, 1.0), (0.0, 0.0), (1.0, 1.0, 1.0)),
|
|
Vertex(vect( 0.5, -0.5, 0.0), vect(0.0, 0.0, 1.0), (1.0, 0.0), (1.0, 1.0, 1.0)),
|
|
Vertex(vect(-0.5, 0.5, 0.0), vect(0.0, 0.0, 1.0), (0.0, 1.0), (1.0, 1.0, 1.0)),
|
|
Vertex(vect( 0.5, -0.5, 0.0), vect(0.0, 0.0, 1.0), (1.0, 0.0), (1.0, 1.0, 1.0)),
|
|
Vertex(vect(-0.5, 0.5, 0.0), vect(0.0, 0.0, 1.0), (0.0, 1.0), (1.0, 1.0, 1.0)),
|
|
Vertex(vect( 0.5, 0.5, 0.0), vect(0.0, 0.0, 1.0), (1.0, 1.0), (1.0, 1.0, 1.0)),
|
|
]
|
|
|
|
class RenderLayer(object):
|
|
def __init__(self, layernum):
|
|
self.id = layernum
|
|
self.mesh = None
|
|
self.material = None
|
|
self.color = [1.0, 1.0, 1.0, 1.0]
|
|
self.scale = [1.0, 1.0, 1.0]
|
|
self.displaylist = None
|
|
self.anim = "idle"
|
|
|
|
def load(self, layerdata):
|
|
meshdata = layerdata.mesh
|
|
matdata = layerdata.material
|
|
self.mesh = mgr.meshes[meshdata['ref']]
|
|
self.material = mgr.materials[matdata['ref']]
|
|
self.color = [matdata.color['r'], matdata.color['g'], matdata.color['b'], matdata.color['a']]
|
|
self.scale = [meshdata.scale['x'], meshdata.scale['y'], meshdata.scale['z']]
|
|
self.scale = [x * meshdata['scale'] for x in self.scale]
|
|
|
|
def render(self):
|
|
self.material.bind()
|
|
glPushMatrix()
|
|
glScalef(*self.scale)
|
|
|
|
if self.displaylist == None:
|
|
self.displaylist = glGenLists(1)
|
|
glNewList(self.displaylist, GL_COMPILE)
|
|
self.mesh.draw(self.material.texcoords)
|
|
glEndList()
|
|
|
|
glCallList(self.displaylist)
|
|
glPopMatrix()
|
|
|
|
|
|
|
|
class Model(object):
|
|
def __init__(self):
|
|
self.layers = []
|
|
|
|
def load(self, data):
|
|
tmplayers = []
|
|
for rend in data.render:
|
|
layernum = rend['layer']
|
|
rl = RenderLayer(layernum)
|
|
rl.load(rend)
|
|
tmplayers.append((layernum, rl))
|
|
|
|
for ln, rl in sorted(tmplayers):
|
|
self.layers.append(rl)
|
|
|
|
def instance(self):
|
|
return self
|
|
|
|
def render(self):
|
|
for layer in self.layers:
|
|
layer.render()
|
|
|
|
def init():
|
|
global mgr
|
|
mgr = Model_Manager()
|
|
mgr.load()
|
|
|
|
mgr = None
|