home *** CD-ROM | disk | FTP | other *** search
- # ***** BEGIN LICENSE BLOCK *****
- # Version: MPL 1.1/GPL 2.0/LGPL 2.1
- #
- # The contents of this file are subject to the Mozilla Public License Version
- # 1.1 (the "License"); you may not use this file except in compliance with
- # the License. You may obtain a copy of the License at
- # http://www.mozilla.org/MPL/
- #
- # Software distributed under the License is distributed on an "AS IS" basis,
- # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- # for the specific language governing rights and limitations under the
- # License.
- #
- # The Original Code is the Python Computer Graphics Kit.
- #
- # The Initial Developer of the Original Code is Matthias Baas.
- # Portions created by the Initial Developer are Copyright (C) 2004
- # the Initial Developer. All Rights Reserved.
- #
- # Contributor(s):
- #
- # Alternatively, the contents of this file may be used under the terms of
- # either the GNU General Public License Version 2 or later (the "GPL"), or
- # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- # in which case the provisions of the GPL or the LGPL are applicable instead
- # of those above. If you wish to allow use of your version of this file only
- # under the terms of either the GPL or the LGPL, and not to allow others to
- # use your version of this file under the terms of the MPL, indicate your
- # decision by deleting the provisions above and replace them with the notice
- # and other provisions required by the GPL or the LGPL. If you do not delete
- # the provisions above, a recipient may use your version of this file under
- # the terms of any one of the MPL, the GPL or the LGPL.
- #
- # ***** END LICENSE BLOCK *****
- # $Id: glmaterial.py,v 1.6 2006/04/05 08:17:32 mbaas Exp $
-
- ## \file glmaterial.py
- ## Contains the GLMaterial class.
-
- import _core
- from cgtypes import *
- from _OpenGL.GL import *
- from _OpenGL.GLU import *
- import math
- import sys, os, os.path
- import _Image as Image
- import glslangparams
- from slots import *
-
- GLSLANG_VERTEX = _core.GLShader.ShaderType.VERTEX
- GLSLANG_FRAGMENT = _core.GLShader.ShaderType.FRAGMENT
-
- # GLTexture
- class GLTexture(_core.GLTexture):
- def __init__(self,
- imagename = "",
- image = None,
- mode = GL_DECAL,
- mipmap = True,
- mag_filter = GL_LINEAR,
- min_filter = GL_LINEAR,
- wrap_s = GL_REPEAT,
- wrap_t = GL_REPEAT,
- internalformat = GL_RGB,
- texenvcolor = vec4(1),
- transform = mat4(1),
- size = None,
- environment_map = False):
- """Constructor.
- """
-
- _core.GLTexture.__init__(self)
- self.imagename = imagename
- self.mode = mode
- self.mag_filter = mag_filter
- if mipmap and min_filter==GL_LINEAR:
- min_filter = GL_LINEAR_MIPMAP_LINEAR
- self.min_filter = min_filter
- self.wrap_s = wrap_s
- self.wrap_t = wrap_t
- self.texenvcolor = vec4(texenvcolor)
- self.transform = transform
- self.environment_map = environment_map
- self.mipmap = mipmap
- self.internalformat = internalformat
- self.size = size
-
- self._image = image
-
- # Remember the current working directory
- self._path = os.getcwd()
-
- # loadTexData
- def loadTexData(self):
- """Load and apply texture file.
- """
- # No image data set? Then use the file name and load the image...
- if self.image==None:
- if self.imagename=="":
- return
- print 'Loading "%s"...'%self.imagename,
- fullname = os.path.join(self._path, self.imagename)
- try:
- img = Image.open(fullname)
- self._passPILImage(img)
- except IOError, e:
- print "failed"
- print e
- return
- else:
- data = self.image
- if type(data)==str:
- # Raw image data as string
- w,h = self.size
- format = self.internalformat
- self.texData(w, h, format, GL_UNSIGNED_BYTE, data)
- else:
- # PIL image
- self._passPILImage(data)
-
-
- ## protected:
-
- def _passPILImage(self, img):
- """Pass a PIL image back to OpenGL.
-
- img must be a PIL image.
- The image is scaled to a power of 2 if necessary.
- """
- img = self._fitPILImage(img)
-
- w,h = img.size
-
- if img.mode=="RGB":
- format = GL_RGB
- elif img.mode=="RGBA":
- format = GL_RGBA
- else:
- raise RuntimeError, "Unsupported texture format (%s)"%img.mode
-
- self.texData(w, h, format, GL_UNSIGNED_BYTE, img.tostring())
-
-
- def _fitPILImage(self, img):
- """Scale the image to a power of 2 resolution.
-
- The image is scale to the user specified resolution. If no
- resolution was set, the next higher power of 2 resolution is used.
-
- If the image resolution is already a power of 2 then
- the input image is returned.
- """
- w,h = img.size
- if self.size==None:
- w2 = 2**int(math.ceil(math.log(w)/math.log(2)))
- h2 = 2**int(math.ceil(math.log(h)/math.log(2)))
- else:
- w2,h2 = self.size
-
- if w2!=w or h2!=h:
- img = img.resize((w2,h2), Image.BICUBIC)
-
- return img
-
-
- # "image" property...
-
- def _getImage(self):
- """Return the current image.
-
- This method is used for retrieving the \a image property.
-
- \return PIL Image (or None)
- """
- return self._image
-
- def _setImage(self, img):
- """Set a new texture image.
-
- This method is used for setting the \a image property.
-
- \param image PIL image or None
- """
- self._image = img
- # Assign the name again so that the image data will be reloaded
- self.imagename = self.imagename
-
- image = property(_getImage, _setImage, None, "Texture image")
-
- # GLShader
- class GLShader(_core.GLShader):
- """OpenGL 2 shader source file.
-
- """
-
- def __init__(self,
- shadertype,
- filename,
- cpp = None,
- cpperrstream = sys.stderr,
- **shaderparams):
- """Constructor.
- """
- _core.GLShader.__init__(self, shadertype, filename)
-
- # Extract the shader parameters...
- uniform,attribute,varying = glslangparams.glslangparams(filename, cpp=cpp, cpperrstream=cpperrstream)
-
- self._uniform = {}
- for type,name,arraysize,structname,struct in uniform:
- if type=="struct":
- print "Warning: structs are not yet supported"
- continue
- self._uniform[name] = (type,name,arraysize,structname,struct)
-
- for paramname in shaderparams:
- setattr(self, paramname, shaderparams[paramname])
-
- def __str__(self):
- if self.type==GLSLANG_VERTEX:
- stype = "vertex"
- else:
- stype = "fragment"
- return "<%s shader '%s'>"%(stype, os.path.basename(self.filename))
-
- # getattr
- def __getattr__(self, attr):
- """Return slot value or None if the slot wasn't created yet.
-
- An attempt an unknwon attribute (i.e. no uniform var) results
- in an error.
- """
- slot = self.__dict__.get("%s_slot"%attr, None)
- if slot!=None:
- return slot.getValue()
-
- if attr in self._uniform:
- return None
-
- raise AttributeError, "shader '%s' has no parameter '%s'"%(self.filename, attr)
-
- # setattr
- def __setattr__(self, attr, value):
- if attr in ["_uniform"] or attr[-5:]=="_slot":
- _core.GLShader.__setattr__(self, attr, value)
- return
-
- # Is attr a slot variable?
- slot = self.__dict__.get("%s_slot"%attr, None)
- if slot!=None:
- slot.setValue(value)
- return
-
- # Is it a parameter that has no value yet? then we must create
- # a new slot...
- uniform = getattr(self, "_uniform", [])
- if attr in uniform:
- slot = self._createSlot(attr, uniform[attr][0])
- slot.setValue(value)
- else:
- raise AttributeError, "shader '%s' has no parameter '%s'"%(self.filename, attr)
-
- # iterUniform
- def iterUniform(self):
- return self._uniform.itervalues()
-
- # _createSlot
- def _createSlot(self, param, type):
- """Create a slot for a parameter.
-
- param is the name of the parameter and type its OpenGL type (as str).
- """
- slot_lut = {"bool" : "BoolSlot",
- "float" : "DoubleSlot",
- "int" : "IntSlot",
- "bvec2" : "Vec3Slot",
- "bvec3" : "Vec3Slot",
- "bvec4" : "Vec4Slot",
- "ivec2" : "Vec3Slot",
- "ivec3" : "Vec3Slot",
- "bvec4" : "Vec4Slot",
- "vec2" : "Vec3Slot",
- "vec3" : "Vec3Slot",
- "vec4" : "Vec4Slot",
- "mat2" : "Mat3Slot",
- "mat3" : "Mat3Slot",
- "mat4" : "Mat4Slot",
- "sampler1D" : "IntSlot",
- "sampler2D" : "IntSlot",
- "sampler3D" : "IntSlot",
- "samplerCube" : "IntSlot",
- "sampler1DShadow" : "IntSlot",
- "sampler2DShadow" : "IntSlot"}
- slotname = slot_lut.get(type, None)
- if slotname==None:
- raise ValueError, "Invalid parameter type: %s"%type
- exec "slot = %s()"%slotname
- self.addSlot(param, slot)
- # Store the slot as <param>_slot
- setattr(self, "%s_slot"%param, slot)
- return slot
-
-
- # GLMaterial
- class GLMaterial(_core.GLMaterial):
-
- def __init__(self,
- name = "GLMaterial",
- ambient = (0.2, 0.2, 0.2, 1),
- diffuse = (0.7, 0.7, 0.7, 1),
- specular = (0,0,0,1),
- shininess = 0.0,
- emission = (0,0,0,1),
- blend_factors = None,
- texture = None,
- vertex_shader = None,
- fragment_shader = None,
- density=1.0):
- _core.GLMaterial.__init__(self, name, density)
-
- self.ambient = vec4(ambient)
- self.diffuse = vec4(diffuse)
- self.specular = vec4(specular)
- self.shininess = shininess
- self.emission = vec4(emission)
- if texture!=None:
- if isinstance(texture, _core.GLTexture):
- texture = [texture]
- self.setNumTextures(len(texture))
- for i,tex in enumerate(texture):
- self.setTexture(tex,i)
- if vertex_shader!=None:
- if isinstance(vertex_shader, _core.GLShader):
- vertex_shader = [vertex_shader]
- self.setNumVertexShaders(len(vertex_shader))
- for i,shd in enumerate(vertex_shader):
- self.setVertexShader(shd,i)
- if fragment_shader!=None:
- if isinstance(fragment_shader, _core.GLShader):
- fragment_shader = [fragment_shader]
- self.setNumFragmentShaders(len(fragment_shader))
- for i,shd in enumerate(fragment_shader):
- self.setFragmentShader(shd,i)
- if blend_factors!=None:
- self.blend_sfactor = blend_factors[0]
- self.blend_dfactor = blend_factors[1]
-