working textures!

completely overhauled models framework...
now loads Model, Mesh, Material, and Texture (plus TextureFile)

fixed a number of bugs/inflexibilities in gamedata xml parser

refactored the various modules to use "init" functions to better control when they get loaded (ie, before or after OpenGL init)
which it turns out is *very important*, because if the shaders and textures get loaded before OpenGL does, they don't work. go figure.
This commit is contained in:
cecilkorik 2011-06-17 19:54:49 -06:00
parent edd7630844
commit deaa55d535
14 changed files with 440 additions and 359 deletions

View file

@ -10,4 +10,8 @@ class asset_manager(object):
return go return go
def init():
global mgr
mgr = asset_manager() mgr = asset_manager()
mgr = None

View file

@ -1,23 +1,37 @@
<xml_binary_packing name="models"> <xml_binary_packing name="models">
<datatag name="mesh" multiple="yes">
<attribute name="id" data="string"/>
<datatag name="file" data="string" default=""/>
<datatag name="sprite" data="bool" default=""/>
<datatag name="centered_sprite" data="bool" default=""/>
</datatag>
<datatag name="model" multiple="yes"> <datatag name="model" multiple="yes">
<attribute name="id" data="string"/> <attribute name="id" data="string"/>
<datatag name="render" multiple="yes"> <datatag name="render" multiple="yes">
<attribute name="layer" data="int"/> <attribute name="layer" data="int"/>
<datatag name="model"> <datatag name="mesh">
<datatag name="file" data="string" default=""/> <datatag name="ref" data="string" default=""/>
<datatag name="xaxis_index" data="int" default="0"/> <datatag name="xaxis" data="int" default="0"/>
<datatag name="yaxis_index" data="int" default="1"/> <datatag name="yaxis" data="int" default="1"/>
<datatag name="zaxis_index" data="int" default="2"/> <datatag name="zaxis" data="int" default="2"/>
<datatag name="scale" data="float" default="1.0">
<attribute name="x" data="float" default="1.0"/>
<attribute name="y" data="float" default="1.0"/>
<attribute name="z" data="float" default="1.0"/>
</datatag>
</datatag>
<datatag name="material">
<datatag name="ref" data="string"/>
<datatag name="color" optional="yes">
<attribute name="r" data="float" default="1.0"/>
<attribute name="g" data="float" default="1.0"/>
<attribute name="b" data="float" default="1.0"/>
<attribute name="a" data="float" default="1.0"/>
</datatag> </datatag>
<datatag name="texture" data="string" optional="yes" multiple="yes">
<attribute name="layer" data="int" default="0"/>
</datatag> </datatag>
<datatag name="sprite" data="string" default=""/>
<datatag name="sprite_color" data="string" default=""/>
<datatag name="billboard" data="bool" default=""/> <datatag name="billboard" data="bool" default=""/>
<datatag name="beam_align" data="bool" default=""/> <datatag name="beam_align" data="bool" default=""/>
<datatag name="particle" data="bool" default=""/> <datatag name="particle" data="bool" default=""/>
<datatag name="scale" data="float" default="1.0"/>
</datatag> </datatag>
<datatag name="light" multiple="yes"> <datatag name="light" multiple="yes">
<datatag name="color" optional="yes"> <datatag name="color" optional="yes">

View file

@ -3,9 +3,16 @@
<attribute name="id" data="string"/> <attribute name="id" data="string"/>
<datatag name="file" data="string"/> <datatag name="file" data="string"/>
<datatag name="coords" optional="yes"> <datatag name="coords" optional="yes">
<attribute name="x" data="int" default="-1" optional="yes"/> <attribute name="x1" data="int" default="-1"/>
<attribute name="y" data="int" default="-1" optional="yes"/> <attribute name="y1" data="int" default="-1"/>
<attribute name="x2" data="int" default="-1"/>
<attribute name="y2" data="int" default="-1"/>
<attribute name="x" data="int" default="-1"/>
<attribute name="y" data="int" default="-1"/>
<attribute name="h" data="int" default="-1"/>
<attribute name="w" data="int" default="-1"/>
</datatag> </datatag>
<datatag name="uniform" data="bool" default=""/>
</datatag> </datatag>
<datatag name="material" multiple="yes"> <datatag name="material" multiple="yes">
<attribute name="id" data="string"/> <attribute name="id" data="string"/>

View file

@ -1,101 +1,14 @@
<models> <models>
<model id="m_star_yellow"> <mesh id="mesh_sprite">
<sprite/>
</mesh>
<mesh id="mesh_centered_sprite">
<centered_sprite/>
</mesh>
<model id="m_test">
<render layer="0"> <render layer="0">
<sprite>star_sprite_washout</sprite> <mesh><ref>mesh_sprite</ref><scale x="200" y="200"/></mesh>
<billboard/> <material><ref>mat_test</ref></material>
<sprite_color>1.0,1.0,0.5,1.0</sprite_color>
</render>
<render layer="1">
<sprite>star_sprite_main</sprite>
<billboard/>
<sprite_color>1.0,1.0,0.7,1.0</sprite_color>
</render>
<render layer="2">
<sprite>star_sprite_inner</sprite>
<billboard/>
<sprite_color>1.0,1.0,1.0,1.0</sprite_color>
</render>
<light>
<color r="1.0" g="0.95" b="0.8"/>
<sun/>
<basepower>1.0</basepower>
</light>
</model>
<model id="m_fi_kestrel">
<render layer="0">
<model><file>kestrel</file></model>
<texture>kestrel</texture>
</render>
</model>
<model id="m_bs_thor">
<render layer="0">
<model><file>thor</file></model>
</render>
<light>
<color r="1.0" g="0.0" b="0.0"/>
<basepower>0.5</basepower>
<attenuation quadratic="0.0001"/>
</light>
</model>
<model id="m_misc_navbuoy0">
<render layer="0">
<model><file>navbuoy</file></model>
</render>
<light>
<color r="0.0" g="1.0" b="0.0"/>
<basepower>1.0</basepower>
<attenuation quadratic="0.000001"/>
</light>
</model>
<model id="m_misc_navbuoy_test">
<render layer="0">
<model><file>navbuoy</file></model>
</render>
<light>
<color r="0.0" g="0.0" b="1.0"/>
<basepower>2.5</basepower>
<attenuation quadratic="0.00000001"/>
</light>
</model>
<model id="m_planet_bob">
<render layer="0">
<model><file>planet1</file></model>
<scale>100.0</scale>
</render>
</model>
<model id="p_soft">
<render layer="0">
<sprite>soft_particle</sprite>
<billboard/>
<particle/>
</render>
</model>
<model id="p_hard">
<render layer="0">
<sprite>hard_particle</sprite>
<billboard/>
<particle/>
</render>
</model>
<model id="p_medium">
<render layer="0">
<sprite>medium_particle</sprite>
<billboard/>
<particle/>
</render>
</model>
<model id="m_fr_spacetruck">
<render layer="0">
<model><file>kestrel</file></model>
<texture>kestrel</texture>
</render>
</model>
<model id="m_pl_bob">
<render layer="0">
<model><file>planet1</file></model>
<texture>planet1_earthy</texture>
<scale>1000.0</scale>
</render> </render>
</model> </model>
</models> </models>

View file

@ -1,16 +1,20 @@
<textures> <textures>
<texture id="t_black"> <texture id="t_black">
<file>tex/black.png</file> <file>tex/black.png</file>
<coords/>
<uniform/>
</texture> </texture>
<texture id="t_white"> <texture id="t_white">
<file>tex/white.png</file> <file>tex/white.png</file>
<uniform/>
</texture> </texture>
<texture id="tnm_flat"> <texture id="tnm_flat">
<file>tex/nm_flat.png</file> <file>tex/nm_flat.png</file>
<uniform/>
</texture> </texture>
<material id="m_blank"> <material id="mat_blank">
<texture ref="t_white" type="diffuse"/> <texture ref="t_white" type="diffuse"/>
<texture ref="tnm_black" type="normal"/> <texture ref="tnm_flat" type="normal"/>
</material> </material>
<texture id="t_test"> <texture id="t_test">
<file>tex/test1.png</file> <file>tex/test1.png</file>
@ -21,7 +25,7 @@
<texture id="t_test_plasma2"> <texture id="t_test_plasma2">
<file>tex/plasma2.png</file> <file>tex/plasma2.png</file>
</texture> </texture>
<material id="m_test"> <material id="mat_test">
<texture ref="t_test"> <texture ref="t_test"/>
</material> </material>
</textures> </textures>

View file

@ -1,16 +1,32 @@
class enum(object): class enum(object):
pass def __len__(self):
return len([x for x in dir(self) if x[0] != '_'])
def __iter__(self):
for name in sequence(self):
yield getattr(self, name)
def index(enumobj, name):
return getattr(enumobj, name)
def reverse(enumobj, value): def reverse(enumobj, value):
for name in dir(enumobj): for name in dir(enumobj):
if name[0] == '_': if name[0] == '_':
continue continue
if value == eval("enumobj.%s" % (name,)): if value == getattr(enumobj, name):
return name return name
return None return None
def sequence(enumobj):
retlist = []
for name in dir(enumobj):
if name[0] == '_':
continue
retlist.append((getattr(enumobj, name), name))
return [x[1] for x in sorted(retlist)]
# render types (for model.renderable_layer) # render types (for model.renderable_layer)
rt = enum() rt = enum()

View file

@ -25,4 +25,11 @@ class filemanager(object):
filename = self.path(*args) filename = self.path(*args)
return pygame.image.load(filename) return pygame.image.load(filename)
def canonize_path(self, path):
return path.lower()
def init():
global mgr
mgr = filemanager() mgr = filemanager()
mgr = None

View file

@ -24,6 +24,8 @@ class GameDataTagDef(object):
class GameDataNode(object): class GameDataNode(object):
def __init__(self): def __init__(self):
self.dict = {} self.dict = {}
self.missing = False
def __setitem__(self, name, val): def __setitem__(self, name, val):
self.dict[name] = val self.dict[name] = val
def __getitem__(self, name): def __getitem__(self, name):
@ -97,20 +99,24 @@ class XMLGameDataReader(object):
def create_attribute_def(self, tag): def create_attribute_def(self, tag):
return self.create_datatag_def(tag) return self.create_datatag_def(tag)
def construct_node(self, bin, xml): def construct_node(self, bin, xml, allow_missing=False):
node = GameDataNode() node = GameDataNode()
if isinstance(xml, MissingNode):
node.missing = True
value = None value = None
if bin.tag == 'datatag': if bin.tag == 'datatag':
df = self.create_datatag_def(bin) df = self.create_datatag_def(bin)
if df.type: if df.type:
value = xml.text value = xml.text
if type(xml) == MissingNode and df.opt: if df.type == 'bool':
# if tag exists, since it is a bool, that means it's True
value = not node.missing
elif (node.missing or value == None) and df.opt:
value = df.default value = df.default
elif type(xml) == MissingNode: elif (node.missing or value == None) and not allow_missing:
raise ValueError, "Missing value for mandatory tag %s" % (bin.get('name'),) raise ValueError, "Missing value for mandatory tag %s" % (bin.get('name'),)
elif df.type == 'bool': elif (node.missing or value == None):
# tag exists, and since it is a bool, that means it's True value = None
value = True
else: else:
value = self.value_as_type(value, df.type) value = self.value_as_type(value, df.type)
@ -121,8 +127,10 @@ class XMLGameDataReader(object):
value = xml.get(bin.get('name')) value = xml.get(bin.get('name'))
if value == None and df.opt: if value == None and df.opt:
value = df.default value = df.default
elif not value: elif not value and not allow_missing:
raise ValueError, "Missing value for mandatory tag %s" % (bin.get('name'),) raise ValueError, "Missing value for mandatory tag %s" % (bin.get('name'),)
elif not value:
value = None
else: else:
value = self.value_as_type(value, df.type) value = self.value_as_type(value, df.type)
@ -133,7 +141,7 @@ class XMLGameDataReader(object):
return node return node
def construct_recurse(self, bin, xml): def construct_recurse(self, bin, xml, allow_missing=False):
xmldict = {} xmldict = {}
tagdict = {} tagdict = {}
attrdict = {} attrdict = {}
@ -141,7 +149,7 @@ class XMLGameDataReader(object):
if bin.tag == 'xml_binary_packing': if bin.tag == 'xml_binary_packing':
node = GameDataNode() node = GameDataNode()
else: else:
node = self.construct_node(bin, xml) node = self.construct_node(bin, xml, allow_missing)
for child in bin.getchildren(): for child in bin.getchildren():
if child.tag == 'datatag': if child.tag == 'datatag':
@ -152,6 +160,9 @@ class XMLGameDataReader(object):
raise ValueError raise ValueError
xmlattrdict = {} xmlattrdict = {}
xmltagdict = {}
if not isinstance(xml, MissingNode):
for k, v in xml.items(): for k, v in xml.items():
if not k in attrdict: if not k in attrdict:
raise ValueError, "Key %s not a valid attribute: %s" % (k, attrdict.keys()) raise ValueError, "Key %s not a valid attribute: %s" % (k, attrdict.keys())
@ -159,13 +170,12 @@ class XMLGameDataReader(object):
binchild = attrdict[k] binchild = attrdict[k]
xmlchild = xml xmlchild = xml
xmlattrdict[k] = 0 xmlattrdict[k] = 0
subnode = self.construct_node(binchild, xml) subnode = self.construct_node(binchild, xml, allow_missing)
if subnode._def.multi: if subnode._def.multi:
node.add_multi(k, subnode) node.add_multi(k, subnode)
else: else:
node.add_single(k, subnode) node.add_single(k, subnode)
xmltagdict = {}
for child in xml.getchildren(): for child in xml.getchildren():
if not child.tag in tagdict: if not child.tag in tagdict:
raise ValueError raise ValueError
@ -173,17 +183,18 @@ class XMLGameDataReader(object):
binchild = tagdict[child.tag] binchild = tagdict[child.tag]
xmlchild = child xmlchild = child
xmltagdict[child.tag] = 0 xmltagdict[child.tag] = 0
subnode = self.construct_recurse(binchild, xmlchild) subnode = self.construct_recurse(binchild, xmlchild, allow_missing)
if subnode._def.multi: if subnode._def.multi:
node.add_multi(child.tag, subnode) node.add_multi(child.tag, subnode)
else: else:
node.add_single(child.tag, subnode) node.add_single(child.tag, subnode)
missing = MissingNode() missing = MissingNode()
for k in tagdict.keys(): for k in tagdict.keys():
if not k in xmltagdict: if not k in xmltagdict:
# Missing datatag # Missing datatag
subnode = self.construct_node(tagdict[k], missing) subnode = self.construct_recurse(tagdict[k], missing, isinstance(xml, MissingNode))
if not subnode._def.multi: if not subnode._def.multi:
node.add_single(k, subnode) node.add_single(k, subnode)
else: else:
@ -192,7 +203,7 @@ class XMLGameDataReader(object):
for k in attrdict.keys(): for k in attrdict.keys():
if not k in xmlattrdict: if not k in xmlattrdict:
# Missing attribute # Missing attribute
subnode = self.construct_node(attrdict[k], missing) subnode = self.construct_node(attrdict[k], missing, isinstance(xml, MissingNode))
if not subnode._def.multi: if not subnode._def.multi:
node.add_single(k, subnode) node.add_single(k, subnode)
else: else:

330
models.py
View file

@ -1,4 +1,9 @@
import enums import enums
import files
import gamedata
import pygame
from OpenGL.GL import *
from py3dutil import vect
class Vertex(object): class Vertex(object):
__slots__ = [ __slots__ = [
@ -8,38 +13,98 @@ class Vertex(object):
'c', # color '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): class Model_Manager(object):
def __init__(self): def __init__(self):
self.load_textypes() pass
self.load_textures()
self.load_materials() def create(self, mname):
self.load_models() return self.models[mname].instance()
def load_textypes():
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.dark] = 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)
def get_textype(self, textype): def get_textype(self, textype):
if isinstance(textype, TextureType): if isinstance(textype, TextureType):
return textype return textype
return self.textypes[textype] return self.textypes[textype]
def load_textures(self): def load(self):
gamedata.get('textures') 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): 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') gamedata.get('materials')
def load_textures(self):
gamedata.get('models')
mgr = Model_Manager() 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): class TextureType(object):
def __init__(self, texunit, texdim, wrap_s=GL_CLAMP, wrap_t=GL_CLAMP, mag=GL_LINEAR, min=GL_LINEAR) def __init__(self, texunit, texdim, wrap_s=GL_CLAMP, wrap_t=GL_CLAMP, mag=GL_LINEAR, min=GL_LINEAR):
self.texunit = texunit self.texunit = texunit
self.texdim = texdim self.texdim = texdim
self.wrap_s = wrap_s self.wrap_s = wrap_s
@ -64,32 +129,126 @@ class TextureType(object):
class Material(object): class Material(object):
def __init__(self): def __init__(self):
pass self.id = None
def attach_texture(self, textype, texid): self.textures = {}
textype = mgr.get_textype(textype) self.texcoords = self.texcoords_notimpl
textype.activate() 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
self.texid
class Texture(object): class Texture(object):
def __init__(self): def __init__(self):
pass self.id = None
def load(self, file): self.texid = None
img = files.mgr.png(file) self.uniform = False
texid, = glGenTextures(1) 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) / float(tf.w)
dest_w = (float(self.x + self.w) / float(tf.w)) - dest_x
dest_y = float(self.y) / float(tf.h)
dest_h = (float(self.y + self.h) / 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
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 self.id = texid
imgdata = pygame.image.tostring(img, "RGBA") imgdata = pygame.image.tostring(img, "RGBA")
imgr = img.get_rect() imgr = img.get_rect()
self.h = imgr.h
self.w = imgr.w
glBindTexture(textype.get_dimension(), texid) dimension = GL_TEXTURE_2D
glTexImage2D(textype.get_dimension(), 0, GL_RGBA8, imgr.w, imgr.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgdata) glBindTexture(dimension, texid)
glBindTexture(textype.get_dimension(), 0) glTexImage2D(dimension, 0, GL_RGBA8, imgr.w, imgr.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgdata)
glBindTexture(dimension, 0)
class Model(object):
class Mesh(object):
def __init__(self): def __init__(self):
self.vertexes = [] self.vertexes = []
@ -101,26 +260,105 @@ class Model(object):
def unset_rotation(self): def unset_rotation(self):
glPopMatrix() glPopMatrix()
def bind_textures(self): def draw(self, texcoord):
glBindTexture(GL_TEXTURE_2D
def unbind_textures(self):
def draw(self):
self.bind_textures()
glBegin(GL_TRIANGLES) glBegin(GL_TRIANGLES)
for v in self.vertexes: for v in self.vertexes:
self.draw_vertex(v) self.draw_vertex(v, texcoord)
glEnd(GL_TRIANGLES) glEnd()
self.unbind_textures()
def draw_vertex(self, v): def draw_vertex(self, v, texcoord):
glColor3f(v.c[0], v.c[1], v.c[2]) glColor3f(v.c[0], v.c[1], v.c[2])
glNormal3f(v.n.x, v.n.y, v.n.z) glNormal3f(v.n.x, v.n.y, v.n.z)
glTexCoord2f(v.t[0], v.t[1]) glTexCoord2f(*texcoord(v.t[0], v.t[1]))
glVertex3f(v.v.x, v.v.y, v.v.z) 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 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()
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]
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.0, 300.0, 0.0)
glScalef(*self.scale)
self.mesh.draw(self.material.texcoords)
glPopMatrix()
class Sprite(object): class Sprite(object):
def __init__(self): def __init__(self):
@ -143,4 +381,12 @@ class Sprite(object):
self.corners = vl self.corners = vl
self.vertexes = [tl, bl, tr, bl, tr, br] self.vertexes = [tl, bl, tr, bl, tr, br]
def set_texture( def set_texture(self):
pass
def init():
global mgr
mgr = Model_Manager()
mgr.load()
mgr = None

70
roc.py
View file

@ -1,11 +1,9 @@
import pygame import pygame
from pygame.locals import * import files
import gamedata
import gametimer
import video import video
import shader import shader
import inputs import models
from OpenGL.GL import * import roc_main
def init2d(): def init2d():
@ -16,6 +14,8 @@ def init3d():
def init(videoinit): def init(videoinit):
pygame.init() pygame.init()
files.init()
shader.init()
size = width, height = (1600,1200) size = width, height = (1600,1200)
size = width, height = (1024,768) size = width, height = (1024,768)
@ -24,63 +24,7 @@ def init(videoinit):
videoinit() videoinit()
video.enable_vsync() video.enable_vsync()
def test_frame(): models.init()
from PIL import Image
# pink triangle
glBegin(GL_TRIANGLE_STRIP)
glNormal3f(0.0, 0.0, 1.0)
glColor4f(1.0, 0.0, 0.5, 1.0)
glVertex3f( 20.0, 50.0, 1.0)
glVertex3f( 20.0, 600.0, 1.0)
glVertex3f( 400.0, 50.0, 1.0)
glEnd()
# yellow square
glBegin(GL_TRIANGLE_STRIP)
glNormal3f(0.0, 0.0, 1.0)
glColor4f(1.0, 1.0, 0.0, 1.0)
glVertex3f( 150.0, 20.0, -50.0)
glVertex3f( 150.0, 400.0, -50.0)
glVertex3f( 360.0, 20.0, -50.0)
glVertex3f( 360.0, 400.0, -50.0)
glEnd()
# texture test
glBegin(GL_TRIANGLE_STRIP)
glNormal3f(0.0, 0.0, 1.0)
glColor4f(1.0, 1.0, 1.0, 1.0)
glVertex3f( 500.0, 300.0, 5.0)
glVertex3f( 500.0, 500.0, 5.0)
glVertex3f( 700.0, 300.0, 5.0)
glVertex3f( 700.0, 500.0, 5.0)
glEnd()
def main(): def main():
gametimer.start_loop() roc_main.mainloop()
while True:
events = pygame.event.get()
gametimer.next_frame()
pygame.event.pump()
for ev in events:
if ev.type == QUIT:
inputs.add_command('exit')
break
elif ev.type == KEYUP:
inputs.keyup(ev.key)
elif ev.type == KEYDOWN:
inputs.keydown(ev.key)
#elif ev.type == VIDEOEXPOSE:
# video.force_redraw()
elif ev.type in (MOUSEBUTTONDOWN, MOUSEBUTTONUP):
pass
if 'exit' in inputs.commands:
break
video.predraw()
test_frame()
video.next_frame()

View file

@ -212,4 +212,8 @@ class shader_manager(object):
for shader in shaders.shader: for shader in shaders.shader:
self.initshadersources.append((shader['id'], shader['vertex'], shader['fragment'])) self.initshadersources.append((shader['id'], shader['vertex'], shader['fragment']))
def init():
global mgr
mgr = shader_manager() mgr = shader_manager()
mgr = None

View file

@ -1,69 +0,0 @@
import files
import os
from OpenGL.GL import *
from py3ds.example.gltexture import Texture
class renderable_sprite(object):
"""
Internal class to create a textured quad for a sprite to live on.
Multiple sprites can use the same sprite_tex if the graphic they want to
display is the same.
"""
def __init__(self):
self.gltex = None
self.gllist = None
self.texfile = None
self.scale = 1.0
def load_name(self, name):
self.texfile = files.mgr.open(os.path.join('sprite', name + '.png'))
def set_file(self, fileobj):
self.texfile = fileobj
def update(self):
pass
def render(self):
if self.gltex == None:
self.gltex = Texture(self.texfile)
self.texfile.close()
self.texfile = None
if self.gllist == None:
glPushMatrix()
#glLoadIdentity()
dl = glGenLists(1)
if dl == 0:
raise GLError, "cannot allocate display list"
glNewList(dl, GL_COMPILE)
glEnable(GL_BLEND)
glEnable(GL_DEPTH_TEST)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
self.gltex.enable()
self.gltex.bind()
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
glBegin(GL_TRIANGLE_STRIP)
glNormal3f(1.0, 0.0, 0.0)
glTexCoord2f(1.0, 1.0); glVertex3f( 0.0, 1.0, 1.0)
glTexCoord2f(0.0, 1.0); glVertex3f( 0.0, 1.0, -1.0)
glTexCoord2f(1.0, 0.0); glVertex3f(-0.0, -1.0, 1.0)
glTexCoord2f(0.0, 0.0); glVertex3f(-0.0, -1.0, -1.0)
glEnd()
self.gltex.disable()
glDisable(GL_BLEND)
glEndList()
self.gllist = dl
glPopMatrix()
glCallList(self.gllist)
class sprite_manager(object):
def __init__(self):
self.sprite_cache = {}
def get(self, name):
if name in self.sprite_cache:
return self.sprite_cache[name]
s = renderable_sprite()
s.load_name(name)
self.sprite_cache[name] = s
return s
mgr = sprite_manager()

View file

@ -1,21 +0,0 @@
class texture_wrapper(object):
def __init__(self):
pass
def load_name(self, name):
pass
class texture_manager(object):
def __init__(self):
self.texture_cache = {}
def get(self, name):
if name in self.texture_cache:
return self.texture_cache[name]
t = texture_wrapper()
t.load_name(name)
self.texture_cache[name] = t
return t
mgr = texture_manager()

View file

@ -70,6 +70,7 @@ def init2d():
glDepthFunc(GL_GEQUAL) glDepthFunc(GL_GEQUAL)
glEnable(GL_BLEND) glEnable(GL_BLEND)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (0.3, 0.3, 0.3, 1.0))
shader.mgr.load() shader.mgr.load()
shader.mgr.init_gl() shader.mgr.init_gl()