home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / lib / site-packages / cgkit / glmaterial.py < prev    next >
Encoding:
Python Source  |  2007-01-11  |  11.4 KB  |  347 lines

  1. # ***** BEGIN LICENSE BLOCK *****
  2. # Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. #
  4. # The contents of this file are subject to the Mozilla Public License Version
  5. # 1.1 (the "License"); you may not use this file except in compliance with
  6. # the License. You may obtain a copy of the License at
  7. # http://www.mozilla.org/MPL/
  8. #
  9. # Software distributed under the License is distributed on an "AS IS" basis,
  10. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. # for the specific language governing rights and limitations under the
  12. # License.
  13. #
  14. # The Original Code is the Python Computer Graphics Kit.
  15. #
  16. # The Initial Developer of the Original Code is Matthias Baas.
  17. # Portions created by the Initial Developer are Copyright (C) 2004
  18. # the Initial Developer. All Rights Reserved.
  19. #
  20. # Contributor(s):
  21. #
  22. # Alternatively, the contents of this file may be used under the terms of
  23. # either the GNU General Public License Version 2 or later (the "GPL"), or
  24. # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  25. # in which case the provisions of the GPL or the LGPL are applicable instead
  26. # of those above. If you wish to allow use of your version of this file only
  27. # under the terms of either the GPL or the LGPL, and not to allow others to
  28. # use your version of this file under the terms of the MPL, indicate your
  29. # decision by deleting the provisions above and replace them with the notice
  30. # and other provisions required by the GPL or the LGPL. If you do not delete
  31. # the provisions above, a recipient may use your version of this file under
  32. # the terms of any one of the MPL, the GPL or the LGPL.
  33. #
  34. # ***** END LICENSE BLOCK *****
  35. # $Id: glmaterial.py,v 1.6 2006/04/05 08:17:32 mbaas Exp $
  36.  
  37. ## \file glmaterial.py
  38. ## Contains the GLMaterial class.
  39.  
  40. import _core
  41. from cgtypes import *
  42. from _OpenGL.GL import *
  43. from _OpenGL.GLU import *
  44. import math
  45. import sys, os, os.path
  46. import _Image as Image
  47. import glslangparams
  48. from slots import *
  49.  
  50. GLSLANG_VERTEX = _core.GLShader.ShaderType.VERTEX
  51. GLSLANG_FRAGMENT = _core.GLShader.ShaderType.FRAGMENT
  52.  
  53. # GLTexture
  54. class GLTexture(_core.GLTexture):
  55.     def __init__(self,
  56.                  imagename = "",
  57.                  image = None,
  58.                  mode = GL_DECAL,
  59.                  mipmap = True,
  60.                  mag_filter = GL_LINEAR,
  61.                  min_filter = GL_LINEAR,
  62.                  wrap_s = GL_REPEAT,
  63.                  wrap_t = GL_REPEAT,
  64.                  internalformat = GL_RGB,
  65.                  texenvcolor = vec4(1),
  66.                  transform = mat4(1),
  67.                  size = None,
  68.                  environment_map = False):
  69.         """Constructor.
  70.         """
  71.         
  72.         _core.GLTexture.__init__(self)
  73.         self.imagename = imagename
  74.         self.mode = mode
  75.         self.mag_filter = mag_filter
  76.         if mipmap and min_filter==GL_LINEAR:
  77.             min_filter = GL_LINEAR_MIPMAP_LINEAR
  78.         self.min_filter = min_filter
  79.         self.wrap_s = wrap_s
  80.         self.wrap_t = wrap_t
  81.         self.texenvcolor = vec4(texenvcolor)
  82.         self.transform = transform
  83.         self.environment_map = environment_map
  84.         self.mipmap = mipmap
  85.         self.internalformat = internalformat
  86.         self.size = size
  87.  
  88.         self._image = image
  89.         
  90.         # Remember the current working directory
  91.         self._path = os.getcwd()
  92.  
  93.     # loadTexData
  94.     def loadTexData(self):
  95.         """Load and apply texture file.
  96.         """
  97.         # No image data set? Then use the file name and load the image...
  98.         if self.image==None:
  99.             if self.imagename=="":
  100.                 return
  101.             print 'Loading "%s"...'%self.imagename,
  102.             fullname = os.path.join(self._path, self.imagename)
  103.             try:
  104.                 img = Image.open(fullname)
  105.                 self._passPILImage(img)
  106.             except IOError, e:
  107.                 print "failed"
  108.                 print e
  109.                 return
  110.         else:
  111.             data = self.image
  112.             if type(data)==str:
  113.                 # Raw image data as string
  114.                 w,h = self.size
  115.                 format = self.internalformat
  116.                 self.texData(w, h, format, GL_UNSIGNED_BYTE, data)
  117.             else:
  118.                 # PIL image
  119.                 self._passPILImage(data)
  120.  
  121.  
  122.     ## protected:
  123.  
  124.     def _passPILImage(self, img):
  125.         """Pass a PIL image back to OpenGL.
  126.  
  127.         img must be a PIL image.
  128.         The image is scaled to a power of 2 if necessary.
  129.         """
  130.         img = self._fitPILImage(img)
  131.         
  132.         w,h = img.size
  133.         
  134.         if img.mode=="RGB":
  135.             format = GL_RGB
  136.         elif img.mode=="RGBA":
  137.             format = GL_RGBA
  138.         else:
  139.             raise RuntimeError, "Unsupported texture format (%s)"%img.mode
  140.         
  141.         self.texData(w, h, format, GL_UNSIGNED_BYTE, img.tostring())
  142.         
  143.  
  144.     def _fitPILImage(self, img):
  145.         """Scale the image to a power of 2 resolution.
  146.  
  147.         The image is scale to the user specified resolution. If no
  148.         resolution was set, the next higher power of 2 resolution is used.
  149.         
  150.         If the image resolution is already a power of 2 then
  151.         the input image is returned.
  152.         """
  153.         w,h = img.size
  154.         if self.size==None:
  155.             w2 = 2**int(math.ceil(math.log(w)/math.log(2)))
  156.             h2 = 2**int(math.ceil(math.log(h)/math.log(2)))
  157.         else:
  158.             w2,h2 = self.size
  159.             
  160.         if w2!=w or h2!=h:
  161.             img = img.resize((w2,h2), Image.BICUBIC)
  162.  
  163.         return img
  164.         
  165.         
  166.     # "image" property...
  167.     
  168.     def _getImage(self):
  169.         """Return the current image.
  170.  
  171.         This method is used for retrieving the \a image property.
  172.  
  173.         \return PIL Image (or None)
  174.         """
  175.         return self._image
  176.  
  177.     def _setImage(self, img):
  178.         """Set a new texture image.
  179.  
  180.         This method is used for setting the \a image property.
  181.  
  182.         \param image PIL image or None
  183.         """
  184.         self._image = img
  185.         # Assign the name again so that the image data will be reloaded
  186.         self.imagename = self.imagename
  187.  
  188.     image = property(_getImage, _setImage, None, "Texture image")
  189.  
  190. # GLShader
  191. class GLShader(_core.GLShader):
  192.     """OpenGL 2 shader source file.
  193.     
  194.     """
  195.  
  196.     def __init__(self,
  197.                  shadertype,
  198.                  filename,
  199.                  cpp = None,
  200.                  cpperrstream = sys.stderr,
  201.                  **shaderparams):
  202.         """Constructor.
  203.         """
  204.         _core.GLShader.__init__(self, shadertype, filename)
  205.  
  206.         # Extract the shader parameters...
  207.         uniform,attribute,varying = glslangparams.glslangparams(filename, cpp=cpp, cpperrstream=cpperrstream)
  208.  
  209.         self._uniform = {}
  210.         for type,name,arraysize,structname,struct in uniform:
  211.             if type=="struct":
  212.                 print "Warning: structs are not yet supported"
  213.                 continue
  214.             self._uniform[name] = (type,name,arraysize,structname,struct)
  215.  
  216.         for paramname in shaderparams:
  217.             setattr(self, paramname, shaderparams[paramname])
  218.  
  219.     def __str__(self):
  220.         if self.type==GLSLANG_VERTEX:
  221.             stype = "vertex"
  222.         else:
  223.             stype = "fragment"
  224.         return "<%s shader '%s'>"%(stype, os.path.basename(self.filename))
  225.  
  226.     # getattr
  227.     def __getattr__(self, attr):
  228.         """Return slot value or None if the slot wasn't created yet.
  229.  
  230.         An attempt an unknwon attribute (i.e. no uniform var) results
  231.         in an error.
  232.         """
  233.         slot = self.__dict__.get("%s_slot"%attr, None)
  234.         if slot!=None:
  235.             return slot.getValue()
  236.  
  237.         if attr in self._uniform:
  238.             return None
  239.  
  240.         raise AttributeError, "shader '%s' has no parameter '%s'"%(self.filename, attr)
  241.  
  242.     # setattr
  243.     def __setattr__(self, attr, value):
  244.         if attr in ["_uniform"] or attr[-5:]=="_slot":
  245.             _core.GLShader.__setattr__(self, attr, value)
  246.             return
  247.  
  248.         # Is attr a slot variable?
  249.         slot = self.__dict__.get("%s_slot"%attr, None)
  250.         if slot!=None:
  251.             slot.setValue(value)
  252.             return 
  253.  
  254.         # Is it a parameter that has no value yet? then we must create
  255.         # a new slot...
  256.         uniform = getattr(self, "_uniform", [])
  257.         if attr in uniform:
  258.             slot = self._createSlot(attr, uniform[attr][0])
  259.             slot.setValue(value)
  260.         else:
  261.             raise AttributeError, "shader '%s' has no parameter '%s'"%(self.filename, attr)
  262.  
  263.     # iterUniform
  264.     def iterUniform(self):
  265.         return self._uniform.itervalues()
  266.  
  267.     # _createSlot
  268.     def _createSlot(self, param, type):
  269.         """Create a slot for a parameter.
  270.  
  271.         param is the name of the parameter and type its OpenGL type (as str).
  272.         """
  273.         slot_lut = {"bool" : "BoolSlot",
  274.                     "float" : "DoubleSlot",
  275.                     "int" : "IntSlot",
  276.                     "bvec2" : "Vec3Slot",
  277.                     "bvec3" : "Vec3Slot",
  278.                     "bvec4" : "Vec4Slot",
  279.                     "ivec2" : "Vec3Slot",
  280.                     "ivec3" : "Vec3Slot",
  281.                     "bvec4" : "Vec4Slot",
  282.                     "vec2" : "Vec3Slot",
  283.                     "vec3" : "Vec3Slot",
  284.                     "vec4" : "Vec4Slot",
  285.                     "mat2" : "Mat3Slot",
  286.                     "mat3" : "Mat3Slot",
  287.                     "mat4" : "Mat4Slot",
  288.                     "sampler1D" : "IntSlot",
  289.                     "sampler2D" : "IntSlot",
  290.                     "sampler3D" : "IntSlot",
  291.                     "samplerCube" : "IntSlot",
  292.                     "sampler1DShadow" : "IntSlot",
  293.                     "sampler2DShadow" : "IntSlot"}
  294.         slotname = slot_lut.get(type, None)
  295.         if slotname==None:
  296.             raise ValueError, "Invalid parameter type: %s"%type
  297.         exec "slot = %s()"%slotname
  298.         self.addSlot(param, slot)
  299.         # Store the slot as <param>_slot 
  300.         setattr(self, "%s_slot"%param, slot)
  301.         return slot
  302.  
  303.         
  304. # GLMaterial
  305. class GLMaterial(_core.GLMaterial):
  306.  
  307.     def __init__(self,
  308.                  name = "GLMaterial",
  309.                  ambient = (0.2, 0.2, 0.2, 1),
  310.                  diffuse = (0.7, 0.7, 0.7, 1),
  311.                  specular = (0,0,0,1),
  312.                  shininess = 0.0,
  313.                  emission = (0,0,0,1),
  314.                  blend_factors = None,
  315.                  texture = None,
  316.                  vertex_shader = None,
  317.                  fragment_shader = None,
  318.                  density=1.0):
  319.         _core.GLMaterial.__init__(self, name, density)
  320.  
  321.         self.ambient = vec4(ambient)
  322.         self.diffuse = vec4(diffuse)
  323.         self.specular = vec4(specular)
  324.         self.shininess = shininess
  325.         self.emission = vec4(emission)
  326.         if texture!=None:
  327.             if isinstance(texture, _core.GLTexture):
  328.                 texture = [texture]
  329.             self.setNumTextures(len(texture))
  330.             for i,tex in enumerate(texture):
  331.                 self.setTexture(tex,i)
  332.         if vertex_shader!=None:
  333.             if isinstance(vertex_shader, _core.GLShader):
  334.                 vertex_shader = [vertex_shader]
  335.             self.setNumVertexShaders(len(vertex_shader))
  336.             for i,shd in enumerate(vertex_shader):
  337.                 self.setVertexShader(shd,i)
  338.         if fragment_shader!=None:
  339.             if isinstance(fragment_shader, _core.GLShader):
  340.                 fragment_shader = [fragment_shader]
  341.             self.setNumFragmentShaders(len(fragment_shader))
  342.             for i,shd in enumerate(fragment_shader):
  343.                 self.setFragmentShader(shd,i)
  344.         if blend_factors!=None:
  345.             self.blend_sfactor = blend_factors[0]
  346.             self.blend_dfactor = blend_factors[1]
  347.