##################################################################### # -*- coding: iso-8859-1 -*- # # # # Frets on Fire # # Copyright (C) 2006 Sami Kyöstilä # # # # This program is free software; you can redistribute it and/or # # modify it under the terms of the GNU General Public License # # as published by the Free Software Foundation; either version 2 # # of the License, or (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program; if not, write to the Free Software # # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # # MA 02110-1301, USA. # ##################################################################### from OpenGL.GL import * import Collada class Mesh: def __init__(self, fileName): self.doc = Collada.DaeDocument() self.doc.LoadDocumentFromFile(fileName) self.geoms = {} self.fullGeoms = {} def _unflatten(self, array, stride): return [tuple(array[i * stride : (i + 1) * stride]) for i in range(len(array) / stride)] def setupLight(self, light, n, pos): l = light.techniqueCommon glEnable(GL_LIGHTING) glEnable(GL_LIGHT0 + n) glLightfv(GL_LIGHT0 + n, GL_POSITION, (pos[0], pos[1], pos[2], 0.0)) glLightfv(GL_LIGHT0 + n, GL_DIFFUSE, (l.color[0], l.color[1], l.color[2], 0.0)) glLightfv(GL_LIGHT0 + n, GL_AMBIENT, (0.0, 0.0, 0.0, 0.0)) def setupMaterial(self, material): for m in material.techniqueCommon.iMaterials: if m.object: for fx in m.object.iEffects: if fx.object: shader = fx.object.profileCommon.technique.shader if isinstance(shader, Collada.DaeFxShadePhong): glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shader.shininess.float) glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, shader.ambient.color.rgba) glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, shader.diffuse.color.rgba) glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, shader.specular.color.rgba) def render(self, geomName = None): if geomName in self.fullGeoms: glCallList(self.fullGeoms[geomName]) return # Prepare a new list for all the geometry if not self.geoms: for geom in self.doc.geometriesLibrary.items: self.geoms[geom.name] = glGenLists(1) glNewList(self.geoms[geom.name], GL_COMPILE) for prim in geom.data.primitives: maxOffset = vertexOffset = normalOffset = 0 vertexOffset = None normalOffset = None texcoordOffset = None vertices = None normals = None texcoords = None for input in prim.inputs: maxOffset = max(maxOffset, input.offset) if input.semantic == "VERTEX": vertexOffset = input.offset vertices = geom.data.FindSource(geom.data.vertices.FindInput("POSITION")) assert vertices.techniqueCommon.accessor.stride == 3 vertices = self._unflatten(vertices.source.data, vertices.techniqueCommon.accessor.stride) elif input.semantic == "NORMAL": normalOffset = input.offset normals = geom.data.FindSource(input) normals = self._unflatten(normals.source.data, 3) elif input.semantic == "TEXCOORD": texcoordOffset = input.offset texcoords = geom.data.FindSource(input) texcoords = self._unflatten(texcoords.source.data, 2) if normalOffset is None: normals = geom.data.FindSource(geom.data.vertices.FindInput("NORMAL")) normals = self._unflatten(normals.source.data, 3) normalOffset = vertexOffset def drawElement(indices, offset, array, func): if offset is not None: func(*array[indices[offset]]) if hasattr(prim, "polygons"): for poly in prim.polygons: glBegin(GL_POLYGON) for indices in self._unflatten(poly, maxOffset + 1): drawElement(indices, normalOffset, normals, glNormal3f) drawElement(indices, texcoordOffset, texcoords, glTexCoord2f) drawElement(indices, vertexOffset, vertices, glVertex3f) glEnd() elif hasattr(prim, "triangles"): glBegin(GL_TRIANGLES) for indices in self._unflatten(prim.triangles, maxOffset + 1): drawElement(indices, normalOffset, normals, glNormal3f) drawElement(indices, texcoordOffset, texcoords, glTexCoord2f) drawElement(indices, vertexOffset, vertices, glVertex3f) glEnd() glEndList() # Prepare a new display list for this particular geometry self.fullGeoms[geomName] = glGenLists(1) glNewList(self.fullGeoms[geomName], GL_COMPILE) if self.geoms: # setup lights for scene in self.doc.visualScenesLibrary.items: for node in scene.nodes: for n, light in enumerate(node.iLights): if light.object: # TODO: hierarchical node transformation, other types of lights pos = [0.0, 0.0, 0.0, 1.0] for t in node.transforms: if t[0] == "translate": pos = t[1] self.setupLight(light.object, n, pos) # render geometry for scene in self.doc.visualScenesLibrary.items: for node in scene.nodes: if geomName is not None and node.name != geomName: continue for geom in node.iGeometries: if geom.object: #for mat in geom.bindMaterials: # self.setupMaterial(mat) glPushMatrix() for t in node.transforms: if t[0] == "translate": glTranslatef(*t[1]) elif t[0] == "rotate": glRotatef(t[1][3], t[1][0], t[1][1], t[1][2]) elif t[0] == "scale": glScalef(*t[1]) if geom.object.name in self.geoms: glCallList(self.geoms[geom.object.name]) glPopMatrix() glDisable(GL_LIGHTING) for n in range(8): glDisable(GL_LIGHT0 + n) glEndList() # Render the new list self.render(geomName) def find(self, geomName = None): found = False if self.geoms: # render geometry for scene in self.doc.visualScenesLibrary.items: for node in scene.nodes: if geomName is not None and node.name != geomName: continue found = True return found