roc/models.py
cecilkorik 49f4256439 reorganized models.py
started adding universe basics
started adding gameobj basics
2011-06-18 22:59:58 -06:00

370 lines
9.4 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.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()
glTranslatef(500.5, 300.5, 0.0)
glScalef(*self.scale)
self.mesh.draw(self.material.texcoords)
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