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 / ribexport.py < prev    next >
Encoding:
Python Source  |  2007-01-11  |  63.5 KB  |  1,948 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: ribexport.py,v 1.17 2006/04/27 16:56:46 mbaas Exp $
  36.  
  37. import sys, os, os.path, shutil, types
  38. import protocols
  39. import pluginmanager
  40. import lightsource
  41. #from cgkit import *
  42. from cgtypes import *
  43. from targetcamera import TargetCamera
  44. from scene import getScene
  45. from geomobject import *
  46. from boxgeom import BoxGeom
  47. from spheregeom import SphereGeom
  48. from ccylindergeom import CCylinderGeom
  49. from planegeom import PlaneGeom
  50. from trimeshgeom import TriMeshGeom
  51. from polyhedrongeom import PolyhedronGeom
  52. from spotlight3ds import SpotLight3DS
  53. from glpointlight import GLPointLight
  54. from gltargetspotlight import GLTargetSpotLight
  55. from glfreespotlight import GLFreeSpotLight
  56. from gltargetdistantlight import GLTargetDistantLight
  57. from glfreedistantlight import GLFreeDistantLight
  58. from glmaterial import GLMaterial
  59. from cgkit.Interfaces import *
  60. from _OpenGL.GL import GL_REPLACE, GL_MODULATE, GL_DECAL, GL_BLEND
  61. from _OpenGL.GL import *
  62. import cmds
  63. from ri import *
  64. import sl
  65. from riutil import *
  66. from math import *
  67.  
  68. #class IObject(protocols.Interface): pass
  69. class IGeometry(protocols.Interface): pass
  70. class ILightSource(protocols.Interface): pass
  71. class IMaterial(protocols.Interface): pass
  72.  
  73. # RIBImporter
  74. class RIBExporter:
  75.     """RIB export class.
  76.     """
  77.  
  78.     _protocols = ["Export"]
  79.  
  80.     # extension
  81.     def extension():
  82.         return ["rib"]
  83.     extension = staticmethod(extension)
  84.  
  85.     # description
  86.     def description(self):
  87.         """Return a short description for the file dialog."""
  88.         return "RenderMan RIB file"
  89.     description = staticmethod(description)
  90.  
  91.     # exportFile
  92.     def exportFile(self,
  93.                    filename,
  94.                    camera = None,
  95.                    output = None,
  96.                    output_framebuffer = True,
  97.                    bake = False,
  98.                    bakemodel = None,
  99.                    bakestvar = "st"):
  100.         """Export a RIB file.
  101.  
  102.         \a camera is the camera object to use. If None is passed, the
  103.         first camera found is used.
  104.         \a output is the output file name or a list of output specifiers
  105.                   (which contain the parameters for a RiDisplay() call). If
  106.                   output is None, no RiDisplay() call is done.
  107.         """
  108.  
  109.         scene = getScene()
  110.         self.timestep = scene.timer().timestep
  111.         self.bake = bake
  112.  
  113.         # A list with all light sources in the scene
  114.         # (the items are the original lights, *not* the adapted lights)
  115.         self.lights = []
  116.         
  117.         # A dictionary that stores lightsource shader names
  118.         # Key is the light class, value is the shader name
  119.         self.light_shader = {}
  120.  
  121.         # A dictionary that stores the passes created by light sources
  122.         # Key is the original light instance, value is the passes list
  123.         # Empty lists are not stored.
  124.         self.light_passes = {}
  125.  
  126.         # A dictionary that stores material shader names
  127.         # Key is the tuple (material class, surface shader name, displacement
  128.         # shader name, interior name), value are the shader names (surface,
  129.         # displacement, interior)
  130.         # (the shader names in the key are not the true file names but
  131.         # the names returned by the material)
  132.         self.material_shaders = {}
  133.  
  134.         # A dictionary that stores the passes created by materials
  135.         # Key is the original material instance, value is the passes list
  136.         # Empty lists are not stored.
  137.         self.material_passes = {}
  138.  
  139.         # A dictionary with map names used so far
  140.         self.mapnames = {}
  141.  
  142.         # The shader names created so far (this dictionary is used to
  143.         # create unique file names)
  144.         self.shader_names = {}
  145.  
  146.         # Key: (geom, matid)  Value: File name
  147.         self.geom_file = {}
  148.         
  149.         # The geom file names creates so far
  150.         # (this dictionary is used to create unique file names)
  151.         self.geom_names = {}
  152.  
  153.         # Directory names
  154.         self.shader_path = "shaders"
  155.         self.map_path = "maps"
  156.         self.geom_path = "geoms"
  157.  
  158.         # The list with render passes
  159.         passes = []
  160.  
  161.         # Search for a camera and collect the passes...
  162.         cam = camera
  163.         self.preprocess_called = {}
  164.         for obj in scene.walkWorld():
  165.             if cam==None and ICamera in obj.protocols():
  166.                 cam = obj
  167.  
  168.             # Check if the object is a light source
  169.             try:
  170.                 explgt = protocols.adapt(obj, ILightSource)
  171.                 self.lights.append(obj)
  172.                 # Create the RenderPass objects required for this light
  173.                 lgtpasses = explgt.createPasses()
  174.                 lgtpasses = self.makePassOutputUnique(lgtpasses)
  175.                 if lgtpasses!=[]:
  176.                     self.light_passes[obj] = lgtpasses
  177.                     passes += lgtpasses
  178.             except NotImplementedError:
  179.                 # TODO: Use protocols instead of isinstance()
  180.                 if isinstance(obj, lightsource.LightSource):
  181.                     print 'Unknown light source: "%s"'%obj.name
  182.  
  183.             if obj.geom==None:
  184.                 continue
  185.  
  186.             # Collect the material passes
  187.             if obj.visible:
  188.                 for i in range(obj.getNumMaterials()):
  189.                     mat = obj.getMaterial(i)
  190.                     if mat not in self.material_passes:
  191.                         try:
  192.                             expmat = protocols.adapt(mat, IMaterial)
  193.                             # Create the RenderPass objects required for the material
  194.                             ps = expmat.createPasses()
  195.                             ps = self.makePassOutputUnique(ps)
  196.                             if ps!=[]:
  197.                                 self.material_passes[mat] = ps
  198.                                 passes += ps
  199.                             if mat not in self.preprocess_called:
  200.                                 expmat.preProcess(self)
  201.                                 self.preprocess_called[mat] = 1
  202.                         except NotImplementedError:
  203.                             pass
  204.  
  205.         if cam==None:
  206.             cam = TargetCamera()
  207.  
  208.         # Store the camera so that Pass objects can access it
  209.         self.cam = cam
  210.  
  211.         # Add the map path to the map names
  212.         # (on win32, a backslash is replaced by two backslashes because
  213.         # a renderer might interpret a single backslash as an escape character
  214.         # (such as 3Delight))
  215.         for ps in passes:
  216.             tab = ps.getFilenameTable()
  217.             for vname in tab:
  218.                 rname = tab[vname]
  219.                 rname = os.path.join(self.map_path, rname)
  220.                 if sys.platform=="win32":
  221.                     rname = rname.replace('\\', "\\\\")
  222.                 tab[vname] = rname
  223.             ps.setFilenameTable(tab)
  224.  
  225.         if len(passes)>0:
  226.             self.checkMapPath()
  227.  
  228.         # Add the final image pass as last pass
  229. #        if output==None:
  230. #            output = scene.getGlobal("output", "out.tif")
  231.         if bake:
  232.             defaultdisplaymode = RI_RGBA
  233.         else:
  234.             defaultdisplaymode = RI_RGB
  235.         mode = scene.getGlobal("displaymode", defaultdisplaymode)
  236.         out = self.outputSpec(output, mode=mode, output_framebuffer=output_framebuffer)
  237.         if bake:
  238.             bakemodel = cmds.worldObject(bakemodel)
  239.             bakepass = BakePass(output=out, bakemodel=bakemodel, bakestvar=bakestvar)
  240.             passes.append(bakepass)
  241.         else:
  242.             imgpass = ImagePass(output=out, cam=cam)
  243.             passes.append(imgpass)
  244.  
  245.         # Initialize the exporter attribute in the passes...
  246.         for p in passes:
  247.             p.exporter = self
  248.  
  249.         # Start export...
  250.         RiBegin(filename)
  251.  
  252.         RiOption("searchpath", "shader", "%s:&"%self.shader_path)
  253.         RiOption("searchpath", "archive", "%s:&"%self.geom_path)
  254.         RiOption("searchpath", "texture", "%s:&"%self.map_path)
  255.         RiHider(RI_HIDDEN, "string depthfilter", "midpoint")
  256.         globalrib = scene.getGlobal("rib", None)
  257.         if globalrib!=None:
  258.             RiArchiveRecord(RI_VERBATIM, globalrib+"\n")
  259.  
  260.         # Do render passes...
  261.         print len(passes),"passes..."
  262. #        nr = 0
  263.         # Tex passes first
  264.         for rpass in passes:
  265.             if isinstance(rpass, TexPass):
  266. #                nr+=1
  267. #                print "\015Pass %d..."%nr,
  268.                 rpass.doPass(0)
  269.                 rpass._done = True
  270.  
  271.         # Other passes...
  272.         for rpass in passes:
  273.             if isinstance(rpass, TexPass):
  274.                 continue
  275. #            nr+=1
  276. #            print "\015Pass %d..."%nr,
  277.             rpass.doPass(0)
  278.             rpass._done = True
  279.  
  280.         RiEnd()
  281.  
  282.     ## protected:
  283.  
  284.     # outputSpec
  285.     def outputSpec(self, output, mode=RI_RGB, output_framebuffer=False):
  286.         """Return the output specification for the final image pass.
  287.  
  288.         output is the parameter passed to exportFile().
  289.         mode and output_framebuffer is only used when output is a string.
  290.         The return value is a list of output specs which can be
  291.         passed as output parameter to the ImagePass.
  292.         """
  293.         # No output?
  294.         if output==None:
  295.             return []
  296.         # Is output a string? (i.e. the output file name)
  297.         elif isinstance(output, types.StringTypes):
  298.             out = [(output, RI_FILE, mode, {})]
  299.             if output_framebuffer:
  300.                 out += [(output, RI_FRAMEBUFFER, mode, {})]
  301.             return out
  302.         # User specified output specs? (output must already be a list
  303.         # of specs)
  304.         else:
  305.             return output
  306.         
  307.  
  308.     # isExportable
  309.     def isExportable(self, wobj):
  310.         """Check if a WorldObject can be exported or not.
  311.  
  312.         ??? Geometry?
  313.         """
  314.  
  315.         geom = wobj.geom
  316.         if geom==None:
  317.             return False
  318.         
  319.         try:
  320.             expgeom = protocols.adapt(geom, IGeometry)
  321.             return True
  322.         except NotImplementedError:
  323.             print '"%s" has unknown geometry.'%wobj.name
  324.             return False
  325.         
  326.     # applyViewTransform
  327.     def applyViewTransform(self, V):
  328.         """Apply the view transformation V.
  329.  
  330.         This method corresponds to a RiConcatTransform() call.
  331.         It outputs the view transformation V as a RenderMan transformation.
  332.         The handedness of the scene is taken into account.
  333.  
  334.         \param V (\c mat4) View transformation (world -> camera)
  335.         """
  336.         scene = getScene()
  337.         if scene.handedness=='r':
  338.             RiScale(-1,1,1)                
  339.         RiConcatTransform(V.toList())
  340.  
  341.     # applyLightSource
  342.     def applyLightSource(self, lgt):
  343.         """Apply the light source lgt.
  344.  
  345.         This method corresponds to a RiLightSource() call.
  346.  
  347.         \param lgt (\c WorldObject) Light source
  348.         \return Light id or None.
  349.         """
  350.  
  351. #        try:
  352.         explgt = protocols.adapt(lgt, ILightSource)
  353. #        except NotImplementedError:
  354. #            return
  355.  
  356.         # Save the light shader if it wasn't already saved before...
  357.         cls = "%s_%s"%(lgt.__class__, explgt.shaderName())
  358.         if cls not in self.light_shader:
  359.             shadername = self.writeShader(explgt.shaderName(),
  360.                                           explgt.shaderSource())
  361.             self.light_shader[cls] = shadername
  362.  
  363.         # Get the shader name
  364.         shadername = self.light_shader[cls]
  365.         if shadername==None:
  366.             return None
  367.  
  368.         # Get the parameters for the shader
  369.         passes = self.light_passes.get(lgt, [])
  370.         params = explgt.shaderParams(passes)
  371.  
  372.         lid = RiLightSource(shadername, params)
  373.         return lid
  374.  
  375.     # applyTransformation
  376.     def applyTransformation(self, T, linearvel=None, angularvel=None):
  377.         """Apply the transformation T.
  378.  
  379.         This method corresponds to a RiConcatTransform() call.
  380.         It outputs T as a RenderMan transformation.
  381.  
  382.         \param T (\c mat4) Transformation
  383.         """
  384.         RiConcatTransform(T.toList())
  385.         if linearvel!=None and angularvel!=None:
  386.             try:
  387.                 axis = angularvel.normalize()
  388.             except:
  389.                 axis = vec3(1,0,0)
  390.             dw = 0.5*self.timestep*degrees(angularvel.length())
  391.             dr = 0.5*self.timestep*linearvel
  392.             if abs(dw)>1E-6:
  393.                 RiMotionBegin(0, 1)
  394.                 RiRotate(-dw, axis)
  395.                 RiRotate( dw, axis)
  396.                 RiMotionEnd()
  397.             if dr!=vec3(0):
  398.                 RiMotionBegin(0,1)
  399.                 RiTranslate(-dr)
  400.                 RiTranslate( dr)
  401.                 RiMotionEnd()
  402.  
  403.     # applyMaterial
  404.     def applyMaterial(self, mat):
  405.         """Apply a material.
  406.  
  407.         This method corresponds to the calls RiColor(), RiOpacity(),
  408.         RiSurface(), RiDisplacement() and RiInterior().
  409.  
  410.         Evtl. Flags als Parameter, die bestimmten welche der Shader
  411.         wirklich ausgegeben werden sollen (Surface, Displacement, Volume).
  412.         Z.B. koennte Shadow-Pass auf Surface verzichten, evtl. aber nicht
  413.         auf Displacement.
  414.  
  415.         \param mat (\c Material) Material
  416.         """
  417.         if mat==None:
  418.             return
  419.  
  420. #        try:
  421.         expmat = protocols.adapt(mat, IMaterial)
  422. #        except NotImplementedError:
  423. #            return
  424.  
  425.         # Save the shaders if they weren't already saved before...
  426.         cls = (mat.__class__,
  427.                expmat.surfaceShaderName(),
  428.                expmat.displacementShaderName(),
  429.                expmat.interiorShaderName())
  430.         if cls not in self.material_shaders:
  431.             # Prepare the material shaders (save shader source)
  432.             srfshader = self.writeShader(expmat.surfaceShaderName(),
  433.                                          expmat.surfaceShaderSource())
  434.             dispshader = self.writeShader(expmat.displacementShaderName(),
  435.                                           expmat.displacementShaderSource())
  436.             intrshader = self.writeShader(expmat.interiorShaderName(),
  437.                                           expmat.interiorShaderSource())
  438.             self.material_shaders[cls] = (srfshader, dispshader, intrshader)
  439.  
  440.         # Get the shader names
  441.         srfshader, dispshader, intrshader = self.material_shaders[cls]
  442.  
  443.         # Get the parameters for the shader
  444.         passes = self.material_passes.get(mat, [])
  445.         srfparams = expmat.surfaceShaderParams(passes)
  446.         dispparams = expmat.displacementShaderParams(passes)
  447.         interiorparams = expmat.interiorShaderParams(passes)
  448.  
  449.         # Get the shader transforms
  450.         srftransform = expmat.surfaceShaderTransform()
  451.         disptransform = expmat.displacementShaderTransform()
  452.         interiortransform = expmat.interiorShaderTransform()
  453.  
  454.         color = expmat.color()
  455.         opacity = expmat.opacity()
  456.  
  457.         if color!=None:
  458.             RiColor(color)
  459.         if opacity!=None:
  460.             RiOpacity(opacity)
  461.         if srfshader!=None:
  462.             if srftransform!=mat4(1):
  463.                 RiTransformBegin()
  464.                 RiConcatTransform(srftransform.toList())
  465.             RiSurface(srfshader, srfparams)
  466.             if srftransform!=mat4(1):
  467.                 RiTransformEnd()
  468.         if dispshader!=None:
  469.             if disptransform!=mat4(1):
  470.                 RiTransformBegin()
  471.                 RiConcatTransform(disptransform.toList())
  472.             coordsys, bound = expmat.displacementBound()
  473.             RiAttribute("displacementbound",
  474.                         "string coordinatesystem", coordsys,
  475.                         "float sphere", bound)
  476.             RiDisplacement(dispshader, dispparams)
  477.             if disptransform!=mat4(1):
  478.                 RiTransformEnd()
  479.         if intrshader!=None:
  480.             if interiortransform!=mat4(1):
  481.                 RiTransformBegin()
  482.                 RiConcatTransform(interiortransform.toList())
  483.             RiInterior(intrshader, interiorparams)
  484.             if interiortransform!=mat4(1):
  485.                 RiTransformEnd()
  486.  
  487.  
  488.     # applyGeometry
  489.     def applyGeometry(self, geom, matid=0):
  490.         """Apply a geometry object.
  491.  
  492.         \param geom (\c GeomObject) Geometry or None
  493.         """
  494.         if geom==None:
  495.             return
  496.  
  497.         # Was the geom already exported?
  498.         if (geom, matid) in self.geom_file:
  499.             filename = self.geom_file[geom, matid]
  500.             RiReadArchive(filename)
  501.             return
  502.  
  503.         # The geom was not exported, so do it now...
  504.  
  505.         try:
  506.             expgeom = protocols.adapt(geom, IGeometry)
  507.         except NotImplementedError:
  508.             print 'Warning: Unknown geometry: "%s" (%s)'%(geom.name, geom.__class__.__name__)
  509.             return
  510.  
  511.         # Create the geoms directory if it doesn't exist
  512.         if not os.path.exists(self.geom_path):
  513.             os.mkdir(self.geom_path)
  514.  
  515.         # Determine the output file name (without path)
  516.         n = "%s_id%d_%s.rib"%(geom.__class__.__name__, matid, geom.name)
  517.         filename = self.makeFilenameUnique(n, self.geom_names)
  518.         self.geom_names[filename] = 1
  519.         self.geom_file[geom, matid] = filename
  520.  
  521.         ctx = RiGetContext()
  522.         RiBegin(os.path.join(self.geom_path, filename))
  523.         RiOption(RI_RIBOUTPUT, RI_VERSION, 0)
  524.         expgeom.render(matid)
  525.         RiEnd()
  526.         RiContext(ctx)
  527.         RiReadArchive(filename)        
  528.  
  529.  
  530.     # writeShader
  531.     def writeShader(self, name, source):
  532.         """Write a shader source file.
  533.  
  534.         \param name (\c str) Initial shader name or None
  535.         \param source (\c str) Shader source code or None
  536.         \return Shader name
  537.         """
  538.         # No source given? Then just use the specified shader name
  539.         if source==None:
  540.             return name
  541.  
  542.         if name==None:
  543.             name = "shader"
  544.  
  545.         shadername = self.makeFilenameUnique(name, self.shader_names)
  546.         self.shader_names[shadername]=1
  547.  
  548.         # Create the shaders directory if it doesn't exist
  549.         if not os.path.exists(self.shader_path):
  550.             os.mkdir(self.shader_path)
  551.  
  552.         filename = os.path.join(self.shader_path, shadername+".sl")
  553.         f = file(filename, "wt")
  554.         # Add the macros that are used for baking...
  555.         if self.bake:
  556.             f.write("#define BAKE_PASS\n")
  557.             begin = 'varying point _P_bake = transform("world", "current", transform("camera", "object", Pref));\\\n  varying point _P_orig = P;\\\n  P = _P_bake;'
  558.             end = 'P = _P_orig;'
  559.             normal = 'normalize(n);'
  560.         else:
  561.             begin = ""
  562.             end = ""
  563.             normal = 'faceforward(normalize(n),I);'
  564.         f.write("#define BAKE_BEGIN %s\n"%begin)
  565.         f.write("#define BAKE_END %s\n"%end)
  566.         f.write("#define BAKE_NORMAL(n) %s\n\n"%normal)
  567.             
  568.         f.write(source.replace("$SHADERNAME", shadername))
  569.         f.close()
  570.         return shadername
  571.  
  572.     # checkMapPath
  573.     def checkMapPath(self):
  574.         """Create the map directory if it doesn't already exist.
  575.         """
  576.         if not os.path.exists(self.map_path):
  577.             os.mkdir(self.map_path)
  578.  
  579.  
  580.     # makePassOutputUnique
  581.     def makePassOutputUnique(self, passes):
  582.         res = []
  583.         for rpass in passes:
  584.             tab = rpass.getFilenameTable()
  585.             for vname in tab:
  586.                 rname = self.makeFilenameUnique(tab[vname], self.mapnames)
  587.                 tab[vname] = rname
  588.                 self.mapnames[rname] = 1
  589. #            print tab
  590.             rpass.setFilenameTable(tab)
  591.             res.append(rpass)
  592.             
  593.         return res
  594.  
  595.     # makeFilenameUnique
  596.     def makeFilenameUnique(self, name, names):
  597.         """Modify a file name so that it is unique.
  598.  
  599.         If \a name is already among \a names it is modified by increasing
  600.         a trailing number so that it is unique.
  601.  
  602.         \param name (\c str) File name
  603.         \param names A list or dictionary with existing file names
  604.         \return Unique file name
  605.         """
  606.         base, ext = os.path.splitext(name)
  607.         # Read any trailing number
  608.         # -> base: name without number (and extension) / num: Number
  609.         i = 1
  610.         while i<=len(base) and base[-i:].isdigit():
  611.             i+=1
  612.         i-=1
  613.         if i==0:
  614.             num = 1
  615.         else:
  616.             num = int(base[-i:])
  617.             base = base[:-i]
  618.         
  619.         while name in names:
  620.             name = "%s%d%s"%(base, num, ext)
  621.             num += 1
  622.             
  623.         return name
  624.         
  625.         
  626.  
  627. ######################################################################
  628.  
  629. # RenderPass
  630. class RenderPass:
  631.     """RenderPass.
  632.  
  633.     A pass object can access the exporter (RIBExport) via self.exporter.
  634.     """
  635.     def __init__(self, output, owner=None):
  636.         """Constructor.
  637.         
  638.         output is a list of output specifications that contain the
  639.         output file name, the output type and the output mode (RI_RGB,
  640.         RI_RGBA,...) and optional extra parameters. It's all the
  641.         information that's necessary for a RiDisplay() call.
  642.             
  643.         \param owner (\c Component) The object that requires the result of this pass
  644.         """
  645.         self.owner = owner
  646.         self.output = output
  647.         # A reference to the exporter class (this is initialized in the
  648.         # exporter after the Passes were created)
  649.         self.exporter = None
  650.  
  651.         # done flag (this is set to True in the exporter)
  652.         self._done = False
  653.  
  654.         # Filename table. Key: Logical file name / Value: Real filename
  655.         self.filenametab = {}
  656.         for name,type,mode,params in output:
  657.             self.filenametab[name] = name
  658.  
  659.     # done
  660.     def done(self):
  661.         """Check if this pass is already done or not.
  662.  
  663.         This method is used when shader parameters have to be determined.
  664.         The output of a pass may only be used once the pass is done and
  665.         the output really exists (for example, you can't use a shadow map
  666.         until it was created).
  667.  
  668.         \return True if the pass was already rendered (i.e. the output images exist).
  669.         """
  670.         return self._done
  671.  
  672.     # realFilename
  673.     def realFilename(self, filename):
  674.         """Translate a logical file name into a real file name.
  675.  
  676.         \param filename (\c str) Logical file name
  677.         """
  678.         if filename not in self.filenametab:
  679.             raise ValueError('File name "%s" is not an output file name.'%filename)
  680.  
  681.         return self.filenametab[filename]
  682.  
  683.     # getFilenameTable
  684.     def getFilenameTable(self):
  685.         """Return the filename translation table.
  686.  
  687.         \return The filename translation dictionary.
  688.         """
  689.         return self.filenametab
  690.  
  691.     # setFilenameTable
  692.     def setFilenameTable(self, tab):
  693.         """Set an updated filename table.
  694.  
  695.         \param tab (\c dict) The new filename translation dictionary.
  696.         """
  697.         self.filenametab = tab
  698.  
  699.     # doPass
  700.     def doPass(self, framenr):
  701.         """Write a Frame block.
  702.  
  703.         \param framenr (\c int) Frame number to use
  704.         """
  705.         pass
  706.  
  707.     # initDisplays
  708.     def initDisplays(self):
  709.         """Call RiDisplay() for all outputs stored in the class."""
  710.         # Do RiDisplay() calls...
  711.         append_plus = False
  712.         for name,type,mode,params in self.output:
  713.             name = self.realFilename(name)
  714.             if append_plus:
  715.                 name = "+"+name
  716.             RiDisplay(name, type, mode, params)
  717.             append_plus = True
  718.  
  719.         
  720.  
  721. # ImagePass
  722. class ImagePass(RenderPass):
  723.     def __init__(self, output, cam):
  724.         RenderPass.__init__(self, output, None)
  725.         self.cam = cam
  726.  
  727.     # doPass
  728.     def doPass(self, framenr):
  729.         scene = getScene()
  730.  
  731.         RiArchiveRecord(RI_COMMENT, "")
  732.         RiArchiveRecord(RI_COMMENT, "Image pass")
  733.         RiArchiveRecord(RI_COMMENT, "")
  734.         RiFrameBegin(framenr)
  735.  
  736.         i,j = scene.getGlobal("pixelsamples", (2,2))
  737.         RiPixelSamples(i,j)
  738.         res = scene.getGlobal("resolution", (640,480))
  739.         try:
  740.             if len(res)==2:
  741.                 w,h = res
  742.                 aspect = 1
  743.             elif len(res)==3:
  744.                 w,h,aspect = res
  745.             else:
  746.                 raise Exception
  747.         except:
  748.             print >>sys.stderr, "Error: Invalid resolution setting:",res
  749.             w,h,aspect = 640,480,1
  750.         RiFormat(w,h,aspect)
  751.         RiShadingRate(scene.getGlobal("shadingrate", 1.0))
  752.         
  753.         filterdata = scene.getGlobal("pixelfilter", None)
  754.         if filterdata!=None:
  755.             filter, (xwidth, ywidth) = filterdata
  756.             RiPixelFilter(filter, xwidth, ywidth)
  757.  
  758.         # Do RiDisplay() calls...
  759.         self.initDisplays()
  760.  
  761.         # Camera...
  762.         cam = self.cam
  763.         fstop = getattr(cam, "fstop", 0)
  764.         focallength = getattr(cam, "focallength", 0)
  765.         RiProjection(RI_PERSPECTIVE, fov=cam.fov)
  766.         if fstop!=0 and focallength!=0:
  767.             # XXX: The following line only works with a TargetCamera!
  768.             focaldistance = (cam.target-cam.pos).length()
  769.             RiDepthOfField(fstop, focallength, focaldistance)
  770.         self.exporter.applyViewTransform(cam.viewTransformation())
  771.         RiShutter(0,1)
  772.  
  773.         RiWorldBegin()
  774.  
  775.         # Set light sources...
  776.         for lgt in self.exporter.lights:
  777.             RiAttributeBegin()
  778.             RiAttribute("identifier", "name", lgt.name)
  779.             RiConcatTransform(lgt.worldtransform.toList())
  780.             lid = self.exporter.applyLightSource(lgt)
  781.             RiAttributeEnd()
  782.             if lid!=None:
  783.                 RiIlluminate(lid, lgt.enabled)
  784.             
  785. #            shader,params,transform,name = exporter.light_shaders[lgt]
  786. #            lid = RiLightSource(shader, params)
  787.  
  788.         self.renderChilds(scene.worldRoot())
  789.         
  790.         RiWorldEnd()     
  791.         RiFrameEnd()
  792.  
  793.     def renderChilds(self, obj):
  794.         exporter = self.exporter
  795.         for child in obj.iterChilds():
  796.             if not child.visible:
  797.                 continue
  798.             # No geometry and no children? Then ignore this node
  799.             if child.geom==None and child.lenChilds()==0:
  800.                 continue
  801. #            if not exporter.isExportable(child):
  802. #                continue
  803.  
  804.             RiAttributeBegin()
  805.             
  806.             # Store the name of the object
  807.             RiAttribute("identifier", "name", child.name)
  808.             # Transform the object
  809.             exporter.applyTransformation(child.localTransform(), child.linearvel, child.angularvel)
  810.  
  811.             for i in range(child.getNumMaterials()):
  812.                 # Set shaders...
  813.                 exporter.applyMaterial(child.getMaterial(i))
  814.  
  815.                 # Custom RIB
  816.                 rib = getattr(child, "rib", None)
  817.                 if rib!=None:
  818.                     RiArchiveRecord(RI_VERBATIM, rib+"\n")
  819.  
  820.                 # Output geometry
  821.                 exporter.applyGeometry(child.geom, i)
  822.             
  823.             # Recursively render all childs
  824.             self.renderChilds(child)
  825.             
  826.             RiAttributeEnd()
  827.  
  828.  
  829. # ShadowPass
  830. class ShadowPass(RenderPass):
  831.     def __init__(self, output, light, fov, resolution, orientoffset=mat4(1)):
  832.         RenderPass.__init__(self, output, None)
  833.         self.light = light
  834.         self.fov = fov
  835.         self.resolution = resolution
  836.         self.orientoffset = orientoffset
  837.  
  838.     # doPass
  839.     def doPass(self, framenr):
  840.         scene = getScene()
  841.  
  842.         RiArchiveRecord(RI_COMMENT, "")
  843.         RiArchiveRecord(RI_COMMENT, "Shadow pass")
  844.         RiArchiveRecord(RI_COMMENT, "")
  845.         RiFrameBegin(framenr)
  846.  
  847.         RiPixelSamples(1,1)
  848.         RiPixelFilter(RiBoxFilter, 1, 1)
  849.         RiFormat(self.resolution, self.resolution, 1)
  850.         RiShadingRate(2)
  851.  
  852.         # Do RiDisplay() calls...
  853.         self.initDisplays()
  854.  
  855.         # Camera...
  856.         RiProjection(RI_PERSPECTIVE, fov=self.fov)
  857.         V = (self.light.transform*self.orientoffset).inverse()
  858.         self.exporter.applyViewTransform(V)
  859.         RiShutter(0,1)
  860.  
  861.         RiWorldBegin()
  862.  
  863.         self.renderChilds(scene.worldRoot())
  864.         
  865.         RiWorldEnd()     
  866.         RiFrameEnd()
  867.         zname = self.realFilename(self.output[0][0])
  868.         mapname = os.path.splitext(zname)[0]+".map"
  869.         RiMakeShadow(zname, mapname)
  870.  
  871.     def renderChilds(self, obj):
  872.         exporter = self.exporter
  873.         for child in obj.iterChilds():
  874.             if not child.visible:
  875.                 continue
  876.             # No geometry and no children? Then ignore this node
  877.             if child.geom==None and child.lenChilds()==0:
  878.                 continue
  879. #            if not exporter.isExportable(child):
  880. #                continue
  881.  
  882.             RiAttributeBegin()
  883.  
  884.             # Store the name of the object
  885.             RiAttribute("identifier", "name", child.name)
  886.             # Transform the object
  887.             exporter.applyTransformation(child.localTransform())
  888.             for i in range(child.getNumMaterials()):
  889.                 # Set shaders...
  890.                 exporter.applyMaterial(child.getMaterial(i))
  891.  
  892.                 # Custom RIB
  893.                 rib = getattr(child, "rib", None)
  894.                 if rib!=None:
  895.                     RiArchiveRecord(RI_VERBATIM, rib+"\n")
  896.  
  897.                 # Output geometry
  898.                 exporter.applyGeometry(child.geom, i)
  899.             
  900.             # Recursively render all childs
  901.             self.renderChilds(child)
  902.  
  903.             RiAttributeEnd()
  904.  
  905. # FlatReflectionPass
  906. class FlatReflectionPass(RenderPass):
  907.     def __init__(self, output, mirrorobj=None):
  908.         RenderPass.__init__(self, output, None)
  909.         self.mirrorobj = mirrorobj
  910.  
  911.     # doPass
  912.     def doPass(self, framenr):
  913.         scene = getScene()
  914.  
  915.         RiArchiveRecord(RI_COMMENT, "(Flat) Reflection pass")
  916.         RiFrameBegin(framenr)
  917.  
  918.         RiPixelSamples(2,2)
  919.         RiFormat(640,480,1)
  920.         RiShadingRate(1)
  921.  
  922.         # Do RiDisplay() calls...
  923.         self.initDisplays()
  924.  
  925.         # Camera...
  926.         cam = self.exporter.cam
  927.         RiProjection(RI_PERSPECTIVE, fov=cam.fov)
  928.         self.exporter.applyViewTransform(cam.viewTransformation())
  929.         RiScale(1,1,-1)
  930.         RiShutter(0,1)
  931. #        RiTranslate(0,0,1)
  932.  
  933.         RiWorldBegin()
  934.  
  935.         # Set light sources...
  936.         for lgt in self.exporter.lights:
  937.             RiAttributeBegin()
  938.             RiAttribute("identifier", "name", lgt.name)
  939.             RiConcatTransform(lgt.worldtransform.toList())
  940.             lid = self.exporter.applyLightSource(lgt)
  941.             RiAttributeEnd()
  942.             if lid!=None:
  943.                 RiIlluminate(lid, RI_TRUE)
  944.             
  945. #            shader,params,transform,name = exporter.light_shaders[lgt]
  946. #            lid = RiLightSource(shader, params)
  947.  
  948.         self.renderChilds(scene.worldRoot())
  949.         
  950.         RiWorldEnd()     
  951.         RiFrameEnd()
  952.         tifname = self.realFilename(self.output[0][0])
  953.         texname = os.path.splitext(tifname)[0]+".tex"
  954.         RiMakeTexture(tifname, texname, RI_CLAMP, RI_CLAMP, RiGaussianFilter, 1, 1)
  955.  
  956.  
  957.     def renderChilds(self, obj):
  958.         exporter = self.exporter
  959.         for child in obj.iterChilds():
  960.             if child==self.mirrorobj:
  961.                 continue
  962.             if not child.visible:
  963.                 continue
  964. #            if not exporter.isExportable(child):
  965. #                continue
  966.  
  967.             RiAttributeBegin()
  968.             
  969.             # Store the name of the object
  970.             RiAttribute("identifier", "name", child.name)
  971.             # Transform the object
  972.             exporter.applyTransformation(child.localTransform(), child.linearvel, child.angularvel)
  973.             for i in range(child.getNumMaterials()):
  974.                 # Set shaders...
  975.                 exporter.applyMaterial(child.getMaterial(i))
  976.  
  977.                 # Custom RIB
  978.                 rib = getattr(child, "rib", None)
  979.                 if rib!=None:
  980.                     RiArchiveRecord(RI_VERBATIM, rib+"\n")
  981.  
  982.                 # Output geometry
  983.                 exporter.applyGeometry(child.geom, i)
  984.             
  985.             # Recursively render all childs
  986.             self.renderChilds(child)
  987.             
  988.             RiAttributeEnd()
  989.  
  990. # BakePass
  991. class BakePass(RenderPass):
  992.     """Create a bake pass.
  993.  
  994.     The class uses the technique described in the "Stupid RAT Tricks 2001":
  995.     "The RenderMan EasyBake Oven" by Jonathan Litt and Dan Goldman.
  996.     http://www.cs.washington.edu/homes/dgoldman/ezbake/EZ_Bake_Oven.htm
  997.  
  998.     Additionally, the original geometry is also stored so that raytracing
  999.     can also be used.
  1000.     """
  1001.     
  1002.     def __init__(self, output, bakemodel, bakestvar="st"):
  1003.         """
  1004.         bakemodel is the WorldObject whose texture should be baked.
  1005.         bakestvar is the name of the variable that holds the texture
  1006.         coordinates for baking.
  1007.         """
  1008.         RenderPass.__init__(self, output, None)
  1009.         self.bakemodel = bakemodel
  1010.         self.bakestvar = bakestvar
  1011.  
  1012.     # doPass
  1013.     def doPass(self, framenr):
  1014.         scene = getScene()
  1015.  
  1016.         RiArchiveRecord(RI_COMMENT, "")
  1017.         RiArchiveRecord(RI_COMMENT, "Bake pass")
  1018.         RiArchiveRecord(RI_COMMENT, "")
  1019.         RiFrameBegin(framenr)
  1020.  
  1021.         i,j = scene.getGlobal("pixelsamples", (2,2))
  1022.         RiPixelSamples(i,j)
  1023.         res = scene.getGlobal("resolution", (256,256))
  1024.         try:
  1025.             if len(res)==2:
  1026.                 w,h = res
  1027.                 aspect = 1
  1028.             elif len(res)==3:
  1029.                 w,h,aspect = res
  1030.             else:
  1031.                 raise Exception
  1032.         except:
  1033.             print >>sys.stderr, "Error: Invalid resolution setting:",res
  1034.             w,h,aspect = 256,256,1
  1035.         RiFormat(w,h,aspect)
  1036.         RiShadingRate(scene.getGlobal("shadingrate", 1.0))
  1037.  
  1038.         # Do RiDisplay() calls...
  1039.         self.initDisplays()
  1040.  
  1041.         # Camera...
  1042.         RiProjection(RI_ORTHOGRAPHIC)
  1043.         bb = scene.boundingBox()
  1044.         bmin, bmax = bb.getBounds()
  1045.         RiScale(2,2,2)
  1046.         RiTranslate(-0.5, -0.5, -bmax.z-1)
  1047.  
  1048.         RiWorldBegin()
  1049.  
  1050.         # Set light sources...
  1051.         for lgt in self.exporter.lights:
  1052.             RiAttributeBegin()
  1053.             RiAttribute("identifier", "name", lgt.name)
  1054.             RiConcatTransform(lgt.worldtransform.toList())
  1055.             lid = self.exporter.applyLightSource(lgt)
  1056.             RiAttributeEnd()
  1057.             if lid!=None:
  1058.                 RiIlluminate(lid, lgt.enabled)
  1059.  
  1060.         # Flattened geometry
  1061.         obj = self.bakemodel
  1062.         RiAttributeBegin()
  1063.         self.exporter.applyMaterial(obj.getMaterial(0))
  1064. #        RiCoordSysTransform("camera")
  1065. #        RiScale(2,2,2)
  1066. #        RiTranslate(-0.5,-0.5,1)
  1067.         RiTranslate(0,0, bmax.z+1.5)
  1068.         self.bakeModel(obj, self.bakestvar)
  1069.         RiAttributeEnd()
  1070.  
  1071.         # 3Delight attribute...
  1072.         RiAttribute("visibility", "string transmission", "opaque")
  1073.         # Pixie attribute...
  1074.         RiAttribute("visibility", "int trace", 1)
  1075.         
  1076.         self.renderChilds(scene.worldRoot())
  1077.  
  1078.         RiWorldEnd()     
  1079.         RiFrameEnd()
  1080.  
  1081.     def bakeModel(self, obj, stvarname="st"):
  1082.         """
  1083.         obj is the model that should be baked. stvarname is the name
  1084.         of the variable that holds the texture coordinates for baking.
  1085.         """
  1086.  
  1087.         # Check texture coordinates...
  1088.         info = obj.geom.findVariable(stvarname)
  1089.         if info==None:
  1090.             raise RuntimeError, "No variable '%s' found"%stvarname
  1091.             
  1092.         name, storage, type, mult = info
  1093.  
  1094.         if type!=FLOAT or mult!=2:
  1095.             raise TypeError, "variable '%s' is of wrong type"%stvarname
  1096.  
  1097.         if storage==FACEVARYING:
  1098.             geom = cmds.convFaceVarToVar(obj.geom)
  1099.         elif storage==VARYING:
  1100.             geom = obj.geom
  1101.         else:
  1102.             raise TypeError, "'%s' storage class %s not supported for baking"%(stvarname,storage)
  1103.  
  1104.         # Convert the model into a trimesh...
  1105.         if not isinstance(geom, TriMeshGeom):
  1106.             tm = TriMeshGeom()
  1107.             geom.convert(tm)
  1108.             geom = tm
  1109.         
  1110.         # Convert the tex coords into vec3s...
  1111.         st = geom.slot(stvarname)
  1112. #        print "sizes:",geom.verts.size(), st.size()
  1113.         stcoords = map(lambda x: vec3(x), st)
  1114.  
  1115.         # Transform the verts...
  1116. #        verts = []
  1117. #        W = obj.worldtransform
  1118. #        for i,j,k in geom.faces:
  1119. #            verts.append(W*geom.verts[i])
  1120. #            verts.append(W*geom.verts[j])
  1121. #            verts.append(W*geom.verts[k])
  1122.  
  1123. #        verts = 156*[(0,0,0)]
  1124.  
  1125.         # Create parameter list...
  1126.         W = obj.worldtransform
  1127.         params = {"P":stcoords,
  1128.                   "Pref":map(lambda x: W*x, geom.verts)}
  1129.         RiDeclare("Pref", "vertex point")
  1130.         clss = ["constant", "uniform", "varying", "vertex", "facevarying", "facevertex", "user"]
  1131.         typs = ["integer", "float", "string", "color", "point", "vector",
  1132.                 "normal", "matrix", "hpoint"]
  1133.         for name, storage, type, multiplicity in geom.iterVariables():
  1134.             cls = clss[abs(storage)]
  1135.             typ = typs[abs(type)]
  1136.             if cls!="user":
  1137.                 s = geom.slot(name)
  1138.                 params[name] = list(s)
  1139.                 if multiplicity==1:
  1140.                     decl = "%s %s"%(cls, typ)
  1141.                 else:
  1142.                     decl = "%s %s[%d]"%(cls, typ, multiplicity)
  1143.                 RiDeclare(name, decl)
  1144.  
  1145. #        RiCoordSysTransform("camera")
  1146.         RiPointsPolygons(len(geom.faces)*[3], list(geom.faces), params)
  1147.  
  1148.     def renderChilds(self, obj):
  1149.         exporter = self.exporter
  1150.         for child in obj.iterChilds():
  1151.             if not child.visible:
  1152.                 continue
  1153.             # No geometry and no children? Then ignore this node
  1154.             if child.geom==None and child.lenChilds()==0:
  1155.                 continue
  1156. #            if not exporter.isExportable(child):
  1157. #                continue
  1158.  
  1159.             RiAttributeBegin()
  1160.             
  1161.             # Store the name of the object
  1162.             RiAttribute("identifier", "name", child.name)
  1163.             # Transform the object
  1164.             exporter.applyTransformation(child.localTransform(), child.linearvel, child.angularvel)
  1165.  
  1166.             for i in range(child.getNumMaterials()):
  1167.                 # Set shaders...
  1168.                 exporter.applyMaterial(child.getMaterial(i))
  1169.  
  1170.                 # Custom RIB
  1171.                 rib = getattr(child, "rib", None)
  1172.                 if rib!=None:
  1173.                     RiArchiveRecord(RI_VERBATIM, rib+"\n")
  1174.  
  1175.                 # Output geometry
  1176.                 exporter.applyGeometry(child.geom, i)
  1177.             
  1178.             # Recursively render all childs
  1179.             self.renderChilds(child)
  1180.             
  1181.             RiAttributeEnd()
  1182.  
  1183.  
  1184. # TexPass
  1185. class TexPass(RenderPass):
  1186.     def __init__(self, maps, output=[]):
  1187.         """Constructor.
  1188.  
  1189.         The map definition list contains one tuple for every map.
  1190.         The tuple is a 7-tuple with the following entries:
  1191.  
  1192.         - Map name (incl. path)
  1193.         - swrap ("periodic", "clamp", "black")
  1194.         - twrap ("periodic", "clamp", "black")
  1195.         - filterfunc ("gaussian", "box", "triangle", "sinc", "catmullrom", ...)
  1196.         - swidth
  1197.         - twidth
  1198.         - params - A dictionary with additional parameters
  1199.  
  1200.         These are the parameters for the \c RiMakeTexture() call.
  1201.         The output file name is generated from the input map name by
  1202.         replacing the suffix with "*.tex".
  1203.         
  1204.         \param maps A list with map defintions
  1205.         """
  1206.         RenderPass.__init__(self, output)
  1207.         self.maps = maps
  1208.  
  1209.     def doPass(self, framenr):
  1210.         
  1211.         for map,swrap,twrap,filterfunc,swidth,twidth,params in self.maps:
  1212.  
  1213.             # Copy the original image into the map directory and convert
  1214.             # to tif if necessary
  1215.             self.copyImageMap(map)
  1216.  
  1217.             # Call RiMakeTexture() to convert the .tif into .tex
  1218.             mapbase = os.path.basename(map)
  1219.             name, ext = os.path.splitext(mapbase)
  1220.             tifname = os.path.join(self.exporter.map_path, name)+".tif"
  1221.             texname = os.path.join(self.exporter.map_path, name)+".tex"
  1222.             if sys.platform=="win32":
  1223.                 tifname = tifname.replace("\\", "\\\\")
  1224.                 texname = texname.replace("\\", "\\\\")
  1225.             RiMakeTexture(tifname, texname,
  1226.                           swrap, twrap,
  1227.                           filterfunc, swidth, twidth, **params)
  1228.  
  1229.     ## protected:
  1230.  
  1231.     def copyImageMap(self, texmap):
  1232.         """Copy the texture map image into the map folder.
  1233.  
  1234.         \param texmap (\c str) Texture map name (incl. path)
  1235.         """
  1236.  
  1237.         self.exporter.checkMapPath()
  1238.         texname = os.path.basename(texmap)
  1239.         name, ext = os.path.splitext(texname)
  1240.         if ext.lower()!=".tif":
  1241.             print 'Converting "%s"'%texmap
  1242.             tifname = os.path.join(self.exporter.map_path, name+".tif")
  1243.             # Read original map
  1244.             try:
  1245.                 img = Image.open(texmap)
  1246.             except IOError, e:
  1247.                 print e
  1248.                 return
  1249.             # Save map as TIF file
  1250.             img.save(tifname)
  1251.         else:
  1252.             print 'Copying "%s"'%texmap
  1253.             dest = os.path.join(self.exporter.map_path, os.path.basename(texmap))
  1254.             shutil.copyfile(texmap, dest)
  1255.  
  1256.  
  1257. ######################################################################
  1258. ####################### Geometry adapters ############################
  1259. ######################################################################
  1260.  
  1261. class BoxAdapter:
  1262.     protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[BoxGeom])
  1263.     
  1264.     def __init__(self, boxgeom, proto):
  1265.         self.geom = boxgeom
  1266.  
  1267.     def render(self, matid):
  1268.         if matid!=0:
  1269.             return
  1270.         
  1271.         lx2 = self.geom.lx/2
  1272.         ly2 = self.geom.ly/2
  1273.         lz2 = self.geom.lz/2
  1274.         A = vec3(-lx2,-ly2,-lz2)
  1275.         B = vec3( lx2,-ly2,-lz2)
  1276.         C = vec3( lx2, ly2,-lz2)
  1277.         D = vec3(-lx2, ly2,-lz2)
  1278.         E = vec3(-lx2,-ly2, lz2)
  1279.         F = vec3( lx2,-ly2, lz2)
  1280.         G = vec3( lx2, ly2, lz2)
  1281.         H = vec3(-lx2, ly2, lz2)
  1282.         RiPatch(RI_BILINEAR, P=[D,C,A,B])
  1283.         RiPatch(RI_BILINEAR, P=[A,B,E,F])
  1284.         RiPatch(RI_BILINEAR, P=[D,A,H,E])
  1285.         RiPatch(RI_BILINEAR, P=[C,D,G,H])
  1286.         RiPatch(RI_BILINEAR, P=[B,C,F,G])
  1287.         RiPatch(RI_BILINEAR, P=[E,F,H,G])
  1288.  
  1289.  
  1290. class SphereAdapter:
  1291.     protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[SphereGeom])
  1292.     
  1293.     def __init__(self, spheregeom, proto):
  1294.         self.geom = spheregeom
  1295.  
  1296.     def render(self, matid):
  1297.         if matid==0:
  1298.             r = self.geom.radius
  1299.             RiSphere(r, -r, r, 360)
  1300.         
  1301.  
  1302. class CCylinderAdapter:
  1303.     protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[CCylinderGeom])
  1304.     
  1305.     def __init__(self, ccylgeom, proto):
  1306.         self.geom = ccylgeom
  1307.  
  1308.     def render(self, matid):
  1309.         if matid!=0:
  1310.             return
  1311.         
  1312.         r = self.geom.radius
  1313.         l = self.geom.length
  1314.         l2 = l/2
  1315.         silhouette_len = pi*r+l
  1316.         cap_len = pi/2*r;
  1317.         v1 = cap_len/silhouette_len
  1318.         v2 = v1+l/silhouette_len
  1319.         
  1320.         RiCylinder(r, -l2, l2, 360, st=[0,v1, 1,v1, 0,v2, 1,v2])
  1321.         RiTransformBegin()
  1322.         RiTranslate(0,0,l2)
  1323.         RiSphere(r, 0, r, 360, st=[0,v2, 1,v2, 0,1, 1,1])
  1324.         RiTransformEnd()
  1325.         RiTransformBegin()
  1326.         RiTranslate(0,0,-l2)
  1327.         RiSphere(r, -r, 0, 360, st=[0,0, 1,0, 0,v1, 1,v1])
  1328.         RiTransformEnd()
  1329.  
  1330. class PlaneAdapter:
  1331.     protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[PlaneGeom])
  1332.     
  1333.     def __init__(self, planegeom, proto):
  1334.         self.geom = planegeom
  1335.  
  1336.     def render(self, matid):
  1337.         if matid!=0:
  1338.             return
  1339.         
  1340.         lx2 = self.geom.lx/2
  1341.         ly2 = self.geom.ly/2
  1342.         A = vec3(-lx2,-ly2,0)
  1343.         B = vec3( lx2,-ly2,0)
  1344.         C = vec3( lx2, ly2,0)
  1345.         D = vec3(-lx2, ly2,0)
  1346.         RiPatch(RI_BILINEAR, P=[A,B,D,C])
  1347.  
  1348. class TriMeshAdapter:
  1349.     protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[TriMeshGeom])
  1350.     
  1351.     def __init__(self, meshgeom, proto):
  1352.         self.geom = meshgeom
  1353.  
  1354.     def render(self, matid):
  1355.         if self.geom.findVariable("matid")!=None:
  1356.             tm = cmds.extractUniform(self.geom, "matid", matid)
  1357.             tm = cmds.removeIsolatedVertices(tm)
  1358.         else:
  1359.             if matid!=0:
  1360.                 return
  1361.             tm = self.geom
  1362.                     
  1363.         if len(tm.faces)==0:
  1364.             return
  1365.  
  1366.         if tm.findVariable("N")!=None and tm.findVariable("Nfaces")!=None:
  1367.             tm = cmds.convMeshAttr(tm, "N", "Nfaces")
  1368.  
  1369.         # Create parameter list...
  1370.         params = {"P":list(tm.verts)}
  1371.         clss = ["constant", "uniform", "varying", "vertex", "facevarying", "facevertex", "user"]
  1372.         typs = ["integer", "float", "string", "color", "point", "vector",
  1373.                "normal", "matrix", "hpoint"]
  1374.         for name, storage, type, multiplicity in tm.iterVariables():
  1375.             cls = clss[abs(storage)]
  1376.             typ = typs[abs(type)]
  1377.             if cls!="user":
  1378.                 s = tm.slot(name)
  1379.                 params[name] = list(s)
  1380.                 if multiplicity==1:
  1381.                     decl = "%s %s"%(cls, typ)
  1382.                 else:
  1383.                     decl = "%s %s[%d]"%(cls, typ, multiplicity)
  1384.                 RiDeclare(name, decl)
  1385.                 
  1386.         if hasattr(self.geom, "subdiv"):
  1387.             RiSubdivisionMesh("catmull-clark", len(tm.faces)*[3],
  1388.                               list(tm.faces), [],0,[],[], params)
  1389.         else:
  1390.             RiPointsPolygons(len(tm.faces)*[3], list(tm.faces), params)
  1391.  
  1392. class PolyhedronAdapter:
  1393.     protocols.advise(instancesProvide=[IGeometry], asAdapterForTypes=[PolyhedronGeom])
  1394.     
  1395.     def __init__(self, polyhedrongeom, proto):
  1396.         self.geom = polyhedrongeom
  1397.  
  1398.     def render(self, matid):
  1399.         if matid!=0:
  1400.             return
  1401.  
  1402.         pg = self.geom
  1403.  
  1404.         # Create parameter list...
  1405.         params = {"P":list(pg.verts)}
  1406.         clss = ["constant", "uniform", "varying", "vertex", "facevarying", "facevertex", "user"]
  1407.         typs = ["integer", "float", "string", "color", "point", "vector",
  1408.                "normal", "matrix", "hpoint"]
  1409.         for name, storage, type, multiplicity in pg.iterVariables():
  1410.             cls = clss[abs(storage)]
  1411.             typ = typs[abs(type)]
  1412.             if cls!="user":
  1413.                 s = pg.slot(name)
  1414.                 params[name] = list(s)
  1415.                 if multiplicity==1:
  1416.                     decl = "%s %s"%(cls, typ)
  1417.                 else:
  1418.                     decl = "%s %s[%d]"%(cls, typ, multiplicity)
  1419.                 RiDeclare(name, decl)
  1420.  
  1421.         nloops = []
  1422.         nverts = []
  1423.         vertids = []
  1424.         for i in range(pg.getNumPolys()):
  1425.             poly = pg.getPoly(i)
  1426.             nloops.append(len(poly))
  1427.             for loop in poly:
  1428.                 nverts.append(len(loop))
  1429.                 vertids.append(loop)
  1430.  
  1431.         if hasattr(self.geom, "subdiv"):
  1432.             if nloops==len(nloops)*[1]:
  1433.                 RiSubdivisionMesh("catmull-clark", nverts, vertids,
  1434.                                   [], 0, [], [], params)
  1435.             else:
  1436.                 print >>sys.stderr, "Warning: Polyhedron with holes in its polys can't be used as subdiv"
  1437.         else:
  1438.             RiPointsGeneralPolygons(nloops, nverts, vertids, params)
  1439.  
  1440.  
  1441. ######################################################################
  1442. ######################### Light adapters #############################
  1443. ######################################################################
  1444.  
  1445. # SpotLight3DSAdapter
  1446. class SpotLight3DSAdapter:
  1447.     protocols.advise(instancesProvide=[ILightSource], asAdapterForTypes=[SpotLight3DS])
  1448.     
  1449.     def __init__(self, lgt, proto):
  1450.         self.obj = lgt
  1451.  
  1452.     def createPasses(self):
  1453.         """Returns a list of RenderPass objects."""
  1454.         if self.obj.shadowed:
  1455.             shadpass = ShadowPass(output=[("shadow.z", "zfile", RI_Z, {})],
  1456.                                   light=self.obj, fov=self.obj.falloff,
  1457.                                   resolution = self.obj.shadow_size)
  1458.             return [shadpass]
  1459.  
  1460.         return []
  1461.  
  1462.     def shaderName(self):
  1463.         """Returns the name of the corresponding light shader or None.
  1464.         """
  1465.         return "spotlight3ds"
  1466.  
  1467.     def shaderSource(self):
  1468.         """Returns surface shader source code as a string or None.
  1469.         """
  1470.         return """// SpotLight3DS shader
  1471.         
  1472. light $SHADERNAME(float intensity = 1.0;
  1473.          uniform color lightcolor = color "rgb" (1, 1, 1);
  1474.          float falloff = 45.0;
  1475.          float hotspot = 43.0;
  1476.          float attenuation = 0;
  1477.          float inner_range = 0;
  1478.          float outer_range = 999;
  1479.          float overshoot = 0;
  1480.          float shadow_filter = 4.0;
  1481.          float shadow_bias = 0.01;
  1482.          float shadow_samples = 16;
  1483.          string shadowname = "")
  1484. {
  1485.   uniform float cosfalloff = cos(radians(0.5*falloff));
  1486.   uniform float coshotspot = cos(radians(0.5*hotspot));
  1487.   uniform vector axis = normalize(vector "shader" (0,0,1));
  1488.   float illuminate_angle;
  1489.  
  1490.   if (overshoot==0)
  1491.   {
  1492.     illuminate_angle = falloff*PI/360.0;
  1493.   }
  1494.   else
  1495.   {
  1496.     illuminate_angle = PI;
  1497.   }
  1498.   
  1499.   illuminate(point "shader" (0,0,0), axis, illuminate_angle)
  1500.   {
  1501.     vector L0 = normalize(L);
  1502.     float dist = length(L);
  1503.     float att = 1.0;
  1504.  
  1505.     // Attenuation due to hotspot/falloff
  1506.     if (overshoot==0)
  1507.     {
  1508.       float ca = L0.axis;
  1509.       att = smoothstep(cosfalloff, coshotspot, ca);
  1510.     }
  1511.  
  1512.     // Attenuation due to distance
  1513.     if (attenuation!=0)
  1514.       att *= 1.0-smoothstep(inner_range, outer_range, dist);
  1515.     
  1516.     Cl = att * intensity * lightcolor;
  1517.  
  1518.     if (shadowname!="")
  1519.       Cl *= 1 - shadow(shadowname, Ps, "width", shadow_filter, "bias", shadow_bias, "samples", shadow_samples);
  1520.     
  1521.   }
  1522. }        
  1523.         """
  1524.  
  1525.     def shaderParams(self, passes):
  1526.         """Return a dictionary with shader parameters and their values."""
  1527.         params = {"intensity":self.obj.intensity,
  1528.                 "uniform color lightcolor":self.obj.color,
  1529.                 "uniform float falloff":self.obj.falloff,
  1530.                 "uniform float attenuation":self.obj.attenuation,
  1531.                 "uniform float inner_range":self.obj.inner_range,
  1532.                 "uniform float outer_range":self.obj.outer_range,
  1533.                 "uniform float hotspot":self.obj.hotspot,
  1534.                 "uniform float overshoot":int(self.obj.overshoot)
  1535.                   }
  1536.         if self.obj.shadowed and passes[0].done():
  1537.             zfile = passes[0].realFilename(passes[0].output[0][0])
  1538.             mapname = os.path.splitext(zfile)[0]+".map"
  1539.             params["uniform string shadowname"] = mapname
  1540.             params["uniform float shadow_filter"] = self.obj.shadow_filter
  1541.             params["uniform float shadow_bias"] = self.obj.shadow_bias
  1542.         return params
  1543.  
  1544.  
  1545.  
  1546. # GLPointLightAdapter
  1547. class GLPointLightAdapter:
  1548.     protocols.advise(instancesProvide=[ILightSource], asAdapterForTypes=[GLPointLight])
  1549.     
  1550.     def __init__(self, lgt, proto):
  1551.         self.obj = lgt
  1552.  
  1553.     def createPasses(self):
  1554.         """Returns a list of RenderPass objects."""
  1555.         return []
  1556.  
  1557.     def shaderName(self):
  1558.         """Returns the name of the corresponding light shader or None.
  1559.         """
  1560.         return "glpointlight"
  1561.  
  1562.     def shaderSource(self):
  1563.         """Returns surface shader source code as a string or None.
  1564.         """
  1565.         return """// GLPointLight shader
  1566. light $SHADERNAME(float intensity = 1.0;
  1567.          color diffuse = color "rgb" (1, 1, 1);
  1568.          color specular = color "rgb" (1, 1, 1);
  1569.          float constant_attenuation = 1;
  1570.          float linear_attenuation = 0;
  1571.          float quadratic_attenuation = 0)         
  1572. {
  1573.   illuminate(point "shader" (0,0,0))
  1574.   {
  1575.     float d = length(L);
  1576.     float att = 1.0/(constant_attenuation + linear_attenuation*d + quadratic_attenuation*d*d);
  1577.     
  1578.     Cl = att*intensity*color "rgb" (1,1,1);
  1579.   }
  1580. }        
  1581.         """
  1582.  
  1583.     def shaderParams(self, passes):
  1584.         """Return a dictionary with shader parameters and their values."""
  1585.         return {"intensity":self.obj.intensity,
  1586.                 "uniform color diffuse":self.obj.diffuse,
  1587.                 "uniform color specular":self.obj.specular,
  1588.                 "uniform float constant_attenuation":self.obj.constant_attenuation,
  1589.                 "uniform float linear_attenuation":self.obj.linear_attenuation,
  1590.                 "uniform float quadratic_attenuation":self.obj.quadratic_attenuation}
  1591.  
  1592.  
  1593. # GLSpotLightAdapter
  1594. class GLSpotLightAdapter:
  1595.     protocols.advise(instancesProvide=[ILightSource], asAdapterForTypes=[GLTargetSpotLight, GLFreeSpotLight])
  1596.     
  1597.     def __init__(self, lgt, proto):
  1598.         self.obj = lgt
  1599.  
  1600.     def createPasses(self):
  1601.         """Returns a list of RenderPass objects."""
  1602.         if hasattr(self.obj, "shadowmap"):
  1603.             res,width,blur,bias,samples = self.obj.shadowmap
  1604.             shadpass = ShadowPass(output=[("shadow.z", "zfile", RI_Z, {})],
  1605.                                   light=self.obj, fov=self.obj.cutoff,
  1606.                                   resolution = res)
  1607.             return [shadpass]
  1608.  
  1609.         return []
  1610.  
  1611.     def shaderName(self):
  1612.         """Returns the name of the corresponding light shader or None.
  1613.         """
  1614.         return "glspotlight"
  1615.  
  1616.     def shaderSource(self):
  1617.         """Returns surface shader source code as a string or None.
  1618.         """
  1619.         return """// GLSpotLight shader
  1620. light $SHADERNAME(float intensity = 1.0;
  1621.          uniform color diffuse = color "rgb" (1, 1, 1);
  1622.          uniform color specular = color "rgb" (1, 1, 1);
  1623.          float constant_attenuation = 1;
  1624.          float linear_attenuation = 0;
  1625.          float quadratic_attenuation = 0;
  1626.          float exponent = 0.0;
  1627.          float cutoff = 45.0;
  1628.          string shadowname = "";
  1629.          float width = 1.0;
  1630.          float blur = 0.0;
  1631.          float bias = 0.1;
  1632.          float samples = 16;)
  1633. {
  1634.   float cutoff_rad = cutoff*PI/180.0;
  1635.   
  1636.   illuminate(point "shader" (0,0,0), vector "shader" (0,0,1), cutoff_rad)
  1637.   {
  1638.     float d = length(L);
  1639.     float att = 1.0/(constant_attenuation + linear_attenuation*d + quadratic_attenuation*d*d);
  1640.     
  1641.     vector Lshad = normalize(vtransform("shader", L));
  1642.     float sp = max(zcomp(Lshad), 0);
  1643.     float spot = 0;
  1644.     if (sp>=cos(cutoff_rad))
  1645.     {
  1646.       spot = pow(sp, exponent);
  1647.     }
  1648.     
  1649.     Cl = att * spot * intensity * color "rgb" (1,1,1);
  1650.  
  1651.     if (shadowname!="")
  1652.       Cl *= 1 - shadow(shadowname, Ps, "blur", blur, "width", width, "bias", bias, "samples", samples);
  1653.     
  1654.   }
  1655. }        
  1656.         """
  1657.  
  1658.     def shaderParams(self, passes):
  1659.         """Return a dictionary with shader parameters and their values."""
  1660.         params = {"intensity":self.obj.intensity,
  1661.                 "uniform color diffuse":self.obj.diffuse,
  1662.                 "uniform color specular":self.obj.specular,
  1663.                 "uniform float constant_attenuation":self.obj.constant_attenuation,
  1664.                 "uniform float linear_attenuation":self.obj.linear_attenuation,
  1665.                 "uniform float quadratic_attenuation":self.obj.quadratic_attenuation,
  1666.                 "uniform float exponent":self.obj.exponent,
  1667.                 "uniform float cutoff":self.obj.cutoff}
  1668.         if hasattr(self.obj, "shadowmap") and passes[0].done():
  1669.             res,width,blur,bias,samples = self.obj.shadowmap
  1670.             zfile = passes[0].realFilename(passes[0].output[0][0])
  1671.             mapname = os.path.splitext(zfile)[0]+".map"
  1672.             params["uniform string shadowname"] = mapname
  1673.             params["uniform float width"] = width
  1674.             params["uniform float blur"] = blur
  1675.             params["uniform float bias"] = bias
  1676.             params["uniform float samples"] = samples
  1677.         return params
  1678.  
  1679. # GLDistantLightAdapter
  1680. class GLDistantLightAdapter:
  1681.     protocols.advise(instancesProvide=[ILightSource], asAdapterForTypes=[GLTargetDistantLight, GLFreeDistantLight])
  1682.     
  1683.     def __init__(self, lgt, proto):
  1684.         self.obj = lgt
  1685.  
  1686.     def createPasses(self):
  1687.         """Returns a list of RenderPass objects."""
  1688.         return []
  1689.  
  1690.     def shaderName(self):
  1691.         """Returns the name of the corresponding light shader or None.
  1692.         """
  1693.         return "gldistantlight"
  1694.  
  1695.     def shaderSource(self):
  1696.         """Returns surface shader source code as a string or None.
  1697.         """
  1698.         return """// GLDistantLight shader
  1699. light $SHADERNAME(float intensity = 1.0;
  1700.          uniform color diffuse = color "rgb" (1, 1, 1);
  1701.          uniform color specular = color "rgb" (1, 1, 1))
  1702. {
  1703.   solar(vector "shader" (0,0,1), PI/2)
  1704.   {
  1705.     Cl = intensity * color "rgb" (1,1,1);
  1706.   }
  1707. }        
  1708.         """
  1709.  
  1710.     def shaderParams(self, passes):
  1711.         """Return a dictionary with shader parameters and their values."""
  1712.         return {"intensity":self.obj.intensity,
  1713.                 "uniform color diffuse":self.obj.diffuse,
  1714.                 "uniform color specular":self.obj.specular}
  1715.  
  1716.  
  1717. ######################################################################
  1718. ####################### Material adapters ############################
  1719. ######################################################################
  1720.  
  1721.  
  1722. # GLMaterialAdapter
  1723. class GLMaterialAdapter:
  1724.     """
  1725.     """
  1726.  
  1727.     protocols.advise(instancesProvide=[IMaterial], asAdapterForTypes=[GLMaterial])
  1728.  
  1729.     def __init__(self, material, proto):
  1730.         self.mat = material
  1731.  
  1732.     def createPasses(self):
  1733.         """Returns a list of RenderPass objects."""
  1734.         if self.mat.getTexture(0)==None:
  1735.             return []
  1736.         
  1737.         tex = self.mat.getTexture(0)
  1738.         return [TexPass(maps=[(tex.imagename, "periodic", "periodic", "gaussian", 1, 1, {})])]
  1739.  
  1740.     def preProcess(self, exporter):
  1741.         """Preprocessing method.
  1742.  
  1743.         This method is called before the image is rendered and can be used
  1744.         to create or copy image maps.
  1745.         """
  1746.         pass
  1747.  
  1748.     def color(self):
  1749.         """Return the color for the RiColor() call or None.
  1750.         """
  1751.         return self.mat.diffuse
  1752.  
  1753.     def opacity(self):
  1754.         """Return the opacity for the RiOpacity() call or None.
  1755.         """
  1756.         return None
  1757. #        a = self.mat.diffuse.w
  1758. #        return (a,a,a)
  1759.  
  1760.     def surfaceShaderName(self):
  1761.         """Returns the name of the corresponding surface shader or None.
  1762.         """
  1763.         return "glmaterial"
  1764.  
  1765.     def surfaceShaderSource(self):
  1766.         """Returns surface shader source code as a string or None.
  1767.  
  1768.         If the return value is None, then shaderName() must return
  1769.         the name of the shader to use.
  1770.         """
  1771.         ambient = self.mat.ambient
  1772.         emission = self.mat.emission
  1773.         return """// GLMaterial shader
  1774. surface $SHADERNAME(color ambient = color "rgb" (0.2, 0.2, 0.2);
  1775.            color specular = color "rgb" (0, 0, 0);
  1776.            float shininess = 0.0;
  1777.            color emission = color "rgb" (0, 0, 0);
  1778.            float diffuse_alpha = 1.0;
  1779.            string texname = "";
  1780.            float T[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
  1781.            float mode = 0;
  1782.            color texenvcolor = color "rgb" (1,1,1);
  1783.            float texenvcolor_alpha = 1;
  1784.            float blend_sfactor = -1;
  1785.            float blend_dfactor = -1;
  1786.            varying point Pref = point(0,0,0);
  1787.            )
  1788. {
  1789.   BAKE_BEGIN
  1790.   normal Nf = BAKE_NORMAL(N);
  1791.   vector V = normalize(-I);
  1792.   color diffuse = Cs;
  1793.  
  1794.   Ci = emission + 0*ambient;
  1795.   illuminance(P, Nf, PI/2)
  1796.   {
  1797.     vector L0 = normalize(L);
  1798.     vector S = normalize(L0+V);
  1799.     float NL = max(Nf.L0, 0);
  1800.     float fi = (NL!=0)? 1 : 0;
  1801.  
  1802.     color diffuse_lgt = color "rgb" (1,1,1);
  1803.     color specular_lgt = color "rgb" (1,1,1);
  1804.     lightsource("diffuse", diffuse_lgt);
  1805.     lightsource("specular", specular_lgt);
  1806.     
  1807.     Ci += Cl*(diffuse*diffuse_lgt*NL +
  1808.               fi*specular*specular_lgt*pow(max(Nf.S, 0), shininess) );
  1809.   }
  1810.  
  1811.   if (texname!="")
  1812.   {
  1813.     float ss = T[0]*s + T[1]*t + T[3];
  1814.     float tt = T[4]*s + T[5]*t + T[7];
  1815.     float dn = T[12]*s + T[13]*t + T[15];
  1816.     color texcolor = texture(texname, ss/dn, tt/dn);
  1817.     if (mode==0)  // GL_REPLACE
  1818.     {
  1819.       Ci = texcolor;
  1820.     }
  1821.     else if (mode==1)  // GL_MODULATE
  1822.     {
  1823.       Ci = texcolor*Ci;
  1824.     }
  1825.     else if (mode==2)  // GL_DECAL
  1826.     {
  1827.       Ci = texcolor;
  1828.     }
  1829.     else  // GL_BLEND
  1830.     {
  1831.       Ci = Ci*(color "rgb" (1,1,1)-texcolor) + texenvcolor*texcolor;
  1832.     }
  1833.   }
  1834.  
  1835.   Oi = 1;
  1836.  
  1837.   if (blend_sfactor!=-1 && blend_dfactor!=-1)
  1838.   {
  1839.     color S = 0;
  1840.     color D = 0;
  1841.  
  1842.     if (blend_sfactor==1)
  1843.       S = 1;
  1844.     else if (blend_sfactor==3)
  1845.       S = Ci;
  1846.     else if (blend_sfactor==5)
  1847.       S = 1-Ci;
  1848.     else if (blend_sfactor==6)
  1849.       S = diffuse_alpha;
  1850.     else if (blend_sfactor==7)
  1851.       S = 1-diffuse_alpha;
  1852.  
  1853.     if (blend_dfactor==1)
  1854.       D = 1;
  1855.     else if (blend_dfactor==3)
  1856.       D = Ci;
  1857.     else if (blend_dfactor==5)
  1858.       D = 1-Ci;
  1859.     else if (blend_dfactor==6)
  1860.       D = diffuse_alpha;
  1861.     else if (blend_dfactor==7)
  1862.       D = 1-diffuse_alpha;
  1863.     
  1864.     Ci = S*Ci;
  1865.     Oi = 1-D;
  1866.   }
  1867.   BAKE_END
  1868. }        
  1869.         """
  1870.  
  1871.     def surfaceShaderParams(self, passes):
  1872.         """Return a dictionary with shader parameters and their values."""
  1873.         blend_dict = { GL_ZERO : 0,
  1874.                        GL_ONE : 1,
  1875.                        GL_DST_COLOR : 2,
  1876.                        GL_SRC_COLOR : 3,
  1877.                        GL_ONE_MINUS_DST_COLOR : 4,
  1878.                        GL_ONE_MINUS_SRC_COLOR : 5,
  1879.                        GL_SRC_ALPHA : 6,
  1880.                        GL_ONE_MINUS_SRC_ALPHA : 7,
  1881.                        GL_DST_ALPHA : 8,
  1882.                        GL_ONE_MINUS_DST_ALPHA : 9,
  1883.                        GL_SRC_ALPHA_SATURATE : 10
  1884.                      }
  1885.         sfactor = blend_dict.get(self.mat.blend_sfactor, -1)
  1886.         dfactor = blend_dict.get(self.mat.blend_dfactor, -1)
  1887.         res = {"uniform float shininess" : self.mat.shininess,
  1888.                "uniform color specular" : tuple(self.mat.specular)[:3],
  1889.                "uniform color ambient" : tuple(self.mat.ambient)[:3],
  1890.                "uniform color emission" : tuple(self.mat.emission)[:3],
  1891.                "uniform float blend_sfactor" : sfactor,
  1892.                "uniform float blend_dfactor" : dfactor,
  1893.                "uniform float diffuse_alpha" : self.mat.diffuse.w
  1894.                }
  1895.  
  1896.         if self.mat.getTexture(0)!=None:
  1897.             tex = self.mat.getTexture(0)
  1898.             # Image name
  1899.             n = os.path.basename(tex.imagename)
  1900.             name,ext = os.path.splitext(n)
  1901.             res["uniform string texname"] = name+".tex"
  1902.             # Mode
  1903.             try:
  1904.                 res["uniform float mode"] = [GL_REPLACE, GL_MODULATE, GL_DECAL, GL_BLEND].index(tex.mode)
  1905.             except:
  1906.                 pass
  1907.             res["uniform color texenvcolor"] = tuple(tex.texenvcolor)[:3]
  1908.             res["uniform float texenvcolor_alpha"] = tex.texenvcolor.w
  1909.             res["uniform float [16] T"] = tex.transform.transpose()
  1910.       
  1911.         return res
  1912.  
  1913.     def surfaceShaderTransform(self):
  1914.         return mat4(1)
  1915.  
  1916.     def displacementShaderName(self):
  1917.         return None
  1918.     
  1919.     def displacementShaderSource(self):
  1920.         return None
  1921.     
  1922.     def displacementShaderParams(self, passes):
  1923.         return {}
  1924.  
  1925.     def displacementShaderTransform(self):
  1926.         return mat4(1)
  1927.  
  1928.     def displacementBound(self):
  1929.         return "current", 0
  1930.     
  1931.     def interiorShaderName(self):
  1932.         return None
  1933.     
  1934.     def interiorShaderSource(self):
  1935.         return None
  1936.     
  1937.     def interiorShaderParams(self, passes):
  1938.         return {}
  1939.  
  1940.     def interiorShaderTransform(self):
  1941.         return mat4(1)
  1942.  
  1943.  
  1944. ######################################################################
  1945.  
  1946. # Register the OffImporter class as a plugin class
  1947. pluginmanager.register(RIBExporter)
  1948.