LuxBlend_0.1.py
author jensverwiebe
Tue Oct 13 20:33:01 2009 +0200 (2009-10-13)
changeset 414 bc1e3bef1607
parent 413 728fbc9db8b2
child 416 6ad00238e6be
child 423 83cdf52989cd
permissions -rw-r--r--
tagging for v0.6
     1 #!BPY
     2 # -*- coding: utf-8 -*-
     3 # coding=utf-8
     4 """Registration info for Blender menus:
     5 Name: 'LuxBlend v0.6 Exporter'
     6 Blender: 248
     7 Group: 'Render'
     8 Tooltip: 'Export/Render to LuxRender v0.6 scene format (.lxs)'
     9 """
    10 
    11 __author__ = "radiance, zuegs, ideasman42, luxblender, dougal2"
    12 __version__ = "0.6"
    13 __url__ = [
    14 	"http://www.luxrender.net/",
    15 	"http://www.luxrender.net/forum/viewforum.php?f=11",
    16 	"http://www.luxrender.net/wiki/index.php/Tutorial_1:_Your_first_scene_%26_render"
    17 ]
    18 __bpydoc__ = """\
    19 LuxRender is an open-source rendering system for physically correct, unbiased image synthesis.
    20 This is the Luxrender Blender Export Script.
    21 
    22 Useful links:
    23 - For updates: http://www.luxrender.net/forum/viewforum.php?f=11
    24 - For Blender Tutorial: http://www.luxrender.net/wiki/index.php/Tutorial_1:_Your_first_scene_%26_render
    25 
    26 Usage: 
    27 - Run the script from the render menu.
    28 - Set the default location of the Luxrender.exe.
    29 
    30 Please check the lux tutorials & forums for more information.
    31 """
    32 
    33 #
    34 # ***** BEGIN GPL LICENSE BLOCK *****
    35 #
    36 # --------------------------------------------------------------------------
    37 # LuxBlend v0.6 exporter
    38 # --------------------------------------------------------------------------
    39 #
    40 # Authors:
    41 # radiance, zuegs, ideasman42, luxblender, dougal2
    42 #
    43 # This program is free software; you can redistribute it and/or
    44 # modify it under the terms of the GNU General Public License
    45 # as published by the Free Software Foundation; either version 2
    46 # of the License, or (at your option) any later version.
    47 #
    48 # This program is distributed in the hope that it will be useful,
    49 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    50 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    51 # GNU General Public License for more details.
    52 #
    53 # You should have received a copy of the GNU General Public License
    54 # along with this program; if not, write to the Free Software Foundation,
    55 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    56 #
    57 # ***** END GPL LICENCE BLOCK *****
    58 # --------------------------------------------------------------------------
    59 
    60 
    61 
    62 
    63 ######################################################
    64 # Importing modules
    65 ######################################################
    66 
    67 import math
    68 import time
    69 import os
    70 import sys as osys
    71 import types
    72 import subprocess
    73 import Blender
    74 from Blender import Mesh, Scene, Object, Material, Texture, Window, sys, Draw, BGL, Mathutils, Lamp, Image
    75 
    76 
    77 
    78 
    79 ######################################################
    80 # Functions
    81 ######################################################
    82 
    83 # New name based on old with a different extension
    84 def newFName(ext):
    85     return Blender.Get('filename')[: -len(Blender.Get('filename').split('.', -1)[-1]) ] + ext
    86 
    87 
    88 # some helpers
    89 def luxstr(str):
    90     return str.replace("\\", "\\\\")
    91 
    92 
    93 ### relpath ##########################
    94 def relpath(base, target):
    95     if target[0:2] == "\\\\" or target[0:2] == "//":
    96         return target[2:len(target)]
    97     if not os.path.isabs(base):
    98         base = os.path.abspath(base)
    99     if not os.path.isabs(target):
   100         target = os.path.abspath(target)
   101     if os.sep == "\\":
   102         base = os.path.normcase(base)
   103         target = os.path.normcase(target)
   104     if base == os.sep:
   105         return '.' + target
   106     baselist = base.split(os.sep)
   107     if baselist[-1] == "":
   108         baselist = baselist[:-1]
   109     targetlist = target.split(os.sep)
   110     i = 0
   111     top = min([len(baselist), len(targetlist)])
   112     while i < top and baselist[i] == targetlist[i]:
   113         i+=1
   114     if i == 0:
   115         return os.sep.join(targetlist)
   116     if i == len(baselist):
   117         return os.sep.join(targetlist[i:])
   118     else:
   119         return ('..' + os.sep) * (len(baselist) - i) + os.sep.join(targetlist[i:])
   120 
   121 ### luxFilePath #####################
   122 lxs_filename = ""
   123 previewing = False
   124 def luxFilePath(filename):
   125     global lxs_filename, previewing
   126     scn = Scene.GetCurrent()
   127     pm = luxProp(scn, "pathmode", "absolute").get()
   128     if (pm=="absolute") or previewing: # absolute paths (the old / default mode)
   129         return filename
   130     elif pm=="relative": # relative paths
   131         base = os.path.dirname(lxs_filename)
   132         return relpath(base, filename)
   133     elif pm=="flat": # flat mode - only filename
   134         return os.path.basename(filename)
   135 
   136 
   137 
   138 ###### RGC ##########################
   139 def rg(col):
   140     scn = Scene.GetCurrent()
   141     if luxProp(scn, "RGC", "true").get()=="true":
   142         gamma = luxProp(scn, "film.gamma", 2.2).get()
   143     else:
   144         gamma = 1.0
   145     ncol = col**gamma
   146     if luxProp(scn, "colorclamp", "false").get()=="true":
   147         ncol = ncol * 0.9
   148         if ncol > 0.9:
   149             ncol = 0.9
   150         if ncol < 0.0:
   151             ncol = 0.0
   152     return ncol
   153 
   154 def texturegamma():
   155     scn = Scene.GetCurrent()
   156     if luxProp(scn, "RGC", "true").get()=="true":
   157         return luxProp(scn, "film.gamma", 2.2).get()
   158     else:
   159         return 1.0
   160 
   161 def exportMaterial(mat):
   162     str = "# Material '%s'\n" %mat.name
   163     return str+luxMaterial(mat)+"\n"
   164 
   165 
   166 def exportMaterialGeomTag(mat):
   167     return "%s\n"%(luxProp(mat, "link", "").get())
   168 
   169 
   170 
   171 
   172 ################################################################
   173 
   174 
   175 dummyMat = 2394723948 # random identifier for dummy material
   176 clayMat = None
   177 
   178 #-------------------------------------------------
   179 # getMaterials(obj)
   180 # helper function to get the material list of an object in respect of obj.colbits
   181 #-------------------------------------------------
   182 def getMaterials(obj, compress=False):
   183     global clayMat
   184     mats = [None]*16
   185     colbits = obj.colbits
   186     objMats = obj.getMaterials(1)
   187     data = obj.getData(mesh=1)
   188     try:
   189         dataMats = data.materials
   190     except:
   191         try:
   192             dataMats = data.getMaterials(1)
   193         except:
   194             dataMats = []
   195             colbits = 0xffff
   196     m = max(len(objMats), len(dataMats))
   197     if m>0:
   198         objMats.extend([None]*16)
   199         dataMats.extend([None]*16)
   200         for i in range(m):
   201             if (colbits & (1<<i) > 0):
   202                 mats[i] = objMats[i]
   203             else:
   204                 mats[i] = dataMats[i]
   205         if compress:
   206             mats = [m for m in mats if m]
   207     
   208     slots = [m for m in mats if m]
   209     if m==0 or not slots:
   210         print("Warning: object %s has no material assigned" % (obj.getName()))
   211         mats = []
   212     # clay option
   213     if luxProp(Scene.GetCurrent(), "clay", "false").get()=="true":
   214         if clayMat==None: clayMat = Material.New("lux_clayMat")
   215         for i in range(len(mats)):
   216             if mats[i]:
   217                 mattype = luxProp(mats[i], "type", "").get()
   218                 if (mattype not in ["portal","light","boundvolume"]): mats[i] = clayMat
   219     return mats
   220 
   221 
   222 
   223 ######################################################
   224 # luxExport class
   225 ######################################################
   226 
   227 class luxExport:
   228     #-------------------------------------------------
   229     # __init__
   230     # initializes the exporter object
   231     #-------------------------------------------------
   232     def __init__(self, scene):
   233         self.scene = scene
   234         self.camera = scene.objects.camera
   235         self.objects = []
   236         self.portals = []
   237         self.volumes = []
   238         self.meshes = {}
   239         self.materials = []
   240         self.lights = []
   241         self.duplis = set()
   242 
   243     #-------------------------------------------------
   244     # analyseObject(self, obj, matrix, name)
   245     # called by analyseScene to build the lists before export
   246     #-------------------------------------------------
   247     def analyseObject(self, obj, matrix, name, isOriginal=True, isDupli=False):
   248         light = False
   249         if (obj.users > 0):
   250             obj_type = obj.getType()
   251             if (obj.enableDupFrames and isOriginal):
   252                 for o, m in obj.DupObjects:
   253                     self.analyseObject(o, m, "%s.%s"%(name, o.getName()), False)    
   254             if (obj.enableDupGroup or obj.enableDupVerts or obj.enableDupFaces):
   255                 self.duplis.add(obj)
   256                 for o, m in obj.DupObjects:
   257                     self.analyseObject(o, m, "%s.%s"%(name, o.getName()), True, True)    
   258             elif ((isDupli or (not obj.getParent() in self.duplis)) and ((obj_type == "Mesh") or (obj_type == "Surf") or (obj_type == "Curve") or (obj_type == "Text"))):
   259                 mats = getMaterials(obj)
   260                 if (len(mats)>0) and (mats[0]!=None) and ((mats[0].name=="PORTAL") or (luxProp(mats[0], "type", "").get()=="portal")):
   261                     self.portals.append([obj, matrix])
   262                 elif (len(mats)>0) and (luxProp(mats[0], "type", "").get()=="boundvolume"):
   263                     self.volumes.append([obj, matrix])
   264                 else:
   265                     for mat in mats:
   266                         if (mat!=None) and (mat not in self.materials):
   267                             self.materials.append(mat)
   268                         if (mat!=None) and ((luxProp(mat, "type", "").get()=="light") or (luxProp(mat, "emission", "false").get()=="true")):
   269                             light = True
   270                     mesh_name = obj.getData(name_only=True)
   271                     try:
   272                         self.meshes[mesh_name] += [obj]
   273                     except KeyError:
   274                         self.meshes[mesh_name] = [obj]                
   275                     self.objects.append([obj, matrix])
   276             elif (obj_type == "Lamp"):
   277                 ltype = obj.getData(mesh=1).getType() # data
   278                 if (ltype == Lamp.Types["Lamp"]) or (ltype == Lamp.Types["Spot"]) or (ltype == Lamp.Types["Area"]):
   279                     self.lights.append([obj, matrix])
   280                     light = True
   281         return light
   282 
   283     #-------------------------------------------------
   284     # analyseScene(self)
   285     # this function builds the lists of object, lights, meshes and materials before export
   286     #-------------------------------------------------
   287     def analyseScene(self):
   288         light = False
   289         for obj in self.scene.objects:
   290             if ((obj.Layers & self.scene.Layers) > 0):
   291                 if self.analyseObject(obj, obj.getMatrix(), obj.getName()): light = True
   292         return light
   293 
   294     #-------------------------------------------------
   295     # exportMaterialLink(self, file, mat)
   296     # exports material link. LuxRender "Material" 
   297     #-------------------------------------------------
   298     def exportMaterialLink(self, file, mat):
   299         if mat == dummyMat:
   300             file.write("\tMaterial \"matte\" # dummy material\n")
   301         else:
   302             file.write("\t%s"%exportMaterialGeomTag(mat)) # use original methode
   303 
   304     #-------------------------------------------------
   305     # exportMaterial(self, file, mat)
   306     # exports material. LuxRender "Texture" 
   307     #-------------------------------------------------
   308     def exportMaterial(self, file, mat):
   309         print("material %s"%(mat.getName()))
   310         file.write("\t%s"%exportMaterial(mat)) # use original methode        
   311     
   312     #-------------------------------------------------
   313     # exportMaterials(self, file)
   314     # exports materials to the file
   315     #-------------------------------------------------
   316     def exportMaterials(self, file):
   317         for mat in self.materials:
   318             
   319             self.exportMaterial(file, mat)
   320 
   321     #-------------------------------------------------
   322     # getMeshType(self, vertcount, mat)
   323     # returns type of mesh as string to use depending on thresholds
   324     #-------------------------------------------------
   325     def getMeshType(self, vertcount, mat):
   326         scn = Scene.GetCurrent()
   327         if mat != dummyMat:
   328             usesubdiv = luxProp(mat, "subdiv", "false")
   329             usedisp = luxProp(mat, "dispmap", "false")
   330             sharpbound = luxProp(mat, "sharpbound", "false")
   331             nsmooth = luxProp(mat, "nsmooth", "true")
   332             sdoffset = luxProp(mat, "sdoffset", 0.0)
   333             dstr = ""
   334             if usesubdiv.get() == "true":
   335                 nlevels = luxProp(mat, "sublevels", 1)
   336                 dstr += "\"loopsubdiv\" \"integer nlevels\" [%i] \"bool dmnormalsmooth\" [\"%s\"] \"bool dmsharpboundary\" [\"%s\"]"% (nlevels.get(), nsmooth.get(), sharpbound.get())
   337             
   338             if usedisp.get() == "true":
   339                 dstr += " \"string displacementmap\" [\"%s::dispmap.scale\"] \"float dmscale\" [-1.0] \"float dmoffset\" [%f]"%(mat.getName(), sdoffset.get()) # scale is scaled in texture
   340 
   341             if dstr != "": return dstr
   342 
   343         return "\"trianglemesh\""
   344 
   345     #-------------------------------------------------
   346     # exportMesh(self, file, mesh, mats, name, portal)
   347     # exports mesh to the file without any optimization
   348     #-------------------------------------------------
   349     def exportMesh(self, file, mesh, mats, name, portal=False):
   350         if mats == []:
   351             mats = [dummyMat]
   352         for matIndex in range(len(mats)):
   353             if (mats[matIndex] != None):
   354                 mesh_str = getMeshType(len(mesh.verts), mats[matIndex])
   355                 if (portal):
   356                     file.write("\tShape %s \"integer indices\" [\n"% mesh_str)
   357                 else:
   358                     self.exportMaterialLink(file, mats[matIndex])
   359                     file.write("\tPortalShape %s \"integer indices\" [\n"% mesh_str)
   360                 index = 0
   361                 ffaces = [f for f in mesh.faces if f.mat == matIndex]
   362                 for face in ffaces:
   363                     file.write("%d %d %d\n"%(index, index+1, index+2))
   364                     if (len(face)==4):
   365                         file.write("%d %d %d\n"%(index, index+2, index+3))
   366                     index += len(face.verts)
   367                 file.write("\t] \"point P\" [\n")
   368                 for face in ffaces:
   369                     for vertex in face:
   370                         file.write("%f %f %f\n"% tuple(vertex.co))
   371                 file.write("\t] \"normal N\" [\n")
   372                 for face in ffaces:
   373                     normal = face.no
   374                     for vertex in face:
   375                         if (face.smooth):
   376                             normal = vertex.no
   377                         file.write("%f %f %f\n"% tuple(normal))
   378                 if (mesh.faceUV):
   379                     file.write("\t] \"float uv\" [\n")
   380                     for face in ffaces:
   381                         for uv in face.uv:
   382                             file.write("%f %f\n"% tuple(uv))
   383                 file.write("\t]\n")
   384 
   385     #-------------------------------------------------
   386     # exportMeshOpt(self, file, mesh, mats, name, portal, optNormals)
   387     # exports mesh to the file with optimization.
   388     # portal: export without normals and UVs
   389     # optNormals: speed and filesize optimization, flat faces get exported without normals
   390     #-------------------------------------------------
   391     def exportMeshOpt(self, file, mesh, mats, name, portal=False, optNormals=True):
   392         shapeList, smoothFltr, shapeText = [0], [[0,1]], [""]
   393         if portal:
   394             normalFltr, uvFltr, shapeText = [0], [0], ["portal"] # portal, no normals, no UVs
   395         else:
   396             uvFltr, normalFltr, shapeText = [1], [1], ["mixed with normals"] # normals and UVs
   397             if optNormals: # one pass for flat faces without normals and another pass for smoothed faces with normals, all with UVs
   398                 shapeList, smoothFltr, normalFltr, uvFltr, shapeText = [0,1], [[0],[1]], [0,1], [1,1], ["flat w/o normals", "smoothed with normals"]
   399         if mats == []:
   400             mats = [dummyMat]
   401         usedmats = [f.mat for f in mesh.faces]
   402         for matIndex in range(len(mats)):
   403             if not matIndex in usedmats:
   404                 continue
   405             if not(portal):
   406                 mat = mats[matIndex]
   407                 if not mat:
   408                    mat = dummyMat
   409                 self.exportMaterialLink(file, mat)
   410             for shape in shapeList:
   411                 blenderExportVertexMap = []
   412                 exportVerts = []
   413                 exportFaces = []
   414                 ffaces = [f for f in mesh.faces if (f.mat == matIndex) and (f.smooth in smoothFltr[shape])]
   415                 for face in ffaces:
   416                     exportVIndices = []
   417                     index = 0
   418                     for vertex in face:
   419 #                            v = [vertex.co[0], vertex.co[1], vertex.co[2]]
   420                         v = [vertex.co]
   421                         if normalFltr[shape]:
   422                             if (face.smooth):
   423 #                                    v.extend(vertex.no)
   424                                 v.append(vertex.no)
   425                             else:
   426 #                                    v.extend(face.no)
   427                                 v.append(face.no)
   428                         if (uvFltr[shape]) and (mesh.faceUV):
   429 #                                v.extend(face.uv[index])
   430                             v.append(face.uv[index])
   431                         blenderVIndex = vertex.index
   432                         newExportVIndex = -1
   433                         length = len(v)
   434                         if (blenderVIndex < len(blenderExportVertexMap)):
   435                             for exportVIndex in blenderExportVertexMap[blenderVIndex]:
   436                                 v2 = exportVerts[exportVIndex]
   437                                 if (length==len(v2)) and (v == v2):
   438                                     newExportVIndex = exportVIndex
   439                                     break
   440                         if (newExportVIndex < 0):
   441                             newExportVIndex = len(exportVerts)
   442                             exportVerts.append(v)
   443                             while blenderVIndex >= len(blenderExportVertexMap):
   444                                 blenderExportVertexMap.append([])
   445                             blenderExportVertexMap[blenderVIndex].append(newExportVIndex)
   446                         exportVIndices.append(newExportVIndex)
   447                         index += 1
   448                     exportFaces.append(exportVIndices)
   449                 if (len(exportVerts)>0):
   450                     mesh_str = self.getMeshType(len(exportVerts), mats[matIndex])
   451                     if (portal):
   452                         file.write("\tPortalShape %s \"integer indices\" [\n"% mesh_str)
   453                     else:
   454                         file.write("\tShape %s \"integer indices\" [\n"% mesh_str)
   455                     for face in exportFaces:
   456                         file.write("%d %d %d\n"%(face[0], face[1], face[2]))
   457                         if (len(face)==4):
   458                             file.write("%d %d %d\n"%(face[0], face[2], face[3]))
   459                     file.write("\t] \"point P\" [\n")
   460 #                        for vertex in exportVerts:
   461 #                            file.write("%f %f %f\n"%(vertex[0], vertex[1], vertex[2]))
   462                     file.write("".join(["%f %f %f\n"%tuple(vertex[0]) for vertex in exportVerts]))
   463                     if normalFltr[shape]:
   464                         file.write("\t] \"normal N\" [\n")
   465 #                            for vertex in exportVerts:
   466 #                                file.write("%f %f %f\n"%(vertex[3], vertex[4], vertex[5]))
   467                         file.write("".join(["%f %f %f\n"%tuple(vertex[1]) for vertex in exportVerts])) 
   468                         if (uvFltr[shape]) and (mesh.faceUV):
   469                             file.write("\t] \"float uv\" [\n")
   470 #                                for vertex in exportVerts:
   471 #                                    file.write("%f %f\n"%(vertex[6], vertex[7]))
   472                             file.write("".join(["%f %f\n"%tuple(vertex[2]) for vertex in exportVerts])) 
   473                     else:            
   474                         if (uvFltr[shape]) and (mesh.faceUV):
   475                             file.write("\t] \"float uv\" [\n")
   476 #                                for vertex in exportVerts:
   477 #                                    file.write("%f %f\n"%(vertex[3], vertex[4]))
   478                             file.write("".join(["%f %f\n"%tuple(vertex[1]) for vertex in exportVerts])) 
   479                     file.write("\t]\n")
   480                     print("  shape(%s): %d vertices, %d faces"%(shapeText[shape], len(exportVerts), len(exportFaces)))
   481     
   482     #-------------------------------------------------
   483     # exportMeshes(self, file)
   484     # exports meshes that uses instancing (meshes that are used by at least "instancing_threshold" objects)
   485     #-------------------------------------------------
   486     def exportMeshes(self, file):
   487         scn = Scene.GetCurrent()
   488         instancing_threshold = luxProp(scn, "instancing_threshold", 2).get()
   489         mesh_optimizing = luxProp(scn, "mesh_optimizing", True).get()
   490         mesh = Mesh.New('')
   491         for (mesh_name, objs) in self.meshes.items():
   492             allow_instancing = True
   493             mats = getMaterials(objs[0]) # mats = obj.getData().getMaterials()
   494             for mat in mats: # don't instance if one of the materials is emissive
   495                 if (mat!=None) and (luxProp(mat, "type", "").get()=="light"):
   496                     allow_instancing = False
   497             for obj in objs: # don't instance if the objects with same mesh uses different materials
   498                 ms = getMaterials(obj)
   499                 if ms != mats:
   500                     allow_instancing = False
   501             if obj.modifiers.__len__() > 0:
   502                 allow_instancing = False
   503             if allow_instancing and (len(objs) > instancing_threshold):
   504                 del self.meshes[mesh_name]
   505                 mesh.getFromObject(objs[0], 0, 1)
   506                 print("blender-mesh: %s (%d vertices, %d faces)"%(mesh_name, len(mesh.verts), len(mesh.faces)))
   507                 file.write("ObjectBegin \"%s\"\n"%mesh_name)
   508 
   509                 if (mesh_optimizing):
   510                     self.exportMeshOpt(file, mesh, mats, mesh_name)
   511                 else:
   512                     self.exportMesh(file, mesh, mats, mesh_name)
   513                 file.write("ObjectEnd # %s\n\n"%mesh_name)
   514         mesh.verts = None
   515 
   516     #-------------------------------------------------
   517     # exportObjects(self, file)
   518     # exports objects to the file
   519     #-------------------------------------------------
   520     def exportObjects(self, file):
   521         scn = Scene.GetCurrent()
   522         cam = scn.getCurrentCamera().data
   523         objectmblur = luxProp(cam, "objectmblur", "true")
   524         usemblur = luxProp(cam, "usemblur", "false")
   525         mesh_optimizing = luxProp(scn, "mesh_optimizing", True).get()
   526         mesh = Mesh.New('')
   527         for [obj, matrix] in self.objects:
   528             print("object: %s"%(obj.getName()))
   529             mesh_name = obj.getData(name_only=True)
   530 
   531             motion = None
   532             if(objectmblur.get() == "true" and usemblur.get() == "true"):
   533                 # motion blur
   534                 frame = Blender.Get('curframe')
   535                 Blender.Set('curframe', frame+1)
   536                 m1 = 1.0*matrix # multiply by 1.0 to get a copy of orignal matrix (will be frame-independant) 
   537                 Blender.Set('curframe', frame)
   538                 if m1 != matrix:
   539                     print("  motion blur")
   540                     motion = m1
   541     
   542             if motion: # motion-blur only works with instances, so ensure mesh is exported as instance first
   543                 if mesh_name in self.meshes:
   544                     del self.meshes[mesh_name]
   545                     mesh.getFromObject(obj, 0, 1)
   546                     mats = getMaterials(obj)
   547                     print("  blender-mesh: %s (%d vertices, %d faces)"%(mesh_name, len(mesh.verts), len(mesh.faces)))
   548                     file.write("ObjectBegin \"%s\"\n"%mesh_name)
   549                     if (mesh_optimizing):
   550                         self.exportMeshOpt(file, mesh, mats, mesh_name)
   551                     else:
   552                         self.exportMesh(file, mesh, mats, mesh_name)
   553                     file.write("ObjectEnd # %s\n\n"%mesh_name)
   554 
   555             file.write("AttributeBegin # %s\n"%obj.getName())
   556             file.write("\tTransform [%s %s %s %s  %s %s %s %s  %s %s %s %s  %s %s %s %s]\n"\
   557                 %(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],\
   558                   matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],\
   559                   matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],\
   560                     matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]))
   561             if motion:
   562                 file.write("\tTransformBegin\n")
   563                 file.write("\t\tIdentity\n")
   564                 file.write("\t\tTransform [%s %s %s %s  %s %s %s %s  %s %s %s %s  %s %s %s %s]\n"\
   565                     %(motion[0][0], motion[0][1], motion[0][2], motion[0][3],\
   566                       motion[1][0], motion[1][1], motion[1][2], motion[1][3],\
   567                       motion[2][0], motion[2][1], motion[2][2], motion[2][3],\
   568                         motion[3][0], motion[3][1], motion[3][2], motion[3][3]))
   569                 file.write("\t\tCoordinateSystem \"%s\"\n"%(obj.getName()+"_motion"))
   570                 file.write("\tTransformEnd\n")
   571             if mesh_name in self.meshes:
   572                 mesh.getFromObject(obj, 0, 1)
   573                 mats = getMaterials(obj)
   574                 print("  blender-mesh: %s (%d vertices, %d faces)"%(mesh_name, len(mesh.verts), len(mesh.faces)))
   575                 if (mesh_optimizing):
   576                     self.exportMeshOpt(file, mesh, mats, mesh_name)
   577                 else:
   578                     self.exportMesh(file, mesh, mats, mesh_name)
   579             else:
   580                 print("  instance %s"%(mesh_name))
   581                 if motion:
   582                     file.write("\tMotionInstance \"%s\" 0.0 1.0 \"%s\"\n"%(mesh_name, obj.getName()+"_motion"))
   583                 else:
   584                     file.write("\tObjectInstance \"%s\"\n"%mesh_name)
   585             file.write("AttributeEnd\n\n")
   586         mesh.verts = None
   587 
   588     #-------------------------------------------------
   589     # exportPortals(self, file)
   590     # exports portals objects to the file
   591     #-------------------------------------------------
   592     def exportPortals(self, file):
   593         scn = Scene.GetCurrent()
   594         mesh_optimizing = luxProp(scn, "mesh_optimizing", True).get()
   595         mesh = Mesh.New('')
   596         for [obj, matrix] in self.portals:
   597             print("portal: %s"%(obj.getName()))
   598             file.write("\tTransform [%s %s %s %s  %s %s %s %s  %s %s %s %s  %s %s %s %s]\n"\
   599                 %(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],\
   600                   matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],\
   601                   matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],\
   602                     matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]))
   603             mesh_name = obj.getData(name_only=True)
   604             mesh.getFromObject(obj, 0, 1)
   605             mats = getMaterials(obj) # mats = obj.getData().getMaterials()
   606             if (mesh_optimizing):
   607                 self.exportMeshOpt(file, mesh, mats, mesh_name, True)
   608             else:
   609                 self.exportMesh(file, mesh, mats, mesh_name, True)
   610         mesh.verts = None
   611 
   612     #-------------------------------------------------
   613     # exportLights(self, file)
   614     # exports lights to the file
   615     #-------------------------------------------------
   616     def exportLights(self, file):
   617         for [obj, matrix] in self.lights:
   618             ltype = obj.getData(mesh=1).getType() # data
   619             if (ltype == Lamp.Types["Lamp"]) or (ltype == Lamp.Types["Spot"]) or (ltype == Lamp.Types["Area"]):
   620                 print("light: %s"%(obj.getName()))
   621                 if ltype == Lamp.Types["Area"]:
   622                     (str, link) = luxLight("", "", obj, None, 0)
   623                     file.write(str)
   624                 if ltype == Lamp.Types["Area"]: file.write("AttributeBegin # %s\n"%obj.getName())
   625                 else: file.write("TransformBegin # %s\n"%obj.getName())
   626                 file.write("\tTransform [%s %s %s %s  %s %s %s %s  %s %s %s %s  %s %s %s %s]\n"\
   627                     %(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],\
   628                       matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],\
   629                       matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],\
   630                         matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]))
   631                 col = obj.getData(mesh=1).col # data
   632                 energy = obj.getData(mesh=1).energy # data
   633                 if ltype == Lamp.Types["Lamp"]:
   634                     lightgroup = luxProp(obj, "light.lightgroup", "default")
   635                     if luxProp(Scene.GetCurrent(), "nolg", "false").get()!="true":
   636                         file.write("LightGroup \"%s\"\n"%lightgroup.get())
   637                     (str, link) = luxLamp("", "", obj, None, 0)
   638                     file.write(str+"LightSource \"point\""+link+"\n")
   639                 if ltype == Lamp.Types["Spot"]:
   640                     (str, link) = luxSpot("", "", obj, None, 0)
   641                     file.write(str)
   642                     proj = luxProp(obj, "light.usetexproj", "false")
   643                     if luxProp(Scene.GetCurrent(), "nolg", "false").get()!="true":
   644                         lightgroup = luxProp(obj, "light.lightgroup", "default")
   645                         file.write("LightGroup \"%s\"\n"%lightgroup.get())
   646                     if(proj.get() == "true"):
   647                         file.write("Rotate 180 0 1 0\n")
   648                         file.write("LightSource \"projection\" \"float fov\" [%f]"%(obj.getData(mesh=1).spotSize))
   649                     else:
   650                         file.write("LightSource \"spot\" \"point from\" [0 0 0] \"point to\" [0 0 -1] \"float coneangle\" [%f] \"float conedeltaangle\" [%f]"\
   651                             %(obj.getData(mesh=1).spotSize*0.5, obj.getData(mesh=1).spotSize*0.5*obj.getData(mesh=1).spotBlend)) # data
   652                     file.write(link+"\n")
   653                 if ltype == Lamp.Types["Area"]:
   654                     lightgroup = luxProp(obj, "light.lightgroup", "default")
   655                     if luxProp(Scene.GetCurrent(), "nolg", "false").get()!="true":
   656                         file.write("LightGroup \"%s\"\n"%lightgroup.get())
   657                     file.write("\tAreaLightSource \"area\"")
   658                     file.write(link)
   659 #                    file.write(luxLight("", "", obj, None, 0))
   660                     file.write("\n")
   661                     areax = obj.getData(mesh=1).getAreaSizeX()
   662                     # lamps "getAreaShape()" not implemented yet - so we can't detect shape! Using square as default
   663                     # todo: ideasman42
   664                     if (True): areay = areax
   665                     else: areay = obj.getData(mesh=1).getAreaSizeY()
   666                     file.write('\tShape "trianglemesh" "integer indices" [0 1 2 0 2 3] "point P" [-%(x)f %(y)f 0.0 %(x)f %(y)f 0.0 %(x)f -%(y)f 0.0 -%(x)f -%(y)f 0.0]\n'%{"x":areax/2, "y":areay/2})
   667                 if ltype == Lamp.Types["Area"]: file.write("AttributeEnd # %s\n"%obj.getName())
   668                 else: file.write("TransformEnd # %s\n"%obj.getName())
   669                 file.write("\n")
   670 
   671 
   672     #-------------------------------------------------
   673     # exportVolumes(self, file)
   674     # exports volumes to the file
   675     #-------------------------------------------------
   676     def exportVolumes(self, file):
   677         for [obj, matrix] in self.volumes:
   678             print("volume: %s"%(obj.getName()))
   679             file.write("# Volume: %s\n"%(obj.getName()))
   680 
   681             # trickery to obtain objectspace boundingbox AABB
   682             mat = obj.matrixWorld.copy().invert()
   683             bb = [vec * mat for vec in obj.getBoundBox()]
   684             minx = miny = minz = 100000000000000.0
   685             maxx = maxy = maxz = -100000000000000.0
   686             for vec in bb:
   687                 if (vec[0] < minx): minx = vec[0]
   688                 if (vec[1] < miny): miny = vec[1]
   689                 if (vec[2] < minz): minz = vec[2]
   690                 if (vec[0] > maxx): maxx = vec[0]
   691                 if (vec[1] > maxy): maxy = vec[1]
   692                 if (vec[2] > maxz): maxz = vec[2]
   693 
   694             file.write("Transform [%s %s %s %s  %s %s %s %s  %s %s %s %s  %s %s %s %s]\n"\
   695                 %(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],\
   696                   matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],\
   697                   matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],\
   698                     matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]))
   699 
   700             str_opt = (" \"point p0\" [%f %f %f] \"point p1\" [%f %f %f]"%(minx, miny, minz, maxx, maxy, maxz))
   701             mats = getMaterials(obj)
   702             if (len(mats)>0) and (mats[0]!=None) and (luxProp(mats[0], "type", "").get()=="boundvolume"):
   703                 mat = mats[0]
   704                 (str, link) = luxMaterialBlock("", "", "", mat, None, 0, str_opt)
   705                 file.write("%s"%link)
   706                 file.write("\n\n")
   707 
   708 
   709 # Note - radiance - this is a work in progress
   710 def luxFlashBlock(camObj):
   711     str = ""
   712     str += "CoordSysTransform \"camera\"\n"
   713 
   714     str += "Texture \"camflashtex\" \"color\" \"blackbody\" \"float temperature\" [5500.0]"
   715     str += "AreaLightSource \"area\" \"texture L\" [\"camflashtex\"] \"float power\" [100.000000] \"float efficacy\" [17.000000] \"float gain\" [1.000000]\n"
   716 
   717     up = 10.0
   718 
   719     str += "Shape \"trianglemesh\" \"integer indices\" [ 0 1 2 0 2 3 ] \"point P\" [ 0.014 0.012 0.0   0.006 0.012 0.0   0.006 0.008 0.0   0.014 0.008 0.0 ]\n"
   720 
   721     return str
   722 
   723 
   724 ######################################################
   725 # EXPORT
   726 ######################################################
   727 
   728 def save_lux(filename, unindexedname):
   729     
   730     export_total_steps = 12.0
   731     
   732     global meshlist, matnames, lxs_filename, geom_filename, geom_pfilename, mat_filename, mat_pfilename, vol_filename, vol_pfilename, LuxIsGUI
   733 
   734     global render_status_text
   735     global render_status
   736     render_status_text = 'Exporting...'
   737     render_status = True
   738 
   739     print("Lux Render Export started...\n")
   740     time1 = Blender.sys.time()
   741     scn = Scene.GetCurrent()
   742 
   743     filepath = os.path.dirname(filename)
   744     filebase = os.path.splitext(os.path.basename(filename))[0]
   745 
   746     lxs_filename = filename
   747 
   748     geom_filename = os.path.join(filepath, filebase + "-geom.lxo")
   749     geom_pfilename = filebase + "-geom.lxo"
   750 
   751     mat_filename = os.path.join(filepath, filebase + "-mat.lxm")
   752     mat_pfilename = filebase + "-mat.lxm"
   753     
   754     vol_filename = os.path.join(filepath, filebase + "-vol.lxv")
   755     vol_pfilename = filebase + "-vol.lxv"
   756 
   757     ### Zuegs: initialization for export class
   758     export = luxExport(Blender.Scene.GetCurrent())
   759 
   760     # check if a light is present
   761     envtype = luxProp(scn, "env.type", "infinite").get()
   762     if envtype == "sunsky":
   763         sun = None
   764         for obj in scn.objects:
   765             if (obj.getType() == "Lamp") and ((obj.Layers & scn.Layers) > 0):
   766                 if obj.getData(mesh=1).getType() == 1: # sun object # data
   767                     sun = obj
   768     if not(export.analyseScene()) and not(envtype == "infinite") and not((envtype == "sunsky") and (sun != None)):
   769         print("ERROR: No light source found")
   770         Draw.PupMenu("ERROR: No light source found%t|OK%x1")
   771         render_status_text = ''
   772         render_status = False
   773         Blender.Window.QRedrawAll()
   774         del export
   775         return False
   776 
   777     if LuxIsGUI: DrawProgressBar(0.0/export_total_steps,'Setting up Scene file')
   778     
   779     class output_proxy():
   780         load_result = False
   781         combine_all_output = False
   782         f = None
   783         def close(self):
   784             if self.f is not None: self.f.close()
   785         def write(self, str):
   786             if self.f is not None:
   787                 self.f.write(str)
   788                 self.f.flush()
   789             
   790     class file_output(output_proxy):
   791         def __init__(self,filename):
   792             self.f = open(filename, "w")
   793             
   794     from threading import Thread
   795     class pipe_output(output_proxy, Thread):
   796         combine_all_output = True
   797         
   798         def __init__(self, xr,yr, haltspp, filename):
   799             Thread.__init__(self)
   800             
   801             self.filename = filename
   802             self.haltspp = haltspp
   803             self.xr = xr
   804             self.yr = yr
   805             
   806             if self.haltspp > 0:
   807                 bintype = "luxconsole"
   808                 self.load_result = True
   809             else:
   810                 bintype = "luxrender"
   811                
   812             print("pipe: using %s" % bintype)
   813                 
   814             self.p = get_lux_pipe(scn, 1, bintype)
   815             self.f = self.p.stdin
   816         def close(self):
   817             global render_status_text
   818             global render_status
   819             render_status = True
   820             render_status_text = "Rendering ..."
   821             Blender.Window.QRedrawAll()
   822             self.start()
   823         
   824         def run(self):
   825             if self.load_result: self.data = self.p.communicate()[0]
   826             self.f.close()
   827             if self.load_result: # self.load_image()
   828                 self.load_data()
   829             print("LuxRender process finished")
   830             self.update_status()
   831             
   832         def load_image(self):
   833             i = Blender.Image.Load(self.filename)
   834             i.makeCurrent()
   835             i.reload()
   836            
   837         def load_data(self):
   838             print("processing %i image bytes" % len(self.data))
   839             i = Blender.Image.New('luxrender', self.xr, self.yr, 32)
   840             raw_image = []
   841             for j in self.data:
   842                 raw_image.append(ord(j))
   843             del self.data
   844             bi = 0
   845             for y in range(self.yr-1, -1, -1):
   846                 for x in range(0, self.xr):
   847                     i.setPixelI(x,y, raw_image[bi:bi+3]+[0])
   848                     bi+=3
   849             i.makeCurrent()
   850             
   851         def update_status(self):
   852             global render_status_text
   853             global render_status
   854             render_status = False
   855             render_status_text = "Rendering complete"
   856             if self.haltspp>0: render_status_text += ", check Image Editor window"
   857             Blender.Window.QRedrawAll()
   858             
   859     use_pipe_output = luxProp(scn, "pipe", "false").get() == "true" and luxProp(scn, "run", "true").get() == "true"
   860     
   861     file = output_proxy()
   862     
   863     if luxProp(scn, "lxs", "true").get()=="true" or use_pipe_output:
   864         ##### Determine/open files
   865         if use_pipe_output:
   866             print("using pipe output")
   867             print("Exporting scene to pipe")
   868             xr,yr = get_render_resolution(scn)
   869             file = pipe_output(xr, yr,
   870                 luxProp(scn, "haltspp", 0).get(),
   871                 os.path.join(filepath, filebase + ".png")
   872             )
   873         else:
   874             print("using file output")
   875             print("Exporting scene to '" + filename + "'...\n")
   876             file = file_output(filename)
   877 
   878         ##### Write Header ######
   879         file.write("# Lux Render v0.6 Scene File\n")
   880         file.write("# Exported by LuxBlend Blender Exporter\n")
   881         file.write("\n")
   882     
   883         ##### Write camera ######
   884         camObj = scn.getCurrentCamera()
   885 
   886         if LuxIsGUI: DrawProgressBar(1.0/export_total_steps,'Exporting Camera')
   887         if camObj:
   888             print("processing Camera...")
   889             cam = camObj.data
   890             cammblur = luxProp(cam, "cammblur", "true")
   891             usemblur = luxProp(cam, "usemblur", "false")
   892 
   893             matrix = camObj.getMatrix()
   894 
   895             motion = None
   896             if(cammblur.get() == "true" and usemblur.get() == "true"):
   897                 # motion blur
   898                 frame = Blender.Get('curframe')
   899                 Blender.Set('curframe', frame+1)
   900                 m1 = 1.0*matrix # multiply by 1.0 to get a copy of original matrix (will be frame-independant) 
   901                 Blender.Set('curframe', frame)
   902                 if m1 != matrix:
   903                     # Motion detected, write endtransform
   904                     print("  motion blur")
   905                     motion = m1
   906                     pos = m1[3]
   907                     forwards = -m1[2]
   908                     target = pos + forwards
   909                     up = m1[1]
   910                     file.write("TransformBegin\n")
   911                     file.write("   LookAt %f %f %f \n       %f %f %f \n       %f %f %f\n" % ( pos[0], pos[1], pos[2], target[0], target[1], target[2], up[0], up[1], up[2] ))
   912                     file.write("   CoordinateSystem \"CameraEndTransform\"\n")
   913                     file.write("TransformEnd\n\n")
   914 
   915             # Write original lookat transform
   916             pos = matrix[3]
   917             forwards = -matrix[2]
   918             target = pos + forwards
   919             up = matrix[1]
   920             file.write("LookAt %f %f %f \n       %f %f %f \n       %f %f %f\n\n" % ( pos[0], pos[1], pos[2], target[0], target[1], target[2], up[0], up[1], up[2] ))
   921             file.write(luxCamera(camObj.data, scn.getRenderingContext()))
   922             if motion:
   923                 file.write("\n   \"string endtransform\" [\"CameraEndTransform\"]")
   924             file.write("\n")
   925         file.write("\n")
   926     
   927         if LuxIsGUI: DrawProgressBar(2.0/export_total_steps,'Exporting Film Settings')
   928         ##### Write film ######
   929         file.write(luxFilm(scn))
   930         file.write("\n")
   931 
   932         if LuxIsGUI: DrawProgressBar(3.0/export_total_steps,'Exporting Pixel Filter')
   933         ##### Write Pixel Filter ######
   934         file.write(luxPixelFilter(scn))
   935         file.write("\n")
   936     
   937         if LuxIsGUI: DrawProgressBar(4.0/export_total_steps,'Exporting Sampler')
   938         ##### Write Sampler ######
   939         file.write(luxSampler(scn))
   940         file.write("\n")
   941     
   942         if LuxIsGUI: DrawProgressBar(5.0/export_total_steps,'Exporting Surface Integrator')
   943         ##### Write Surface Integrator ######
   944         file.write(luxSurfaceIntegrator(scn))
   945         file.write("\n")
   946         
   947         if LuxIsGUI: DrawProgressBar(6.0/export_total_steps,'Exporting Volume Integrator')
   948         ##### Write Volume Integrator ######
   949         file.write(luxVolumeIntegrator(scn))
   950         file.write("\n")
   951         
   952         if LuxIsGUI: DrawProgressBar(7.0/export_total_steps,'Exporting Accelerator')
   953         ##### Write Acceleration ######
   954         file.write(luxAccelerator(scn))
   955         file.write("\n")    
   956     
   957         ########## BEGIN World
   958         file.write("\n")
   959         file.write("WorldBegin\n")
   960         file.write("\n")
   961 
   962         ########## World scale
   963         #scale = luxProp(scn, "global.scale", 1.0).get()
   964         #if scale != 1.0:
   965         #    # TODO: not working yet !!!
   966         #    # TODO: propabily scale needs to be applyed on camera coords too 
   967         #    file.write("Transform [%s 0.0 0.0 0.0  0.0 %s 0.0 0.0  0.0 0.0 %s 0.0  0.0 0.0 0 1.0]\n"%(scale, scale, scale))
   968         #    file.write("\n")
   969         
   970         if LuxIsGUI: DrawProgressBar(8.0/export_total_steps,'Exporting Environment')
   971         ##### Write World Background, Sunsky or Env map ######
   972         env = luxEnvironment(scn)
   973         if env != "":
   974             file.write("AttributeBegin\n")
   975             file.write(env)
   976             export.exportPortals(file)
   977             file.write("AttributeEnd\n")
   978             file.write("\n")    
   979 
   980     # Note - radiance - this is a work in progress
   981 #        flash = luxFlashBlock(camObj)
   982 #        if flash != "":
   983 #            file.write("# Camera flash lamp\n")
   984 #            file.write("AttributeBegin\n")
   985 #            #file.write("CoordSysTransform \"camera\"\n")
   986 #            file.write(flash)
   987 #            file.write("AttributeEnd\n\n")
   988 
   989         #### Write material & geometry file includes in scene file
   990         if not file.combine_all_output: file.write("Include \"%s\"\n\n" %(mat_pfilename))
   991         if not file.combine_all_output: file.write("Include \"%s\"\n\n" %(geom_pfilename))
   992         if not file.combine_all_output: file.write("Include \"%s\"\n\n" %(vol_pfilename))
   993         
   994     if luxProp(scn, "lxm", "true").get()=="true" or use_pipe_output:
   995         if LuxIsGUI: DrawProgressBar(9.0/export_total_steps,'Exporting Materials')
   996         ##### Write Material file #####
   997         if not file.combine_all_output: print("Exporting materials to '" + mat_filename + "'...\n")
   998         mat_file = open(mat_filename, 'w') if not file.combine_all_output else file
   999         mat_file.write("")
  1000         export.exportMaterials(mat_file)
  1001         mat_file.write("")
  1002         if not file.combine_all_output: mat_file.close()
  1003     
  1004     if luxProp(scn, "lxo", "true").get()=="true" or use_pipe_output:
  1005         if LuxIsGUI: DrawProgressBar(10.0/export_total_steps,'Exporting Geometry')
  1006         ##### Write Geometry file #####
  1007         if not file.combine_all_output: print("Exporting geometry to '" + geom_filename + "'...\n")
  1008         geom_file = open(geom_filename, 'w') if not file.combine_all_output else file
  1009         meshlist = []
  1010         geom_file.write("")
  1011         export.exportLights(geom_file)
  1012         export.exportMeshes(geom_file)
  1013         export.exportObjects(geom_file)
  1014         geom_file.write("")
  1015         if not file.combine_all_output: geom_file.close()
  1016 
  1017     if luxProp(scn, "lxv", "true").get()=="true" or use_pipe_output:
  1018         if LuxIsGUI: DrawProgressBar(11.0/export_total_steps,'Exporting Volumes')
  1019         ##### Write Volume file #####
  1020         if not file.combine_all_output: print("Exporting volumes to '" + vol_filename + "'...\n")
  1021         vol_file = open(vol_filename, 'w') if not file.combine_all_output else file
  1022         meshlist = []
  1023         vol_file.write("")
  1024         export.exportVolumes(vol_file)
  1025         vol_file.write("")
  1026         if not file.combine_all_output: vol_file.close()
  1027 
  1028     render_status_text = ''
  1029     render_status = False
  1030     Blender.Window.QRedrawAll()
  1031 
  1032     if luxProp(scn, "lxs", "true").get()=="true" or use_pipe_output:
  1033         #### Write End Tag
  1034         file.write("WorldEnd\n\n")
  1035         file.close()
  1036 
  1037     if LuxIsGUI: DrawProgressBar(12.0/export_total_steps,'Export Finished')
  1038     print("Finished.\n")
  1039     del export
  1040     
  1041     time2 = Blender.sys.time()
  1042     print("Processing time: %f\n" %(time2-time1))
  1043 
  1044     if use_pipe_output:
  1045         #if luxProp(scn, "haltspp", 0).get() > 0:
  1046             # Wait for piped luxconsole render thread to end
  1047         file.join()
  1048 
  1049         # Don't launch it again as a piped scene is started implicitly
  1050         return False
  1051 
  1052     return True
  1053 
  1054 ########################################################################
  1055 ####  Construct server string argument
  1056 ########################################################################
  1057 
  1058 def networkstring(scn):
  1059     servers_string = ""
  1060     if  (luxProp(scn,"network","false").get() == "true"):
  1061         if (luxProp(scn,"network_use_file","false").get() == "true"):
  1062             print("read network servers from file: "+ luxProp(scn,"network_file_path","false").get())
  1063             f = open(luxProp(scn,"network_file_path","false").get())
  1064             for s in f:
  1065                 s = s.strip("\n")
  1066                 print("add server :" + s)
  1067                 servers_string=servers_string+" -u "+ s
  1068             f.close
  1069         else : 
  1070              if  luxProp(scn,"network_servers","").get():
  1071                  for server in luxProp(scn,"network_servers","").get().split(","):
  1072                     servers_string=servers_string+" -u "+ server
  1073     return servers_string
  1074 
  1075 
  1076 #########################################################################
  1077 ###     LAUNCH LuxRender AND RENDER CURRENT SCENE
  1078 #########################################################################
  1079 
  1080 def get_lux_exec(scn, type="luxrender"):
  1081     
  1082     #get blenders 'bpydata' directory
  1083     datadir=Blender.Get("datadir")
  1084     
  1085     ic = luxProp(scn, "lux", "").get()
  1086     ic = Blender.sys.dirname(ic) + os.sep + type
  1087     
  1088     if osys.platform == "win32": ic = ic + ".exe"
  1089     
  1090     if type=="luxrender" and osys.platform == "darwin": ic = ic + ".app/Contents/MacOS/luxrender"
  1091     
  1092     return ic
  1093     
  1094 def get_lux_args(filename, extra_args=[], anim=False):
  1095     ostype = osys.platform
  1096     scn = Scene.GetCurrent()
  1097     
  1098     ic = get_lux_exec(scn, type=(anim and 'luxconsole' or 'luxrender'))
  1099     
  1100     servers_string = networkstring(scn)
  1101     update_int=luxProp(scn,"newtork_interval",180).get()
  1102     
  1103     checkluxpath = luxProp(scn, "checkluxpath", True).get()
  1104     if checkluxpath:
  1105         if sys.exists(ic) != 1:
  1106             Draw.PupMenu("Error: Lux renderer not found. Please set path on System page.%t|OK")
  1107             return
  1108     autothreads = luxProp(scn, "autothreads", "true").get()
  1109     threads = luxProp(scn, "threads", 1).get()
  1110     luxnice = luxProp(scn, "luxnice", 0).get()
  1111     noopengl = luxProp(scn, "noopengl", "false").get()
  1112     
  1113     if noopengl == "true":
  1114         extra_args.append("--noopengl")
  1115     
  1116     lux_args = "\"%s\" " % ic
  1117     
  1118     extra_args.append('%s'%servers_string)
  1119     extra_args.append("-i %d " % update_int)
  1120     
  1121     if autothreads != "true":
  1122         extra_args.append("--threads=%d " % threads)
  1123     
  1124     lux_args2 = ' '.join(extra_args)
  1125     
  1126     if filename == '-':
  1127         lux_args2 = " - " + lux_args2
  1128     else:
  1129         filename = "\"%s\"" % filename
  1130         lux_args2 = lux_args2 + filename
  1131         
  1132     lux_args += lux_args2
  1133     
  1134     if ostype == "win32":
  1135         prio = ""
  1136         if luxnice > 15: prio = "/low"
  1137         elif luxnice > 5: prio = "/belownormal"
  1138         elif luxnice > -5: prio = "/normal"
  1139         elif luxnice > -15: prio = "/abovenormal"
  1140         else: prio = "/high"
  1141         
  1142         if not anim:
  1143             cmd = "start /b %s \"\" %s" % (prio, lux_args)
  1144         else:
  1145             cmd = "start /WAIT %s \"\" %s" % (prio, lux_args)
  1146         
  1147 #    if ostype == "linux2" or ostype == "darwin":
  1148     else:
  1149         if not anim:
  1150             cmd = "(nice -n %d %s)&"%(luxnice, lux_args)
  1151         else:
  1152             cmd = "(nice -n %d %s)"%(luxnice, lux_args)
  1153     
  1154     return cmd, lux_args2
  1155 
  1156 def get_lux_pipe(scn, buf = 1024, type="luxconsole"):
  1157     bin = "\"%s\"" % get_lux_exec(scn, type)
  1158     
  1159     print("piping to lux binary: " + bin)
  1160     
  1161     PIPE = subprocess.PIPE
  1162     
  1163     cmd, raw_args = get_lux_args('-',
  1164         extra_args=['-b'] if type=="luxconsole" else []
  1165     )
  1166     
  1167     return subprocess.Popen(bin + raw_args, shell=True, bufsize=buf, stdin=PIPE, stdout=PIPE, stderr=PIPE)
  1168 
  1169 def launchLux(filename):
  1170     cmd, raw_args = get_lux_args(filename, extra_args=[])
  1171     print("Running Luxrender:\n"+cmd)
  1172     os.system(cmd)
  1173 
  1174 def launchLuxWait(filename, anim=False):
  1175     ostype = osys.platform
  1176     cmd, raw_args = get_lux_args(filename, extra_args=[], anim=anim)
  1177     
  1178     if ostype == "win32":
  1179         os.system(cmd)
  1180     
  1181 #    if ostype == "linux2" or ostype == "darwin":
  1182     else:
  1183         subprocess.call(cmd,shell=True)
  1184 
  1185 #### SAVE ANIMATION ####
  1186 
  1187 
  1188 #def save_anim(filename):
  1189 #    global LuxIsGUI
  1190 #    scn = Scene.GetCurrent()
  1191 #    to = luxProp(scn, 'export.threaded', 'true').get()
  1192 #    run = luxProp(scn, "run", "true").get()
  1193 #    deflt = luxProp(scn, "default", "true").get()
  1194 #    if to == 'true' and run == 'true' and deflt == 'false':
  1195 #        import threading
  1196 #        anim_thread = threading.Thread(target=save_anim_real, args=(filename,True))
  1197 #        anim_thread.start()
  1198 #    else:
  1199 #        save_anim_real(filename)
  1200 
  1201 def save_anim(filename, as_thread=False):
  1202     if as_thread: print('SAR thread started')
  1203     global MatSaved, LuxIsGUI
  1204     
  1205     MatSaved = 0
  1206     startF = Blender.Get('staframe')
  1207     endF = Blender.Get('endframe')
  1208     scn = Scene.GetCurrent()
  1209 
  1210     Run = luxProp(scn, "run", "true").get()
  1211 
  1212     if Run == "true":
  1213         haltspp = luxProp(scn, "haltspp", 0).get()
  1214         if haltspp == 0:
  1215             Draw.PupMenu("ERROR: You must set a limit for spp (Output->halt) when doing animation and the 'run' flag is switched on")
  1216             if LuxIsGUI:
  1217                 Draw.Redraw()
  1218             return
  1219 
  1220     print("\n\nRendering animation (frame %i to %i)\n\n"%(startF, endF))
  1221 
  1222     v_frame = Blender.Get('curframe')
  1223 
  1224     for i in range (startF, endF+1):
  1225         # Seems to get stuck unless we redraw the UI
  1226 #        if LuxIsGUI:
  1227 #            Window.QRedrawAll()
  1228         Blender.Set('curframe', i)
  1229         print("Rendering frame %i"%(i))
  1230         Blender.Redraw()
  1231         frameindex = ("-%05d" % (i)) + ".lxs"
  1232         indexedname = sys.makename(filename, frameindex)
  1233         unindexedname = filename
  1234         luxProp(scn, "filename", Blender.Get("filename")).set(sys.makename(filename, "-%05d" %  (Blender.Get('curframe'))))
  1235 
  1236         if Run == "true":
  1237             if save_lux(filename, unindexedname):
  1238                 launchLuxWait(filename, anim=True)
  1239         else:
  1240             save_lux(indexedname, unindexedname)
  1241 
  1242         MatSaved = 1
  1243         # Seems to get stuck unless we redraw the UI
  1244 #        if LuxIsGUI:
  1245 #            Window.QRedrawAll()
  1246             
  1247     Blender.Set('curframe', v_frame)
  1248 
  1249     print("\n\nFinished Rendering animation\n")
  1250     if as_thread: print('SAR thread finished')
  1251 
  1252 #### SAVE STILL (hackish...) ####
  1253 
  1254 #import threading
  1255 #def save_still(filename):
  1256 #    global LuxIsGUI
  1257 #    scn = Scene.GetCurrent()
  1258 #    to = luxProp(scn, 'export.threaded', 'true').get()
  1259 #    if to == 'true' and luxProp(scn, "run", "true").get() == "true":
  1260 #        import threading
  1261 #        still_thread = threading.Thread(target=save_still_real, args=(filename,))
  1262 #        still_thread.start()
  1263 #    else:
  1264 #        save_still_real(filename)
  1265 
  1266 def save_still(filename):
  1267     global MatSaved, runRenderAfterExport
  1268     scn = Scene.GetCurrent()
  1269     luxProp(scn, "filename", Blender.Get("filename")).set(sys.makename(filename, ""))
  1270     MatSaved = 0
  1271     unindexedname = filename
  1272     # Seems to get stuck unless we redraw the UI
  1273 #    if LuxIsGUI:
  1274 #        Window.QRedrawAll()
  1275     if save_lux(filename, unindexedname):
  1276         if runRenderAfterExport and luxProp(scn, "pipe", "false").get() == "false": #(run == None and luxProp(scn, "run", "true").get() == "true") or run:
  1277             launchLux(filename)
  1278             
  1279     # Seems to get stuck unless we redraw the UI
  1280 #    if LuxIsGUI:
  1281 #        Window.QRedrawAll()
  1282 
  1283 
  1284 ######################################################
  1285 # Icons
  1286 ######################################################
  1287 
  1288 def base64value(char):
  1289     if 64 < ord(char) < 91: return ord(char)-65
  1290     if 96 < ord(char) < 123: return ord(char)-97+26
  1291     if 47 < ord(char) < 58: return ord(char)-48+52
  1292     if char == '+': return 62
  1293     return 63
  1294 
  1295 def decodeIconStr(s):
  1296     buf = BGL.Buffer(BGL.GL_BYTE, [16,16,4])
  1297     offset = 0
  1298     for y in range(16):
  1299         for x in range(16):
  1300             for c in range(4):
  1301                 buf[y][x][c] = int(base64value(s[offset])*4.048)
  1302                 offset += 1
  1303     return buf
  1304 
  1305 def decodeLogoStr(s):
  1306     buf = BGL.Buffer(BGL.GL_BYTE, [18,118,4])
  1307     offset = 0
  1308     for y in range(18):
  1309         for x in range(118):
  1310             for c in range(4):
  1311                 buf[y][x][c] = int(base64value(s[offset])*4.048)
  1312                 offset += 1
  1313     return buf
  1314 
  1315 def decodeArrowStr(s):
  1316     buf = BGL.Buffer(BGL.GL_BYTE, [22,22,4])
  1317     offset = 0
  1318     for y in range(22):
  1319         for x in range(22):
  1320             for c in range(4):
  1321                 buf[y][x][c] = int(base64value(s[offset])*4.048)
  1322                 offset += 1
  1323     return buf
  1324 
  1325 def decodeBarStr(s):
  1326     buf = BGL.Buffer(BGL.GL_BYTE, [17,138,4])
  1327     offset = 0
  1328     for y in range(17):
  1329         for x in range(138):
  1330             for c in range(4):
  1331                 buf[y][x][c] = int(base64value(s[offset])*4.048)
  1332                 offset += 1
  1333     return buf
  1334 
  1335 arrow_down = decodeArrowStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///Q///G///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///3///e///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///V///////7///D///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///1///////////e///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///a///////////////7///C///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///B///5///////////////////c///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///f///////////////////////7///C///A///A///A///A///A///A///A///A///A///A///A///A///A///C///6///////////////////////////c///A///A///A///A///A///A///A///A///A///A///A///A///A///i///////////////////////////////6///C///A///A///A///A///A///A///A///A///A///A///A///G///9///////////////////////////////////e///A///A///A///A///A///A///A///A///A///A///I///n///////////////////////////////////////6///N///A///A///A///A///A///A///A///A///A///L///b///e///e///e///e///e///e///e///e///e///g///O///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1336 
  1337 arrow_right = decodeArrowStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///L///I///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///b///n///G///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///e///////9///i///C///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///e///////////////6///f///B///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///e///////////////////////5///a///A///A///A///A///A///A///A///A///A///A///A///A///A///A///e///////////////////////////////1///V///A///A///A///A///A///A///A///A///A///A///A///A///e///////////////////////////////////////3///Q///A///A///A///A///A///A///A///A///A///A///e///////////////////////////////////7///e///G///A///A///A///A///A///A///A///A///A///A///e///////////////////////////7///e///D///A///A///A///A///A///A///A///A///A///A///A///A///e///////////////////7///c///C///A///A///A///A///A///A///A///A///A///A///A///A///A///A///e///////////6///c///C///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///g///6///e///C///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///O///N///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1338 
  1339 icon_luxblend = decodeLogoStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A/gAA/gAA/gAA/gAA/gAA/gAA/gAa/gA5/gAZ/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A/gAA/gAA/gAA/gAA/gAA/gAA/gAj/gA//gAh/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A/gAA/gAA/gAA/gAA/gAA/gAA/gAC/gAO/gAC/gAB/gAS/gAQ/gAA/gAA/gAA/gAA/gAA///A///A///A/gAA/gAZ/gAu/gA7/gA//gA//gA//gA//gA//gA//gA//gAd/gAA/gAZ/gAu/gA//gA//gA//gA//gA//gA//gA3/gAm/gAI/gAE/gAz/gA//gA//gAZ/gAA/gAA/gAA/gAZ/gA//gA//gAm/gAR/gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gAz/gAd/gAE/gAA/gA//gA//gAd/gAA/gAI/gAm/gA3/gA//gA//gA//gAR/gAA/gAA/gAA/gAA/gAA/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA//gAA/gAE/gAd/gAz/gA//gA//gA//gA//gA//gA7/gAq/gAV/gAA///A///A///A///A///A///A/gAA/gAA/gAA/gAI/gAK/gAA/gAA/gAA/gAA/gAn/gA//gA//gAc/gAA/gAA/gAA/gAA///A///A///A/gAi/gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gAd/gAZ/gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gA7/gAE/gAE/gAz/gA//gA//gAR/gAA/gAZ/gA//gA//gAm/gAA/gAR/gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gAz/gAA/gA//gA//gAd/gAI/gA7/gA//gA//gA//gA//gA//gAR/gAA/gAA/gAA/gAA/gAA/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA//gAA/gAu/gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gAi///A///A///A///A///A///A/gAA/gAA/gAA/gAv/gA4/gAA/gAA/gAA/gAD/gA9/gA//gA//gAz/gAA/gAA/gAA/gAA///A///A///A/gA//gA//gAq/gAI/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAu/gA//gA3/gAI/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA//gAR/gAA/gAM/gA7/gA//gA7/gAZ/gA//gA//gAz/gAA/gAA/gAR/gA//gA//gAR/gAA/gAA/gAA/gAA/gAA/gAA/gAE/gAd/gA//gA//gAM/gA//gA//gAd/gAd/gA//gA//gAd/gAI/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA//gAA/gA//gA//gAq/gAA/gAA/gAA/gAA/gAA/gAE/gAq/gA//gA////A///A///A///A///A///A/gAA/gAA/gAA/gAN/gAQ/gAA/gAA/gAA/gAA/gAs/gA//gA//gA+/gAs/gAp/gAZ/gAA///A///A///A/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAR/gA//gA//gAR/gAA/gAA/gAM/gA7/gA//gA//gA//gAz/gAE/gAA/gAA/gAR/gA//gA//gAR/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAR/gA//gA//gAR/gA//gA//gAd/gAd/gA//gA//gAu/gAu/gAu/gAu/gAu/gAu/gAu/gAu/gAu/gAM/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA//gAA/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA////A///A///A///A///A///A/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAI/gAA/gAE/gAZ/gAw/gA//gA//gA//gA//gAh///A///A///A/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAR/gA//gA//gAR/gAA/gAA/gAA/gAR/gA//gA//gA//gAI/gAA/gAA/gAA/gAR/gA//gA//gAm/gAd/gAd/gAd/gAd/gAd/gAd/gAd/gA3/gA//gA3/gAA/gA//gA//gAd/gAd/gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gAR/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA//gAA/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA////A///A///A///A///A///A/gAl/gAL/gAA/gAA/gAA/gAA/gAf/gA+/gAd/gAA/gAA/gAT/gA//gA//gA//gA//gA6///A///A///A/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAR/gA//gA//gAR/gAA/gAA/gAE/gAz/gA//gA//gA//gAz/gAE/gAA/gAA/gAR/gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gAd/gAA/gA//gA//gAd/gAd/gA//gA//gAR/gAR/gAR/gAR/gAR/gAR/gAd/gA//gA//gAR/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA//gAA/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA////A///A///A///A///A///A/gAl/gAK/gAA/gAA/gAA/gAA/gAf/gA+/gAd/gAA/gAA/gAT/gA//gA//gA//gA//gA6///A///A///A/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAR/gA//gA//gAR/gAA/gAA/gAz/gA//gA7/gAd/gA//gA//gAm/gAA/gAA/gAR/gA//gA//gAm/gAd/gAd/gAd/gAd/gAd/gAd/gAd/gAu/gA//gA//gAI/gA//gA//gAd/gAd/gA//gA//gAd/gAR/gAR/gAR/gAR/gAR/gAq/gA//gA//gAR/gAu/gA//gA7/gAZ/gAR/gAR/gAR/gAR/gAV/gAz/gA//gA//gAA/gA3/gA//gA7/gAi/gAd/gAd/gAd/gAd/gAd/gAu/gA//gA////A///A///A///A///A///A/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAI/gAA/gAE/gAa/gAw/gA//gA//gA//gA//gAg///A///A///A/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAu/gA//gAu/gAA/gAA/gAA/gAA/gAA/gAA/gAR/gA//gA//gAR/gAA/gAm/gA//gA7/gAM/gAA/gAZ/gA//gA//gAm/gAA/gAR/gA//gA//gAR/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAR/gA//gA//gAR/gA//gA//gAd/gAE/gAz/gA//gA//gA//gA//gA//gA//gA//gA//gA//gAz/gAA/gAV/gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gAi/gAA/gAV/gA7/gA//gA//gA//gA//gA//gA//gA//gA//gA//gA////A///A///A///A///A///A/gAA/gAA/gAA/gAO/gAR/gAA/gAA/gAA/gAA/gAt/gA//gA//gA+/gAs/gAq/gAZ/gAA///A///A///A/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAi/gAu/gAi/gAA/gAA/gAA/gAA/gAA/gAA/gAM/gAu/gAu/gAM/gAm/gA//gA7/gAM/gAA/gAA/gAA/gAm/gA//gA//gAd/gAR/gA//gA//gAd/gAR/gAR/gAR/gAR/gAR/gAR/gAR/gAq/gA//gA//gAM/gA//gA//gAd/gAA/gAA/gAZ/gAm/gAu/gAu/gAu/gAu/gAu/gAq/gAZ/gAA/gAA/gAA/gAI/gAd/gAu/gAu/gAu/gAu/gAu/gAu/gAi/gAV/gAA/gAA/gAA/gAE/gAV/gAd/gAd/gAd/gAd/gAd/gAd/gAu/gA//gA////A///A///A///A///A///A/gAA/gAA/gAA/gAv/gA4/gAA/gAA/gAA/gAD/gA9/gA//gA//gAz/gAA/gAA/gAA/gAA///A///A///A/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAR/gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gA//gAm/gAA/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA////A///A///A///A///A///A/gAA/gAA/gAA/gAI/gAK/gAA/gAA/gAA/gAA/gAn/gA//gA//gAc/gAA/gAA/gAA/gAA///A///A///A/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAM/gAu/gAu/gAu/gAu/gAu/gAu/gAu/gAu/gAu/gAu/gAm/gAR/gAA/gAA/gA//gA//gAd/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAd/gA//gA////A///A///A///A///A///A/gAA/gAA/gAA/gAA/gAA/gAA/gAC/gAO/gAC/gAB/gAS/gAP/gAA/gAA/gAA/gAA/gAA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A/gAA/gAA/gAA/gAA/gAA/gAA/gAj/gA//gAh/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A/gAA/gAA/gAA/gAA/gAA/gAA/gAa/gA5/gAY/gAA/gAA/gAA/gAA/gAA/gAA/gAA/gAA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1340 
  1341 
  1342 icon_blender = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wA27wA27wA27wAFFFGIIIsNNN5IIIsFFFG27wA27wA27wA27wA27wA///A27wA27wA27wA27wA27wAFFFmnnn9sss/kkk9FFFm27wA27wA27wA27wA27wA///A27wA27wA27wA27wA27wAEEEvwww/AAA/sss/EEEv27wA27wA27wA27wA27wA///A27wA27wA27wA27wA27wAFFFxzzz/xxx/vvv/FFFx27wA27wA27wA27wA27wA///A27wAGGGRLLLtKKK7KKK9JJJ/111/ppp/xxx/III/JJJ9JJJ7LLLtGGGR27wA///AGGGQPPP8xxx/444/vvv/555/333/999/zzz/xxx/jjj/nnn/nnn/OOO8GGGQ///ALLL2222/zzz/lll/+++/888/666/444/222/000/yyy/aaa/nnn/vvv/LLL2///AMMMxqqq/+++/ttt/////AAA/888/666/444/AAA/000/iii/zzz/nnn/MMMx///AGGGKLLLqKKK7ZZZ/yyy/yyy/yyy/888/vvv/ttt/rrr/VVV/JJJ7LLLqGGGK///A27wA27wA27wAJJJ1999+////sss5UUU8qqq5777/333+III127wA27wA27wA///A27wA27wA27wAHHHJMMMzUUU7GGGpHHHIGGGpSSS7MMMzHHHJ27wA27wA27wA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1343 icon_col = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wA27wA27wAVIAPXKB5VIAS27wA27wA27wA27wA///A///A///A///A///A27wA27wA27wAVIAPXKB8shU/XLC9VIAS27wA27wA27wA///A///A///A///A///A27wA27wAVIAPXKB8ymU/7xd/0qb/XLC9VIAS27wA27wA///A///A///A///A///A27wAVIAPXKA8xkO/7uW/7wa/7xd/0qb/XLC9VIAS27wA///A///A///A///A///AVIAPXKA8xiJ/6rO/6sS/7uW/7wZ/7xd/0qa/XLC9VIAS///A///A///A///A///AXKA1ypd/+6z/6rO/6rO/6sS/7uW/7vZ/7xd/shT/XKB5///A///A///A///A///AVJAMYMC873w/+6z/6rO/6rO/6sS/7uV/ymT/XKB8VIAP///A///A///A///A///A27wAVJAMYMC873w/+6z/6rO/6rO/xkN/XKB8VIAP27wA///A///A///A///A///A27wA27wAVJAMYMC873w/+6z/xiJ/XKA8VIAP27wA27wA///A///A///A///A///A27wA27wA27wAVJAMYMC8xpc/XKA8VIAP27wA27wA27wA///A///A///A///A///A27wA27wA27wA27wAVJAMXKA1VIAP27wA27wA27wA27wA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1344 icon_float = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wA27wA27wAMMMSOOO5MMMP27wA27wA27wA27wA///A///A///A///A///A27wA27wA27wAMMMSPPP9nnn/PPP8MMMP27wA27wA27wA///A///A///A///A///A27wA27wAMMMSPPP9ttt/333/vvv/PPP8MMMP27wA27wA///A///A///A///A///A27wAMMMSOOO9ppp/zzz/111/333/vvv/PPP8MMMP27wA///A///A///A///A///AMMMSOOO9lll/uuu/www/zzz/111/333/vvv/PPP8MMMP///A///A///A///A///AOOO5sss/666/sss/uuu/www/zzz/111/333/kkk/PPP1///A///A///A///A///AMMMPQQQ8444/666/ttt/uuu/www/zzz/ppp/OOO8MMMM///A///A///A///A///A27wAMMMPQQQ8444/666/ttt/uuu/mmm/OOO8MMMM27wA///A///A///A///A///A27wA27wAMMMPQQQ8444/555/jjj/OOO8MMMM27wA27wA///A///A///A///A///A27wA27wA27wAMMMPQQQ8ppp/OOO8MMMM27wA27wA27wA///A///A///A///A///A27wA27wA27wA27wAMMMPOOO1MMMM27wA27wA27wA27wA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1345 icon_map2d = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wA27wA27wA27wAMMMUMMMzMMMzMMMU27wA27wA27wA27wA27wA///A///A27wA27wA27wANNNPMMMyYVQ/wnV/bbb/RRR/MMMyNNNP27wA27wA27wA///A///A27wAMMMLMMMtWUQ/vnZ/7vY/6rP/aaa/eee/ZZZ/PPP/MMMtMMML27wA///A///AMMMfTSQ/tnc/7yg/7uV/6qN/6qM/YYY/ZZZ/ddd/fff/YYY/OOO/MMMf///A///AMMM/71o/7wb/6sQ/rgK/dVG/6qM/YYY/ZZZ/bbb/ccc/fff/ggg/MMM////A///AMMM/92q/AAA/6rP/dVH/AAA/6qM/YYY/ZZZ/bbb/ccc/eee/iii/MMM////A///AMMM/93r/dWI/6rP/dVH/AAA/6qM/XXX/ZZZ/bbb/ccc/eee/iii/MMM////A///AMMM/94t/6sR/6rQ/6rO/6qN/6qM/XXX/ZZZ/bbb/ccc/eee/jjj/MMM////A///AMMM/94u/dWI/dVI/6rP/6rN/6qM/XXX/ZZZ/bbb/ccc/eee/kkk/MMM////A///AMMM/+5v/AAA/AAA/6rP/7vX/94t/xxx/ggg/bbb/ccc/eee/lll/MMM////A///AMMM/+5x/6sR/7xd/+6y/////////////////111/mmm/eee/mmm/MMM////A///AMMM/+72//96/////////////////////////////////666/vvv/MMM////A///AMMMiTTS/wuq/986/////////////////////////555/ppp/SSS/MMMi///A///A27wAMMMHMMMdMMM0aZX/0yu/+97/888/uuu/XXX/MMM0MMMdMMMH27wA///A///A27wA27wA27wA27wANNNLMMMhMMM3MMM3MMMhNNNL27wA27wA27wA27wA///A")
  1346 icon_map2dparam = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wAQQQB27wA27wA27wA27wA27wA27wA27wA27wA27wA27wA27wA27wA///A///A27wAUUUwMMM9EEE3AAAvAAAlAAAbAAAI27wA27wA27wA27wA27wA27wA///A///A27wAeeeOVVV9OOO/MMM/CCC/AAA+AAA9AAAg27wA27wA27wA27wA27wA///A///A27wA27wAfffKWWW9ggg/mmm/TTT/AAA/AAA9AAAS27wA27wA27wA27wA///A///A27wA27wA27wAeeeXVVV9hhh/lll/TTT/BBB/BBB6AAAN27wA27wA27wA///A///A27wAAAAK27wA27wAdddgTTT8NNN/NNN/JJJ/VVV9EEE8AAAoAAAG27wA///A///A27wAAAAXAAAA27wA27wAeeeaVVV2QQQ/nnn+222/mmm/PPP9JGF8KGCX///A///A27wAAAAkAAAA27wA27wA27wA27wAVVVXYYY8+++/333/gec+ZPL+XOJq///A///A27wAAAAxAAAB27wA27wA27wA27wA27wAXXXiiii83219ofY8eUO/aQL2///A///A27wAAAA9AAAC27wA27wA27wA27wA27wAgggAWWVwmgc84yt/oeW/gWP1///A///ACCC6AAA/AAA/CCC627wA27wA27wA27wA27wAKFFDKGDzxsm52wq/peW2///A///AAAA/////////AAA/AAABAAAAAAAAAAAA27wA27wALFCFMHE31wr61uo5///A///AAAA/////////AAA/AAA+AAAzAAAmAAAZAAAM27wA27wAKFDJPLH6umez///A///ACCC6AAA/AAA/CCC627wA27wA27wA27wA27wA27wA27wA27wAKFCOOJFf///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1347 icon_map3dparam = decodeIconStr("27wA27wA27wA27wA27wA27wA3nIC6pMJ6pMJ3nIC27wA27wA27wA27wA27wA27wA27wA27wA27wA27wA27wA3nIC6qMj6qM/6qM/6qMj3nIC27wA27wA27wA27wA27wA27wA27wA27wA27wA27wA6pMJ6qM/////////6qM/6pMJ27wA27wA27wA27wA27wA27wA27wA27wA27wANNNOSQMz5qM/////////5qM/SQMzNNNO27wA27wA27wA27wA27wA27wAMMMIMMMrXXX/www/5wg/6qM/5qM/vnX/bbb/PPP/MMMrMMMI27wA27wA27wA27wAMMM1xxx/777/222/yyy/zxu/caY/bbb/ggg/iii/YYY/MMM127wA27wA27wA27wAMMM/+++/zzz/yyy/yyy/yyy/ZZZ/bbb/ddd/fff/kkk/MMM/27wA27wA27wA27wAMMM/////yyy/yyy/yyy/yyy/ZZZ/bbb/ddd/eee/lll/MMM/27wA27wA27wA27wAMMM/////yyy/yyy/yyy/yyy/ZZZ/bbb/ddd/eee/nnn/MMM/27wA27wA27wA3nICRPM//97/yyy/yyy/yyy/yyy/ZZZ/bbb/ddd/eee/rpm/RPM/3nIC27wA3nIC6qMj5qM/6qM/2ue/zzz/444/999/666/rrr/fff/tkU/5qM/5qM/6qMj3nIC6pMJ6qM/////////6qM/+96/////////////////985/6qM/////////6qM/6pMJ6pMJ6qM/////////6qM/+86/////////////////974/6qM/////////6qM/6pMJ3nIC6qMj6qM/6qM/pfM2PPP+mmm/555/000/hhh/PPP+pfM26qM/6qM/6qMj3nIC27wA3nIC6pMJ6pMJ3nICMMMEMMMaMMMwMMMwMMMaMMME3nIC6pMJ6pMJ3nIC27wA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1348 icon_mat = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wA27wAVJAMXKBnXLB1WJA9XLB1XKBnVJAM27wA27wA27wA///A///A///A27wAVAAAWJBgYMD9ukW/1sc/5we/0qY/sgQ/XLB9WJBgVAAA27wA///A///A///A27wAWJBghXM96zk/8yf/7wa/7vY/7vZ/YUN/TQM/aPF9WJBg27wA///A///A///AVIALZNE970o/7wb/QNG/QNG/7vX/7vX/JHD/DDD/bXP/XKB9VIAL///A///A///AXKBpype/8zj/7vX/QNG/QNG/7vX/7vX/sjR/IGD/keS/rfQ/XKBp///A///A///AXLB36zp/7xc/7vX/7vX/7vX/7vX/7vX/7vX/7vX/7vZ/0qZ/XLB3///A///A///AVJA+95x/2rX/fYM/zoU/7vX/7vX/7vX/7vX/7vX/7vY/6wf/VJA+///A///A///AXKB361s/VTO/AAA/NKF/7vX/7vX/meP/IGD/JHD/tkU/1rc/XKB3///A///A///AXKBq0tj/cba/AAA/HGD/7vX/7vX/IGD/AAA/AAA/VTQ/ujW/XKBq///A///A///AVIAMaPG920w/RPN/meP/7vX/7vX/gaM/BAA/HHH/njd/YMD9VIAM///A///A///A27wAWKBilbS995y/91n/8xd/7vZ/7xc/4wh/4yn/iXM9WKBi27wA///A///A///A27wAQQABWKBiaOF9zsj/61s/95x/5zp/xpe/ZNE9WKBiQQAB27wA///A///A///A27wA27wA27wAVIAMXKBqXKB3VJA+XKB3XKBqVIAM27wA27wA27wA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1349 icon_matmix = decodeIconStr("27wA27wA27wA27wA27wA27wA27wAMIFdUMG7WNF+WNF+SLG5LHFS27wA27wA///A27wA27wA27wA27wA27wASLGAOJGziYN/xmV/wmT/pgQ/jaN/YPH/NJGm27wA///A27wA27wA27wA27wA27wAMIFjlbR/9ye/6sQ/zlJ/sgJ/ofM/ngT/YPH/MIGT///A27wA27wA27wA27wA27wAXQJ/6xk/9xZ/6sQ/5qM/zlK/sfI/ofM/jaN/SLG5///A27wA27wA27wA27wAHHHGgXQ//4r/8xc/7vX/7tR/5pM/zlK/sgJ/pgQ/WMF+///A27wA27wA27wA27wAJOVVYbf/58//y27/wz3/7vY/7tS/4pM/ykJ/vmU/WMF////A27wAAAAALIGkTMG+NQU/Qcu/Sfz/Sfz/Wi1/wz4/7vZ/7sR/6sR/wmW/UMH8///ASLGAOJG1iYN/xmV/kns/Rfz/99+/++//Rfz/z27/8ye/9yc/9zg/iYN/LIFh///AMHFilbR/9ye/6sQ/jns/Rfz/////////Rfz/57///4q/6xk/lbR/NJG227wA///AYQJ96xk/9xZ/6sQ/orw/Tgz/Rfz/Rez/Qdw/Xaf/gXP/XPI/MIGoAAAA27wA///AgXQ//4r/8xc/7vX/7tR/nrw/jms/dhn/ein/WNG/GGGRAAAA27wA27wA27wA///AhYR//7x/91m/8xe/7vY/7tS/4pM/ykJ/vmU/WMF/GGGH27wA27wA27wA27wA///AbTM995x//+6/80k/8ye/7vZ/7sR/6sR/wmW/TMG+27wA27wA27wA27wA27wA///APIEitld///7//+6/91n/8ye/9yc/9zg/iYN/LIGk27wA27wA27wA27wA27wA///ARKGCRKFyskc/94v//7w//4q/6xk/lbR/OJG0AAAA27wA27wA27wA27wA27wA///A27wAQJECPIEibTL9hYQ/gXP/YQJ9MHEi27wA27wA27wA27wA27wA27wA27wA///A")
  1350 icon_tex = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///AOOO6MMM/MMM/MMM/MMM/MMM/MMM/MMM/MMM/MMM/MMM/MMM/OOO6///A///A///AMMM/444/555/555/555/555/666/666/777/777/888/888/MMM////A///A///AMMM/555/mmm/TTT/aaa/xxx/111/222/222/QQQ/ZZZ/777/MMM////A///A///AMMM/333/DDD/AAA/AAA/YYY/zzz/111/xxx/AAA/AAA/nnn/MMM////A///A///AMMM/222/DDD/AAA/AAA/bbb/yyy/zzz/111/RRR/AAA/iii/MMM////A///A///AMMM/666/jjj/TTT/ddd/vvv/xxx/yyy/zzz/000/rrr/555/MMM////A///A///AMMM/666/rrr/sss/uuu/vvv/www/xxx/yyy/zzz/000/666/MMM////A///A///AMMM/666/qqq/iii/qqq/uuu/vvv/ppp/nnn/yyy/zzz/555/MMM////A///A///AMMM/777/jjj/AAA/RRR/sss/bbb/AAA/AAA/SSS/yyy/555/MMM////A///A///AMMM/888/mmm/LLL/ccc/rrr/QQQ/AAA/AAA/AAA/www/555/MMM////A///A///AMMM/888/nnn/ooo/ppp/qqq/jjj/HHH/DDD/XXX/www/555/MMM////A///A///AMMM/666/888/888/777/666/666/555/555/555/444/333/MMM////A///A///ANNN4NNN+NNN+NNN+NNN+NNN+NNN+NNN+NNN+NNN+NNN+NNN+OOO4///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1351 icon_texcol = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///AWKA4VJA+VJA+VJA+VJA+VJA+VJA+VJA+VJA+VJA+VJA+VJA+WKA4///A///A///AVIA/82p/93r/93r/93s/93s/93s/93t/94u/94u/94w/95w/VIA////A///A///AVIA/93s/xoV/ZVM/icR/6wf/8zi/80k/80l/USN/daU/94v/VIA////A///A///AVIA/72r/FDC/AAA/AAA/eZP/8yf/8zh/3vg/AAA/AAA/olf/VIA////A///A///AVIA/50p/DCB/AAA/AAA/faO/8xd/8yf/8zh/SPK/AAA/jga/VIA////A///A///AVIA/94t/rhO/WRI/haN/5uY/7wb/8xd/8yf/7yg/tma/72r/VIA////A///A///AVIA/94u/6sQ/6tT/7uV/7uX/7vY/7wa/7xc/8ye/8yg/93s/VIA////A///A///AVIA/94u/6rO/ylO/5sS/7uU/7uW/1qV/yoW/7xc/8ye/93s/VIA////A///A///AVIA/+5w/zlL/DDD/bVK/6tS/mdN/AAA/AAA/YTK/7xc/93r/VIA////A///A///AVIA/+5x/3oL/NKD/mcK/6sQ/WQG/AAA/AAA/BAA/5uZ/93r/VIA////A///A///AVIA/+6z/6qM/6qM/6qM/6rO/ujM/IGC/BBA/aUJ/7vX/93r/VIA////A///A///AVIA/+5w/+6y/+5w/+4v/94t/93s/82r/93r/93r/93r/92p/VIA////A///A///AWJA6VJA/WJB/WJB/WJB/WJB/WJB/WJB/WJB/WJB/WJB/VJA/WJA6///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1352 icon_texmix = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///APPP7ccc/ddd/ccc/bbb/bbb/ddd/eee/RRR9///A///A///A///A///A///A///AYYY+yyy/fff/qqq/000/111/jjj/sss/eee////A///A///A///A///A///A///Aaaa9XXX/AAA/III/rrr/xxx/LLL/GGG/VVV////A///A///A///A///A///A///AZZZ9hhh/JJJ/XXX/rrr/uuu/kkk/eee/YYY////A///A///A///A///A///A///AVYd/sv0/imq/nqu/rrr/ttt/vvv/000/bbb////A///APPP7ccc/ddd/ccc/Ycg/Qcu/Sfz/Sfz/Wi1/fin/RRR/bbb/yyy/bbb////A///AYYY+yyy/fff/qqq/x05/Rfz/99+/++//Rfz/PSX/AAA/AAA/uuu/bbb////A///Aaaa9XXX/AAA/III/orw/Rfz/////////Rfz/lpu/XXX/eee/000/ccc////A///AZZZ9hhh/JJJ/XXX/osw/Tgz/Rfz/Rez/Qdw/Wae/bbb9aaa9YYY9PPP7///A///AYYY9vvv/lll/ppp/rrr/pty/sw1/w06/Ych////A///A///A///A///A///A///AZZZ9sss/SSS/iii/hhh/RRR/bbb/yyy/bbb////A///A///A///A///A///A///AZZZ9rrr/JJJ/eee/SSS/AAA/AAA/uuu/bbb////A///A///A///A///A///A///AZZZ+111/ttt/uuu/ooo/XXX/eee/000/ccc////A///A///A///A///A///A///AOOO4aaa9aaa9ZZZ9ZZZ9bbb9aaa9YYY9PPP7///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1353 icon_texmixcol = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///AaOE7mcS/ndT/mcS/lbS/kbS/ndU/neV/bQH9///A///A///A///A///A///A///AiYP+92o/niY/0tg//4p//6s/pme/wun/neV////A///A///A///A///A///A///AkZP9aYT/AAA/LJF/5vd//2j/OMH/GHH/eVN////A///A///A///A///A///A///AjYP9qlZ/OKE/haO/7wb/+zf/voZ/jgY/hYP////A///A///A///A///A///A///AXae/z27/qty/ux2/9wZ/+yc//1f//5o/lbS////A///AaOE7mcS/ndT/mcS/adh/Qcu/Sfz/Sfz/Wi1/lot/ZUK/leQ//3l/kbR////A///AiYP+92o/niY/0tg/25+/Rfz/99+/++//Rfz/TXc/AAA/BAA/9zg/lbS////A///AkZP9aYT/AAA/LJF/tx2/Rfz/////////Rfz/quz/bZU/lhX//6o/lcS////A///AjYP9qlZ/OKE/haO/uy3/Tgz/Rfz/Rez/Qdw/Ybg/laQ9laQ9iYP9aOE7///A///AhXP9/1f/6sQ/8vW/9wZ/wz4/y28/26//aej////A///A///A///A///A///A///AhXQ98xd/eWH/znR/xmR/ZUK/leQ//3l/kbR////A///A///A///A///A///A///AhYR97xb/TMA/xkL/dVG/AAA/BAA/9zg/lbS////A///A///A///A///A///A///AiYR+/7q//zb//0d/1tb/bZU/lhX//6o/lcS////A///A///A///A///A///A///AZNE4iZS9iZS9iYR9jZQ9laQ9laQ9iYP9aOE7///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1354 icon_texparam = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wAOOO5GGG/BBB9AAA5AAAwAAAnAAAO27wA27wA27wA27wA27wA27wA///A875F27wAYYYZPPP/KKK/III/BBB/AAA/AAA/AAAxAAAB27wA27wA27wA27wA///AoooO875K27wAaaaTRRR/eee/lll/SSS/AAA/AAA/AAAk27wA27wA27wA27wA///AeeeX222V876J27wAbbbkSSS/iii/mmm/TTT/AAA/AAA/CCCW27wA27wA27wA///AXXXfxxxftttW887I27wAcccwSSS/OOO/PPP/III/RRR/CCC/CCC3CCCL27wA///ATTTmtttsQQQvbbbd887H27wAdddrVVV/PPP/hhh/222/lll/NNN/HFE/KFCo///APPPssss3HHH6NNNwZZZd988G27wA27wAXXXlXXX/999/333/jhg/ZPK/WOJ5///AMMMvsss/jjj1XXXxrrrf333R998F27xA27wAYYYvggg/554/meX/eUO/ZQL////AJJJyvvv/jjj/oooztttoyyyc444Q999E27xAfffAYXW7jeZ/4yt/pfX/gWP////AHHH0zzz/iii/jjj+oooytttnlllggggX+99D27xALFAFKGD9wql/2wr/peW////AFFF3333/HHH/QQQ/jjj9mmmyDDD8KKKxTTTe555D26xAIFDKMHE+0vq/1uo////ADDD6666/HHH/QQQ/jjj/kkk8DDD+BBB+JJJyrrrR+++C26xAKFDROKG/wog+///ABBB9555/777/333/000/www/rrr9bbb6fffv000Y555M///B26xAKFCYOKF0///ABBB5BBB9DDD6EEE4GGG1IIIzKKKxNNNtPPPmSSSfUUUXUUUODDDE26xA27wA///A")
  1355 
  1356 icon_emission = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wA27wAAAAgAAA/AAAg27wA27wA27wA///A///A///A///A///A///A///A27wAAAAFAAAxAAA/AAA/AAA/AAAxAAAF27wA///A///A///A///A///A///A///A27wAAAAZooo5////444/nnn/KKK2AAAZ27wA///A///A///A///A///A///A///A27wAAAALSSS/ggg/bbb/AAA/AAA/AAAL27wA///A///A///A///A///A///A///A27wAAAAYrrr/////777/nnn/KKJ+AAAZ27wA///A///A///A///A///A///A///A27wAPNBRTRI+kiX8ebQ+ebN8NLA+PNCP27wA///A///A///A///A///A///A///AQQABVRB1qlQ483g2qlR+81Z2pkO6VRB0QQAB///A///A///A///A///A///A///ATQBlieP685t361ezjcD+5ySx61c0dYG6TQBl///A///A///A///A///A///A///AVRA453x650gwhbB93vRthbB+4yXvwrX0VRA4///A///A///A///A///A///A///AVRA+++8941ow2xbs0tRp0tRp1vUr2yiyVRA+///A///A///A///A///A///A///AUQA48868/++999772yiszuYo2yhsvsdxVRA5///A///A///A///A///A///A///ATPBlqof6//////++64yy64yy7611cYK4TPBl///A///A///A///A///A///A///AKKABUQA1qnf59989//++6525ifT4UQA1KKAB///A///A///A///A///A///A///A27wAKKABSPBkUQA4VQA+UQA4SPBkKKAB27wA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1357 
  1358 icon_spectex = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///AAAATGGGzAAAiAAAA27wA27wA27wA27wA27wA27wA27wAAAADAAAjGGGxAAAT///AFFFy555/SBx/MA5+ASx9AhZ9ArC9AwA9WvA9xnA9/WA97AA/xBB/555/FFFz///AAAAUccc/ka1/MA6/ASx/AhZ/ArC/AwA/WvA/xnA//WA/9AA/1ff/SSS+AAAZ///A27wAMMM6ph2/MA6/Xi0/AhZ/ArC/AwA/WvA/xnA//WA/1bb/jjj/AAAY27wA///A27wABBBnpmv/ni6/lr1/AhZ/ArC/AwA/WvA/xnA//WA/6vv/SSS/AAAE27wA///A27wAAAAEGGG1PPP/SUY/Zsn/ArC/AwA/hyS/xnA//WA/5uu/DDDw27wA27wA///A27wA27wAAAABAAAEIII3oyw/ArC/WvW/syn/31u/3vr/nll/AAAa27wA27wA///A27wA27wA///A///AAAAnlus/BrE/v4v/TTT/kkk/444/PPP+AAAE27wA27wA///A27wA27wA27wA27wAAAAZnnn/444/555/GGG3AAAdEEExAAAM27wA27wA27wA///A27wA27wA27wA27wAAAAKaaa/555/zzz/AAAn27wA27wA27wA27wA27wA27wA///A27wA27wA27wA27wAAAAALLL8555/iii/AAAX27wA27wA27wA27wA27wA27wA///A27wA27wA27wA27wA27wAAAAPKKK6AAArAAAB27wA27wA27wA27wA27wA27wA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1359 
  1360 icon_c_filter = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///AAAASGGG1BBBsAAAW27wA27wA27wA27wA27wA27wA27wAAAAWBBBsGGGyAAAU///AHHHx555/333/ddd/AAAl27wA27wA27wA27wA27wAAAAlddd/333/555/FFFz///AAAAUMMM8eee/555/ccc/AAAT27wA27wA27wAAAATccc/555/eee/MMM8AAAV///A27wAAAAAAAAbfff/222/GGG1AAAA27wAAAAAGGG1222/fff/AAAbAAAA27wA///A27wA27wAAAAAFFFz222/hhh/AAAW27wAAAAWhhh/222/FFFzAAAA27wA27wA///A27wA27wA27wAAAAQccc/333/EEEz27wAEEEz333/ccc/AAAQ27wA27wA27wA///A27wA27wA27wA27wAGGG1444/aaa/AAAdaaa/444/GGG127wA27wA27wA27wA///A27wA27wA27wA27wAAAAakkk/000/UUU/000/kkk/AAAa27wA27wA27wA27wA///A27wA27wA27wA27wAAAACGGG1xxx/555/xxx/GGG1AAAC27wA27wA27wA27wA///A27wA27wA27wA27wA27wAAAAFAAAoJJJ1AAAoAAAF27wA27wA27wA27wA27wA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1361 
  1362 icon_c_camera = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wA27wA27wAAAAAAAABAAABAAABAAABAAAA27wA27wA27wA27wA///A///ANNN6MMM/MMM/JJJ/MMM/LLL/LLL/LLL/LLL/MMM/MMM/MMM/MMM/OOO6///A///AMMM/vvv/ttt/ccc/mmm/jjj/ggg/hhh/jjj/ooo/sss/www/iii/MMM////A///AMMM/uuu/eee/RRR/XXX/ZZZ/mmm/xxx/ppp/ggg/jjj/ppp/eee/MMM////A///AMMM/ttt/aaa/OOO/WWW/rrr/aaa/TTT/jjj/zzz/hhh/lll/ccc/MMM////A///AMMM/sss/XXX/LLL/ggg/QQQ/HHH/KKK/QQQ/hhh/rrr/ggg/bbb/MMM////A///AMMM/rrr/VVV/JJJ/ooo/QQQ/TTT/III/JJJ/RRR/yyy/ddd/ZZZ/MMM////A///AMMM/sss/UUU/JJJ/eee/eee/www/RRR/EEE/VVV/ooo/ccc/ZZZ/MMM////A///AMMM/uuu/VVV/KKK/RRR/kkk/fff/QQQ/OOO/ooo/bbb/eee/ZZZ/MMM////A///AMMM/xxx/WWW/LLL/NNN/SSS/eee/ooo/hhh/YYY/YYY/ggg/ZZZ/MMM////A///AMMM/zzz/vvv/aaa/fff/VVV/OOO/PPP/RRR/bbb/mmm/sss/fff/NNN9///A///ANNN6MLJ/MJE/IHG/OOO+ggg/bbb/ccc/eee/jjj/NNN+MMM/NNN9MMMP///A///A27wAMHAl9jA/NIApMMMmWWW/888/////888/bbb/NNNmAAAA27wA27wA///A///A27wALGAPMHAoMHASMMMGSSS/777/////888/WWW/NNNF27wA27wA27wA///A///A27wA27wA27wA27wA27wARRRiPPP+QQQ/RRR+VVVi27wA27wA27wA27wA///A")
  1363 
  1364 icon_c_environment = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///AGMV1HNV7HNV7HNV7HNV7HNV7HNV7HNV7HNV7HNV7HNV7GMV1///A///A///A///AHNV7y0u/z0u/y0t/xzs/wyr/wyq/vxp/uxo/twn/svm/HNV7///A///A///A///AIOW8341/tvm/qtj/qtj/qtj/qtj/qtj/qtj/qtj/two/HNV7///A///A///A///AINV8sts/cdc/qrp/uxp/qtj/qtj/qtj/qtj/qtj/tvo/HNU7///A///A///A///AGMV7svy/Ubh/VZb/ZZZ/xyt/ruk/qtj/qtj/rul/bcb/GLU7///A///A///A///AGMV7twz/Uci/Uci/Tbg/TUU/ssq/y0u/vxr/TVT/fko/GMV7///A///A///A///AGMV7vy0/Vdj/Zgl/Xfk/Uci/RWZ/TVV/PSU/Tag/hnr/GMV7///A///A///A///AGMV7wz1/gmq/023/txz/Xfk/Uci/Uci/Uci/Uci/jos/GMV7///A///A///A///AGMV7y02/jos/////023/Zgl/Uci/Uci/Uci/Uci/kpt/GMV7///A///A///A///AGMV7z23/ahm/jos/gmq/Vdj/Uci/Uci/Uci/Uci/mru/GMV7///A///A///A///AGMV7x02/023/y02/wz1/vy0/uxz/swy/rux/ptw/lqu/GMV7///A///A///A///AGMV1GMV7GMV7GMV7GMV7GMV7GMV7GMV7GMV7GMV7GMV7GMV1///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1365 
  1366 icon_c_sampler = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wA27wAMMMXSSS3MMMg27wA27wA27wA27wAMMMdTTT2MMMc27wA27wA27wA27wA27wAMMMSggg/////XXX+MMMB27wA27wA27wAUUU8////jjj/MMMT27wA27wA27wAMMMIYYY8+++/xxx/NNNuMMMCMMMCMMMCMMMCNNNqwww/////ZZZ9MMMJ27wAMMMASSS0666/+++/fff/bbb/bbb/eee/eee/bbb/bbb/ddd/999/777/SSS327wAMMMGjjj/////////////////////////////////////////////////lll/MMMI27wARRRz555/999/ccc/YYY/YYY+aaa+bbb+YYY+YYY+bbb/999/666/RRR2MMMB27wAMMMHWWW7999/yyy/NNNu27wA27wA27wA27wANNNtxxx/+++/YYY8MMMI27wAVVqARfzGOTZZeee/////WWW+QctHRfzLRfzLRfzGUUU8////hhh/OSYaRfzGVVqARfzGRezcRfz5PXj8STV5NPSiRezcRfz5Rfz5RezcNQThRST6PYk7Rfz5RezcRfzGRfzLRfz5////////Rfz5RfzMRfz5////////Rfz5RfzMRfz5////////Rfz5RfzLRfzLRfz5////////Rfz5RfzMRfz5////////Rfz5RfzMRfz5////////Rfz5RfzLRfzGRezcRfz5Rfz5RezcRfzKRezcRfz5Rfz5RezcRfzKRezcRfz5Rfz5RezcRfzGVVqARfzGRfzLRfzLRfzGVVqARfzGRfzLRfzLRfzGVVqARfzGRfzLRfzLRfzGVVqA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1367 
  1368 icon_c_integrator = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wAAAAAEJPYHMT0MRY+GLS0EJPYAAAA27wA27wA27wA27wA27wA27wA27wA27wAAAVAEJPoVai/lr0/elv/Xeo/LRZ/EIPnDHOEAAVA27wA27wA27wA27wA27wA27wAEIPcZel/rw5/cir/NTb/SYi/PWh/MSb/QVd/KPW6EJPfAJSB27wA27wA27wAAAAAHMT4ty7/hmv/FKQyDGMXEJP7bhq/nt2/pv4/sy6/diq/EJQuIIQC27wA27wAFIQGRWd/u08/TYf/CFKQDGLfUai/flv/Zfp/SZj/bgp/rx6/fks/EJQuAJSB27wAAJSBINT7uz8/glt/EIOqGKQ4Xeo/SYi/KQY/SZk/IOW/Ydl/ty7/diq/EJPg27wA27wAEJPhflt/u08/Yel/JOW/QXi/HNV/TZi/Yfp/GLS6EJPuejr/tz8/HMT6AMMB27wAGGMCFLRxiow/u08/ciq/SZk/Yeo/gnw/Vaj/DINhDGJQQVd/u08/SXe/FIQG27wA27wAFJODFKRyhmu/u08/sy7/pv4/cir/FJQ7CGLTEIPudir/uz8/JOU6AMMB27wA27wA27wAFJODEJPjKPW8UZh/RXg/RYj/QXg/MSa/Zfo/pv4/diq/EJPg27wA27wA27wA27wA27wA27wAFKQDEIPLEJPtPVe/ahr/flv/jpz/diq/FJQtAJSB27wA27wA27wA27wA27wA27wA27wA27wAAMMBEJPeGLS5OUb/INU5EJPeAMMB27wA27wA27wA27wA27wA27wA27wA27wA27wA27wA27wAAAAAEIQEAAVA27wA27wA27wA27wA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1369 
  1370 icon_c_volumeintegrator = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wA27wA27wAMMMAMMMWNNN8NNN9MMMWMMMA27wA27wA27wA27wA///A27wA27wAAAAAEJPYIMS3MRY/KOU/gik/ggg/TTT/MMMzMMMR27wA27wA27wA27wA27wAAAVAFJPtVai/lr0/elv/Xeo/LRZ/NQU/ggh/ddd/RRR/MMMvMMMN27wA27wA27wAHKOvZel/rw5/cir/NTb/SYi/PWh/MSb/QVd/LQW/TWZ/aaa/PPP/MMMh27wAAAAAIMS/ty7/hmv/OSX/gik/HMS/bhq/nt2/pv4/sy6/diq/MQV/hhh/MMM/27wAFIQGRWd/u08/TYf/lmn/bdf/Uai/flv/Zfp/SZj/bgp/rx6/fks/NRV/MMN/27wAAJSBINT/uz8/glt/TWa/LPU/Xeo/SYi/KQY/SZk/IOW/Ydl/ty7/diq/IKO/27wA27wAIKO/flt/u08/Yel/JOW/QXi/HNV/TZi/Yfp/INT/LOT/ejr/tz8/IMT/AMMB27wAMMM/SWb/iow/u08/ciq/SZk/Yeo/gnw/Vaj/PRU/XXY/QVd/u08/SXe/FIQG27wAMMM/899/PTY/hmu/u08/sy7/pv4/cir/HLR/UVX/KOT/dir/uz8/JOU/AMMB27wAMMM/////vww/WZd/MRX/UZh/RXg/RYj/QXg/MSa/Zfo/pv4/diq/IKO/27wA27wAMMM/////999/////999/123/VZd/PVe/ahr/flv/jpz/diq/RUa/MMN/27wA27wAMMMxRRR/rrr/888/////////+++/jmp/MRX/OUb/NRX/WYb/PQQ/MMMx27wA27wA27wANNNEMMMaMMMxWWW/www/+++/999/uuu/UUV/MMMxMMMaNNNE27wA27wA///A27wA27wA27wA27wANNNIMMMfMMM1MMM1MMMfNNNI27wA27wA27wA27wA///A")
  1371 
  1372 icon_help = decodeIconStr("///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A27wA27wA27wAAAAOGGGtFFF4HHH6GGG3GGGqAAAK27wA27wA27wA///A///A///A27wAAAABEEEnNNN7vvv/666/888/888/vvv/III7EEEgAAAA27wA///A///A///A27wAEEEmfff+333/333/333/lll/999/999/999/WWW8EEEd27wA///A///A///AAAAPSSS7333/zzz/111/xxx/III/+++/777/999/999/JJJ6AAAJ///A///A///AFFFtxxx/yyy/xxx/zzz/444/999/777/666/777/999/ppp/FFFh///A///A///AEEE4555/uuu/vvv/xxx/ttt/MMM/yyy/666/666/777/111/GGGy///A///A///AJJJ7666/sss/ttt/vvv/yyy/ttt/HHH/yyy/666/555/777/FFF5///A///A///ADDD3777/sss/qqq/lll/vvv/yyy/sss/EEE/777/444/xxx/GGGv///A///A///ADDDq000/xxx/iii/FFF/kkk/lll/hhh/HHH/555/333/kkk/DDDe///A///A///AAAAJNNN8999/rrr/iii/DDD/DDD/GGG/000/000/000/GGG6AAAE///A///A///A27wACCCcccc9999/yyy/ttt/sss/www/000/000/QQQ8CCCT27wA///A///A///A27wA27wACCCXMMM7www/444/777/000/ooo+III5BBBR27wA27wA///A///A///A27wA27wA27wAAAAFBBBbEEEsEEE1FFFqBBBZAAAD27wA27wA27wA///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A///A")
  1373 
  1374 
  1375 bar_spectrum = decodeBarStr("AAA/AAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAA/AAA/AAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAA/AAA/AAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAA/AAA/AAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAA/AAA/AAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAA/AAA/AAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAA/AAA/AAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAA/AAA/AAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAA/AAA/AAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAA/AAA4AAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAA4AAAsAAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAAsAAAcAAA/AAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAA/CAAcAAAKAAAzAAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAAzCAAK///AAAAaAAB/AAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAA/CAAa///A///A///AAABfAAC/AAD/BAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAA/DAA/CAAf///A///A///A///A///AAACaAADzBAF/CAH/DAK/EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA/FAA/EAA/DAAzDAAa///A///A///A///A///A///A///AAADKBAFcCAHsDAK4EAN/GAQ/HAU/JAX/LAb/MAf/OAj/PAm/QAq/RAt/SAv/SAx/SAz/SA1/SA3/SA4/SA5/RA6/PA6/OA6/MA6/IA5/CA4/AA3/AD2/AJ1/AN0/AQy/ATw/AVu/AYr/AZo/Abl/Adj/Aeg/Agd/Ahb/AiY/AjW/AlT/AmR/AnO/AoL/AqI/AqE/ArA/AsA/AtA/AuA/AvA/AvA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/AwA/CwA/OvA/UvA/ZuA/euA/htA/lsA/orA/rqA/tpA/woA/ymA/0lA/2jA/4hA/5fA/7eA/8cA/9aA/+YA//VA//TA//QA//NA//KA//FA/+AA/+AA/8AA/7AA/6AA/5AA/3AA/2AA/0AA/yAA/wAA/uAA/sAA/qAA/oAA/lAA/jAA/hAA/fAA/dAA/bAA/ZAA/YAA/WAA/UAA/SAA/RAA/QAA/OAA/NAA/MAA/LAA/KAA/JAA/IAA/HAA/GAA/FAA4FAAsEAAcDAAK///A///A///A///A")
  1376 
  1377 bar_blackbody = decodeBarStr("+LA/+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/+aA//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ//sK//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////+///++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LA/+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/QQQ//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ/QQQ//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////QQQ/++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LA/+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/QQQ//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ/QQQ//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////QQQ/++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LA/+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/QQQ//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ/QQQ//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////QQQ/++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LA/+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/QQQ//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ/QQQ//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////QQQ/++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LA/+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/+aA//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ//sK//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////+///++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LA/+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/QQQ/QQQ/QQQ//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ/QQQ//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////QQQ/QQQ/QQQ/++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LA/+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/QQQ//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ/QQQ//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////QQQ/++//QQQ/++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LA/+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/QQQ//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ/QQQ//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////QQQ/++//QQQ/++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LA4+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/+aA/QQQ/QQQ//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ/QQQ//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////QQQ/QQQ/++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LAs+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/+aA//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ//sK//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////+///++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LAc+LA/+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/+aA//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ//sK//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////+///++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LAK+LAz+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/+aA//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ//sK//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////+///++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LAA+LAa+MA/+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/+aA//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ//sK//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////+///++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LAA+LAA+MAf+NA/+OA/+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/+aA//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ//sK//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////+///++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LAA+LAA+MAA+NAa+OAz+QA/+RA/+SA/+TA/+VA/+WA/+XA/+ZA/+aA//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ//sK//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////+///++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//+LAA+LAA+MAA+NAA+OAK+QAc+RAs+SA4+TA/+VA/+WA/+XA/+ZA/+aA//bA//cA//eA//fA//gA//hA//iA//kA//lA//mA//nA//oA//oB//pD//pE//qF//qG//qH//rI//rJ//sK//sM//sN//tO//tP//uQ//uR//vS//vT//vU//wW//wX//xY//xZ//xa//yb//yc//zd//ze//zg//0h//0i//1j//1k//1l//2m//2n//3p//3q//4r//4s//4t//5u//5v//6w//6y//6y//70//71//82//83//84//95//96//+7//+9///9/////////////////+///++//++//++//++//9+//9+//99//99//89//89//89//88//88//78//78//78//78//67//67//67//67//57//57//56//56//56//46//46//46//45//35//35//35//35//24//24//24//24//24//13//13//13//13//03//03//03//02//z2//z2//z2//z2//02//")
  1378 
  1379 bar_equalenergy = decodeBarStr("AAA/AAA/AAA/AAA/BBB/BBB/BBB/BBB/CCC/CCC/CDC/DDD/DDD/DDD/EEE/EEE/EFF/FFF/FFF/GGG/GGG/HGG/HHH/HHH/III/III/JJJ/JJJ/KJK/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QQQ/RRR/RRR/SSS/TSS/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/XXY/YYY/ZZZ/ZZZ/aaa/aaa/bbb/cbb/ccc/ddd/ddd/eee/eee/fff/ffg/ggg/hhh/hhh/iii/iii/jjj/kkk/kkk/lll/lll/mmm/mnm/nnn/ono/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/sss/ttt/utu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/122/222/222/333/333/444/444/545/555/555/666/666/667/777/777/788/888/888/999/999/999/9++/+++/+++/+++/////////////AAA/AAA/AAA/AAA/BBB/BBB/BBB/BBB/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/EEF/FFF/FFF/GGG/GGG/GGH/HHH/HHH/III/III/JJJ/JJJ/KJJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QQQ/RRR/RSR/SSS/TTT/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/YXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/cbb/ccc/ddd/ddd/eee/eee/fff/ffg/ggg/hhh/hhh/iii/iii/jjj/kkj/kkk/lll/lll/mmm/mmn/nnn/ono/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/stt/ttt/tuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/111/222/222/333/333/444/444/554/555/555/666/666/766/777/777/777/888/888/999/999/999/9++/+++/+++/+++/////////////AAA/AAA/AAA/AAA/BBB/BBB/BBB/BCC/CCC/CCC/DCC/DDD/DDD/DDD/EEE/EEE/FEF/FFF/FFF/GGG/GGG/GGG/HHH/HHH/III/III/JJJ/JJJ/KJJ/KKK/KLK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/RQQ/RRR/SRR/SSS/STT/TTT/UTU/UUU/VVV/VVV/WWW/WWW/XXX/XXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/cbb/ccc/ddd/ddd/eee/eee/fff/ggg/ggg/hhh/hhh/iii/iii/jjj/jjk/kkk/lll/lll/mmm/mmm/nnn/ooo/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/tst/ttt/utt/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/122/222/222/333/333/444/444/555/555/555/666/666/667/777/777/888/888/888/999/999/999/++9/+++/+++/+++/////////////AAA/AAA/AAA/AAA/BBB/BBB/BBB/BBB/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/FEE/FFF/FFF/GGG/GGG/HGG/HHH/HHH/III/III/JJJ/JJJ/JKJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QRQ/RRR/RRS/SSS/TST/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/XYY/YYY/ZZZ/ZZZ/aaa/aaa/bbb/bcc/ccc/ddd/ddd/eee/eee/fff/gfg/ggg/hhh/hhh/iii/iii/jjj/jjk/kkk/lll/lll/mmm/mmm/nnn/onn/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/tst/ttt/uuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/211/222/222/333/333/444/444/455/555/555/666/666/776/777/777/887/888/888/899/999/999/999/+++/+++/+++/////////////AAA/AAA/AAA/AAA/BBB/BBB/BBB/CBC/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/EEF/FFF/FFF/GGG/GGG/HHG/HHH/HHH/III/III/JJJ/JJJ/KKJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QQR/RRR/RRR/SSS/STT/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/XXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/bcb/ccc/ddd/ddd/eee/eee/fff/gff/ggg/hhh/hhh/iii/iii/jjj/jkk/kkk/lll/lll/mmm/mmm/nnn/noo/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/sss/ttt/uuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/211/222/322/333/333/444/444/554/555/555/666/666/766/777/777/878/888/888/999/999/999/+9+/+++/+++/+++/////////////AAA/AAA/AAA/AAA/BBB/BBB/BBB/BBB/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/EEF/FFF/FFF/GGG/GGG/GGH/HHH/HHH/III/III/JJJ/JJJ/KJJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QQQ/RRR/RSR/SSS/TTT/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/YXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/cbb/ccc/ddd/ddd/eee/eee/fff/ffg/ggg/hhh/hhh/iii/iii/jjj/kkj/kkk/lll/lll/mmm/mmn/nnn/ono/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/stt/ttt/tuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/111/222/222/333/333/444/444/554/555/555/666/666/766/777/777/777/888/888/999/999/999/9++/+++/+++/+++/////////////AAA/AAA/AAA/AAA/BBB/BBB/BBB/BCC/CCC/CCC/DCC/DDD/DDD/DDD/EEE/EEE/FEF/FFF/FFF/GGG/GGG/GGG/HHH/HHH/III/III/JJJ/JJJ/KJJ/KKK/KLK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/RQQ/RRR/SRR/SSS/STT/TTT/UTU/UUU/VVV/VVV/WWW/WWW/XXX/XXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/cbb/ccc/ddd/ddd/eee/eee/fff/ggg/ggg/hhh/hhh/iii/iii/jjj/jjk/kkk/lll/lll/mmm/mmm/nnn/ooo/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/tst/ttt/utt/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/122/222/222/333/333/444/444/555/555/555/666/666/667/777/777/888/888/888/999/999/999/++9/+++/+++/+++/////////////AAA/AAA/AAA/AAA/BBB/BBB/BBB/BBB/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/FEE/FFF/FFF/GGG/GGG/HGG/HHH/HHH/III/III/JJJ/JJJ/JKJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QRQ/RRR/RRS/SSS/TST/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/XYY/YYY/ZZZ/ZZZ/aaa/aaa/bbb/bcc/ccc/ddd/ddd/eee/eee/fff/gfg/ggg/hhh/hhh/iii/iii/jjj/jjk/kkk/lll/lll/mmm/mmm/nnn/onn/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/tst/ttt/uuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/211/222/222/333/333/444/444/455/555/555/666/666/776/777/777/887/888/888/899/999/999/999/+++/+++/+++/////////////AAA/AAA/AAA/AAA/BBB/BBB/BBB/CBC/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/EEF/FFF/FFF/GGG/GGG/HHG/HHH/HHH/III/III/JJJ/JJJ/KKJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QQR/RRR/RRR/SSS/STT/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/XXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/bcb/ccc/ddd/ddd/eee/eee/fff/gff/ggg/hhh/hhh/iii/iii/jjj/jkk/kkk/lll/lll/mmm/mmm/nnn/noo/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/sss/ttt/uuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/211/222/322/333/333/444/444/554/555/555/666/666/766/777/777/878/888/888/999/999/999/+9+/+++/+++/+++/////////////GBA+AAA/AAA/AAA/BBB/BBB/BBB/BBB/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/EEF/FFF/FFF/GGG/GGG/GGH/HHH/HHH/III/III/JJJ/JJJ/KJJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QQQ/RRR/RSR/SSS/TTT/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/YXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/cbb/ccc/ddd/ddd/eee/eee/fff/ffg/ggg/hhh/hhh/iii/iii/jjj/kkj/kkk/lll/lll/mmm/mmn/nnn/ono/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/stt/ttt/tuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/111/222/222/333/333/444/444/554/555/555/666/666/766/777/777/777/888/888/999/999/999/9++/+++/+++/+++/////////++/+OCA5AAA/AAA/AAA/BBB/BBB/BBB/BCC/CCC/CCC/DCC/DDD/DDD/DDD/EEE/EEE/FEF/FFF/FFF/GGG/GGG/GGG/HHH/HHH/III/III/JJJ/JJJ/KJJ/KKK/KLK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/RQQ/RRR/SRR/SSS/STT/TTT/UTU/UUU/VVV/VVV/WWW/WWW/XXX/XXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/cbb/ccc/ddd/ddd/eee/eee/fff/ggg/ggg/hhh/hhh/iii/iii/jjj/jjk/kkk/lll/lll/mmm/mmm/nnn/ooo/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/tst/ttt/utt/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/122/222/222/333/333/444/444/555/555/555/666/666/667/777/777/888/888/888/999/999/999/++9/+++/+++/+++/////////89/5WEAsAAA/AAA/AAA/BBB/BBB/BBB/BBB/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/FEE/FFF/FFF/GGG/GGG/HGG/HHH/HHH/III/III/JJJ/JJJ/JKJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QRQ/RRR/RRS/SSS/TST/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/XYY/YYY/ZZZ/ZZZ/aaa/aaa/bbb/bcc/ccc/ddd/ddd/eee/eee/fff/gfg/ggg/hhh/hhh/iii/iii/jjj/jjk/kkk/lll/lll/mmm/mmm/nnn/onn/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/tst/ttt/uuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/211/222/222/333/333/444/444/455/555/555/666/666/776/777/777/887/888/888/899/999/999/999/+++/+++/+++/////////78/scFASKCA9AAA/AAA/BBB/BBB/BBB/CBC/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/EEF/FFF/FFF/GGG/GGG/HHG/HHH/HHH/III/III/JJJ/JJJ/KKJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QQR/RRR/RRR/SSS/STT/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/XXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/bcb/ccc/ddd/ddd/eee/eee/fff/gff/ggg/hhh/hhh/iii/iii/jjj/jkk/kkk/lll/lll/mmm/mmm/nnn/noo/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/sss/ttt/uuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/211/222/322/333/333/444/444/554/555/555/666/666/766/777/777/878/888/888/999/999/999/+9+/+++/+++/+++/////99/967/S///AXEApBAA/AAA/BBB/BBB/BBB/BBB/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/EEF/FFF/FFF/GGG/GGG/GGH/HHH/HHH/III/III/JJJ/JJJ/KJJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QQQ/RRR/RSR/SSS/TTT/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/YXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/cbb/ccc/ddd/ddd/eee/eee/fff/ffg/ggg/hhh/hhh/iii/iii/jjj/kkj/kkk/lll/lll/mmm/mmn/nnn/ono/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/stt/ttt/tuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/111/222/222/333/333/444/444/554/555/555/666/666/766/777/777/777/888/888/999/999/999/9++/+++/+++/+++/////67/p///A///A///AVEAvBAA/BBB/BBB/BBB/BCC/CCC/CCC/DCC/DDD/DDD/DDD/EEE/EEE/FEF/FFF/FFF/GGG/GGG/GGG/HHH/HHH/III/III/JJJ/JJJ/KJJ/KKK/KLK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/RQQ/RRR/SRR/SSS/STT/TTT/UTU/UUU/VVV/VVV/WWW/WWW/XXX/XXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/cbb/ccc/ddd/ddd/eee/eee/fff/ggg/ggg/hhh/hhh/iii/iii/jjj/jjk/kkk/lll/lll/mmm/mmm/nnn/ooo/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/tst/ttt/utt/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/122/222/222/333/333/444/444/555/555/555/666/666/667/777/777/888/888/888/999/999/999/++9/+++/+++/+++/78/v///A///A///A///A///AXFApKDA9BBB/BBB/BBB/CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/FEE/FFF/FFF/GGG/GGG/HGG/HHH/HHH/III/III/JJJ/JJJ/JKJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QRQ/RRR/RRS/SSS/TST/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/XYY/YYY/ZZZ/ZZZ/aaa/aaa/bbb/bcc/ccc/ddd/ddd/eee/eee/fff/gfg/ggg/hhh/hhh/iii/iii/jjj/jjk/kkk/lll/lll/mmm/mmm/nnn/onn/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/tst/ttt/uuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/211/222/222/333/333/444/444/455/555/555/666/666/776/777/777/887/888/888/899/999/999/999/+++/89+967/p///A///A///A///A///A///A///AdHASXGAsQFB5IDB+CCC/CCC/CCC/DDD/DDD/DDD/EEE/EEE/EEF/FFF/FFF/GGG/GGG/HHG/HHH/HHH/III/III/JJJ/JJJ/KKJ/KKK/KKK/LLL/LLL/MMM/MMM/NNN/NNN/OOO/OOO/PPP/PPP/QQQ/QQR/RRR/RRR/SSS/STT/TTT/UUU/UUU/VVV/VVV/WWW/WWW/XXX/XXX/YYY/ZZZ/ZZZ/aaa/aaa/bbb/bcb/ccc/ddd/ddd/eee/eee/fff/gff/ggg/hhh/hhh/iii/iii/jjj/jkk/kkk/lll/lll/mmm/mmm/nnn/noo/ooo/ppp/ppp/qqq/qqq/rrr/rrr/sss/sss/ttt/uuu/uuu/vvv/vvv/www/www/xxx/xxx/yyy/yyy/zzz/zzz/000/000/111/111/211/222/322/333/333/444/444/554/555/555/666/666/766/777/777/878/888/888/999/999/88++78+567+s56/S///A///A///A///A") 
  1380 
  1381 def drawIcon(icon, x, y):
  1382     BGL.glEnable(BGL.GL_BLEND)
  1383     BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA) 
  1384     BGL.glRasterPos2f(int(x)+0.5, int(y)+0.5)
  1385     BGL.glDrawPixels(16, 16, BGL.GL_RGBA, BGL.GL_UNSIGNED_BYTE, icon)
  1386     BGL.glDisable(BGL.GL_BLEND)
  1387 
  1388 def drawArrow(icon, x, y):
  1389     BGL.glEnable(BGL.GL_BLEND)
  1390     BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA) 
  1391     BGL.glRasterPos2f(int(x)+0.5, int(y)+0.5)
  1392     BGL.glDrawPixels(22, 22, BGL.GL_RGBA, BGL.GL_UNSIGNED_BYTE, icon)
  1393     BGL.glDisable(BGL.GL_BLEND)
  1394 
  1395 def drawLogo(icon, x, y):
  1396     BGL.glEnable(BGL.GL_BLEND)
  1397     BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA) 
  1398     BGL.glRasterPos2f(int(x)+0.5, int(y)+0.5)
  1399     BGL.glDrawPixels(118, 18, BGL.GL_RGBA, BGL.GL_UNSIGNED_BYTE, icon)
  1400     BGL.glDisable(BGL.GL_BLEND)
  1401 
  1402 def drawBar(icon, x, y):
  1403     BGL.glEnable(BGL.GL_BLEND)
  1404     BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA) 
  1405     BGL.glRasterPos2f(int(x)+0.5, int(y)+0.5)
  1406     BGL.glDrawPixels(138, 17, BGL.GL_RGBA, BGL.GL_UNSIGNED_BYTE, icon)
  1407     BGL.glDisable(BGL.GL_BLEND)
  1408 
  1409 
  1410 
  1411 #-------------------------------------------------
  1412 # luxImage()
  1413 # helper class to handle images and icons for the GUI
  1414 #-------------------------------------------------
  1415 
  1416 class luxImage:
  1417     def resize(self, width, height):
  1418         self.width = width
  1419         self.height = height
  1420         self.buf = BGL.Buffer(BGL.GL_BYTE, [width,height,4]) # GL buffer
  1421     def __init__(self, width=0, height=0):
  1422         self.resize(width, height)
  1423     def draw(self, x, y):
  1424         BGL.glEnable(BGL.GL_BLEND)
  1425         BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA) 
  1426         BGL.glRasterPos2f(int(x)+0.5, int(y)+0.5)
  1427         BGL.glDrawPixels(self.width, self.height, BGL.GL_RGBA, BGL.GL_UNSIGNED_BYTE, self.buf)
  1428         BGL.glDisable(BGL.GL_BLEND)        
  1429     def decodeStr(self, width, height, s):
  1430         self.resize(width, height)
  1431         offset = 0
  1432         for y in range(self.height):
  1433             for x in range(self.width):
  1434                 for c in range(4):
  1435                     self.buf[y][x][c] = int(base64value(s[offset])*4.048)
  1436                     offset += 1
  1437 
  1438     def decodeLuxConsole(self, width, height, data):
  1439         self.resize(width, height)
  1440         offset = 0
  1441         for y in range(self.height-1,-1,-1):
  1442             for x in range(self.width):
  1443                 for c in range(3):
  1444                     self.buf[y][x][c] = ord(data[offset])
  1445                     offset += 1
  1446                 self.buf[y][x][3] = 255
  1447 
  1448 
  1449 previewCache = {}  # dictionary that will hold all preview images
  1450 
  1451 
  1452 ######################################################
  1453 # New GUI by Zuegs
  1454 ######################################################
  1455 
  1456 from types import *
  1457 
  1458 evtLuxGui = 99
  1459 evtSavePreset = 98
  1460 evtDeletePreset = 97
  1461 evtSaveMaterial = 96
  1462 evtLoadMaterial = 95
  1463 evtDeleteMaterial = 94
  1464 evtConvertMaterial = 92
  1465 evtSaveMaterial2 = 91
  1466 evtLoadMaterial2 = 90
  1467 
  1468 
  1469 # default settings
  1470 defaultsExclude = ['preset','filename','page','link']
  1471 try:
  1472     luxdefaults = Blender.Registry.GetKey('luxblend', True)
  1473     if not(type(luxdefaults) is DictType):
  1474         luxdefaults = {}
  1475 except:
  1476     luxdefaults = {}
  1477 newluxdefaults = luxdefaults.copy()
  1478 
  1479 
  1480 def saveluxdefaults():
  1481     try: del newluxdefaults['page']
  1482     except: pass
  1483     try: Blender.Registry.SetKey('luxblend', newluxdefaults, True)
  1484     except: pass
  1485 
  1486 
  1487 
  1488 
  1489 
  1490 # *** PRESETS **************************************
  1491 presetsExclude = ['preset','lux','datadir','threads','filename','page','RGC','film.gamma','colorclamp','link']
  1492 def getPresets(key):
  1493     presets = Blender.Registry.GetKey(key, True)
  1494     if not(type(presets) is DictType):
  1495         presets = {}
  1496     return presets
  1497 def getScenePresets():
  1498     presets = getPresets('luxblend_presets').copy()
  1499 
  1500     # radiance's hardcoded render presets:
  1501 
  1502     presets['0 Preview - Direct Lighting'] = {
  1503     'film.displayinterval': 4,
  1504     'haltspp': 0,
  1505     'useparamkeys': 'false',
  1506     'sampler.showadvanced': 'false',
  1507     'sintegrator.showadvanced': 'false',
  1508     'pixelfilter.showadvanced': 'false',
  1509 
  1510     'sampler.type': 'lowdiscrepancy',
  1511     'sampler.lowdisc.pixelsamples': 1,
  1512     'sampler.lowdisc.pixelsampler': 'lowdiscrepancy',
  1513 
  1514     'sintegrator.type': 'directlighting',
  1515     'sintegrator.dlighting.maxdepth': 5,
  1516 
  1517     'pixelfilter.type': 'mitchell',
  1518     'pixelfilter.mitchell.sharp': 0.250, 
  1519     'pixelfilter.mitchell.xwidth': 2.0, 
  1520     'pixelfilter.mitchell.ywidth': 2.0, 
  1521     'pixelfilter.mitchell.optmode': "slider" }
  1522 
  1523     presets['1 Final - MLT/Bidir Path Tracing (interior) (recommended)'] =  {
  1524     'film.displayinterval': 8,
  1525     'haltspp': 0,
  1526     'useparamkeys': 'false',
  1527     'sampler.showadvanced': 'false',
  1528     'sintegrator.showadvanced': 'false',
  1529     'pixelfilter.showadvanced': 'false',
  1530 
  1531     'sampler.type': 'metropolis',
  1532     'sampler.metro.strength': 0.6,
  1533     'sampler.metro.lmprob': 0.4,
  1534     'sampler.metro.maxrejects': 512,
  1535     #'sampler.metro.initsamples': 262144,
  1536     'sampler.metro.usevariance': "false",
  1537 
  1538     'sintegrator.type': 'bidirectional',
  1539     'sintegrator.bidir.bounces': 16,
  1540     'sintegrator.bidir.eyedepth': 16,
  1541     'sintegrator.bidir.lightdepth': 16,
  1542 
  1543     'pixelfilter.type': 'mitchell',
  1544     'pixelfilter.mitchell.sharp': 0.250, 
  1545     'pixelfilter.mitchell.xwidth': 2.0, 
  1546     'pixelfilter.mitchell.ywidth': 2.0, 
  1547     'pixelfilter.mitchell.optmode': "slider" }
  1548 
  1549     presets['2 Final - MLT/Path Tracing (exterior)'] =  {
  1550     'film.displayinterval': 8,
  1551     'haltspp': 0,
  1552     'useparamkeys': 'false',
  1553     'sampler.showadvanced': 'false',
  1554     'sintegrator.showadvanced': 'false',
  1555     'pixelfilter.showadvanced': 'false',
  1556 
  1557     'sampler.type': 'metropolis',
  1558     'sampler.metro.strength': 0.6,
  1559     'sampler.metro.lmprob': 0.4,
  1560     'sampler.metro.maxrejects': 512,
  1561     #'sampler.metro.initsamples': 262144,
  1562     'sampler.metro.usevariance': "false",
  1563 
  1564     'sintegrator.type': 'path',
  1565     'sintegrator.bidir.bounces': 10,
  1566     'sintegrator.bidir.maxdepth': 10,
  1567 
  1568     'pixelfilter.type': 'mitchell',
  1569     'pixelfilter.mitchell.sharp': 0.250, 
  1570     'pixelfilter.mitchell.xwidth': 2.0, 
  1571     'pixelfilter.mitchell.ywidth': 2.0, 
  1572     'pixelfilter.mitchell.optmode': "slider" }
  1573     
  1574     presets['4 '] = { }
  1575 
  1576     presets['5 Progressive - Bidir Path Tracing (interior)'] =  {
  1577     'film.displayinterval': 8,
  1578     'haltspp': 0,
  1579     'useparamkeys': 'false',
  1580     'sampler.showadvanced': 'false',
  1581     'sintegrator.showadvanced': 'false',
  1582     'pixelfilter.showadvanced': 'false',
  1583 
  1584     'sampler.type': 'lowdiscrepancy',
  1585     'sampler.lowdisc.pixelsamples': 1,
  1586     'sampler.lowdisc.pixelsampler': 'lowdiscrepancy',
  1587 
  1588     'sintegrator.type': 'bidirectional',
  1589     'sintegrator.bidir.bounces': 16,
  1590     'sintegrator.bidir.eyedepth': 16,
  1591     'sintegrator.bidir.lightdepth': 16,
  1592 
  1593     'pixelfilter.type': 'mitchell',
  1594     'pixelfilter.mitchell.sharp': 0.250, 
  1595     'pixelfilter.mitchell.xwidth': 2.0, 
  1596     'pixelfilter.mitchell.ywidth': 2.0, 
  1597     'pixelfilter.mitchell.optmode': "slider" }
  1598 
  1599     presets['6 Progressive - Path Tracing (exterior)'] =  {
  1600     'film.displayinterval': 8,
  1601     'haltspp': 0,
  1602     'useparamkeys': 'false',
  1603     'sampler.showadvanced': 'false',
  1604     'sintegrator.showadvanced': 'false',
  1605     'pixelfilter.showadvanced': 'false',
  1606 
  1607     'sampler.type': 'lowdiscrepancy',
  1608     'sampler.lowdisc.pixelsamples': 1,
  1609     'sampler.lowdisc.pixelsampler': 'lowdiscrepancy',
  1610 
  1611     'sintegrator.type': 'path',
  1612     'sintegrator.bidir.bounces': 10,
  1613     'sintegrator.bidir.maxdepth': 10,
  1614 
  1615     'pixelfilter.type': 'mitchell',
  1616     'pixelfilter.mitchell.sharp': 0.250, 
  1617     'pixelfilter.mitchell.xwidth': 2.0, 
  1618     'pixelfilter.mitchell.ywidth': 2.0, 
  1619     'pixelfilter.mitchell.optmode': "slider" }
  1620 
  1621     presets['7 '] = { }
  1622 
  1623     presets['8 Bucket - Bidir Path Tracing (interior)'] =  {
  1624     'film.displayinterval': 8,
  1625     'haltspp': 0,
  1626     'useparamkeys': 'false',
  1627     'sampler.showadvanced': 'false',
  1628     'sintegrator.showadvanced': 'false',
  1629     'pixelfilter.showadvanced': 'false',
  1630 
  1631     'sampler.type': 'lowdiscrepancy',
  1632     'sampler.lowdisc.pixelsamples': 64,
  1633     'sampler.lowdisc.pixelsampler': 'hilbert',
  1634 
  1635     'sintegrator.type': 'bidirectional',
  1636     'sintegrator.bidir.bounces': 8,
  1637     'sintegrator.bidir.eyedepth': 8,
  1638     'sintegrator.bidir.lightdepth': 10,
  1639 
  1640     'pixelfilter.type': 'mitchell',
  1641     'pixelfilter.mitchell.sharp': 0.250, 
  1642     'pixelfilter.mitchell.xwidth': 2.0, 
  1643     'pixelfilter.mitchell.ywidth': 2.0, 
  1644     'pixelfilter.mitchell.optmode': "slider" }
  1645 
  1646     presets['9 Bucket - Path Tracing (exterior)'] =  {
  1647     'film.displayinterval': 8,
  1648     'haltspp': 0,
  1649     'useparamkeys': 'false',
  1650     'sampler.showadvanced': 'false',
  1651     'sintegrator.showadvanced': 'false',
  1652     'pixelfilter.showadvanced': 'false',
  1653 
  1654     'sampler.type': 'lowdiscrepancy',
  1655     'sampler.lowdisc.pixelsamples': 64,
  1656     'sampler.lowdisc.pixelsampler': 'hilbert',
  1657 
  1658     'sintegrator.type': 'path',
  1659     'sintegrator.bidir.bounces': 8,
  1660     'sintegrator.bidir.maxdepth': 8,
  1661 
  1662     'pixelfilter.type': 'mitchell',
  1663     'pixelfilter.mitchell.sharp': 0.333, 
  1664     'pixelfilter.mitchell.xwidth': 2.0, 
  1665     'pixelfilter.mitchell.ywidth': 2.0, 
  1666     'pixelfilter.mitchell.optmode': "slider" }
  1667 
  1668     presets['A '] = { }
  1669 
  1670     presets['B Anim - Distributed/GI low Q'] =  {
  1671     'film.displayinterval': 8,
  1672     'haltspp': 1,
  1673     'useparamkeys': 'false',
  1674     'sampler.showadvanced': 'false',
  1675     'sintegrator.showadvanced': 'false',
  1676     'pixelfilter.showadvanced': 'false',
  1677 
  1678     'sampler.type': 'lowdiscrepancy',
  1679     'sampler.lowdisc.pixelsamples': 16,
  1680     'sampler.lowdisc.pixelsampler': 'hilbert',
  1681 
  1682     'sintegrator.type': 'distributedpath',
  1683     'sintegrator.distributedpath.causticsonglossy': 'true',
  1684     'sintegrator.distributedpath.diffuserefractdepth': 5,
  1685     'sintegrator.distributedpath.indirectglossy': 'true',
  1686     'sintegrator.distributedpath.directsamples': 1,
  1687     'sintegrator.distributedpath.diffuserefractsamples': 1,
  1688     'sintegrator.distributedpath.glossyreflectdepth': 2,
  1689     'sintegrator.distributedpath.causticsondiffuse': 'false',
  1690     'sintegrator.distributedpath.directsampleall': 'true',
  1691     'sintegrator.distributedpath.indirectdiffuse': 'true',
  1692     'sintegrator.distributedpath.specularreflectdepth': 3,
  1693     'sintegrator.distributedpath.diffusereflectsamples': 1,
  1694     'sintegrator.distributedpath.glossyreflectsamples': 1,
  1695     'sintegrator.distributedpath.glossyrefractdepth': 5,
  1696     'sintegrator.distributedpath.diffusereflectdepth': '2',
  1697     'sintegrator.distributedpath.indirectsamples': 1,
  1698     'sintegrator.distributedpath.indirectsampleall': 'false',
  1699     'sintegrator.distributedpath.glossyrefractsamples': 1,
  1700     'sintegrator.distributedpath.directdiffuse': 'true',
  1701     'sintegrator.distributedpath.directglossy': 'true',
  1702     'sintegrator.distributedpath.strategy': 'auto',
  1703     'sintegrator.distributedpath.specularrefractdepth': 5,
  1704 
  1705     'pixelfilter.type': 'mitchell',
  1706     'pixelfilter.mitchell.sharp': 0.333, 
  1707     'pixelfilter.mitchell.xwidth': 2.0, 
  1708     'pixelfilter.mitchell.ywidth': 2.0, 
  1709     'pixelfilter.mitchell.optmode': "slider" }
  1710 
  1711     presets['C Anim - Distributed/GI medium Q'] =  {
  1712     'film.displayinterval': 8,
  1713     'haltspp': 1,
  1714     'useparamkeys': 'false',
  1715     'sampler.showadvanced': 'false',
  1716     'sintegrator.showadvanced': 'false',
  1717     'pixelfilter.showadvanced': 'false',
  1718 
  1719     'sampler.type': 'lowdiscrepancy',
  1720     'sampler.lowdisc.pixelsamples': 64,
  1721     'sampler.lowdisc.pixelsampler': 'hilbert',
  1722 
  1723     'sintegrator.type': 'distributedpath',
  1724     'sintegrator.distributedpath.causticsonglossy': 'true',
  1725     'sintegrator.distributedpath.diffuserefractdepth': 5,
  1726     'sintegrator.distributedpath.indirectglossy': 'true',
  1727     'sintegrator.distributedpath.directsamples': 1,
  1728     'sintegrator.distributedpath.diffuserefractsamples': 1,
  1729     'sintegrator.distributedpath.glossyreflectdepth': 2,
  1730     'sintegrator.distributedpath.causticsondiffuse': 'false',
  1731     'sintegrator.distributedpath.directsampleall': 'true',
  1732     'sintegrator.distributedpath.indirectdiffuse': 'true',
  1733     'sintegrator.distributedpath.specularreflectdepth': 3,
  1734     'sintegrator.distributedpath.diffusereflectsamples': 1,
  1735     'sintegrator.distributedpath.glossyreflectsamples': 1,
  1736     'sintegrator.distributedpath.glossyrefractdepth': 5,
  1737     'sintegrator.distributedpath.diffusereflectdepth': '2',
  1738     'sintegrator.distributedpath.indirectsamples': 1,
  1739     'sintegrator.distributedpath.indirectsampleall': 'false',
  1740     'sintegrator.distributedpath.glossyrefractsamples': 1,
  1741     'sintegrator.distributedpath.directdiffuse': 'true',
  1742     'sintegrator.distributedpath.directglossy': 'true',
  1743     'sintegrator.distributedpath.strategy': 'auto',
  1744     'sintegrator.distributedpath.specularrefractdepth': 5,
  1745 
  1746     'pixelfilter.type': 'mitchell',
  1747     'pixelfilter.mitchell.sharp': 0.333, 
  1748     'pixelfilter.mitchell.xwidth': 2.0, 
  1749     'pixelfilter.mitchell.ywidth': 2.0, 
  1750     'pixelfilter.mitchell.optmode': "slider" }
  1751     
  1752     presets['D Anim - Distributed/GI high Q'] =  {
  1753     'film.displayinterval': 8,
  1754     'haltspp': 1,
  1755     'useparamkeys': 'false',
  1756     'sampler.showadvanced': 'false',
  1757     'sintegrator.showadvanced': 'false',
  1758     'pixelfilter.showadvanced': 'false',
  1759 
  1760     'sampler.type': 'lowdiscrepancy',
  1761     'sampler.lowdisc.pixelsamples': 256,
  1762     'sampler.lowdisc.pixelsampler': 'hilbert',
  1763 
  1764     'sintegrator.type': 'distributedpath',
  1765     'sintegrator.distributedpath.causticsonglossy': 'true',
  1766     'sintegrator.distributedpath.diffuserefractdepth': 5,
  1767     'sintegrator.distributedpath.indirectglossy': 'true',
  1768     'sintegrator.distributedpath.directsamples': 1,
  1769     'sintegrator.distributedpath.diffuserefractsamples': 1,
  1770     'sintegrator.distributedpath.glossyreflectdepth': 2,
  1771     'sintegrator.distributedpath.causticsondiffuse': 'false',
  1772     'sintegrator.distributedpath.directsampleall': 'true',
  1773     'sintegrator.distributedpath.indirectdiffuse': 'true',
  1774     'sintegrator.distributedpath.specularreflectdepth': 3,
  1775     'sintegrator.distributedpath.diffusereflectsamples': 1,
  1776     'sintegrator.distributedpath.glossyreflectsamples': 1,
  1777     'sintegrator.distributedpath.glossyrefractdepth': 5,
  1778     'sintegrator.distributedpath.diffusereflectdepth': '2',
  1779     'sintegrator.distributedpath.indirectsamples': 1,
  1780     'sintegrator.distributedpath.indirectsampleall': 'false',
  1781     'sintegrator.distributedpath.glossyrefractsamples': 1,
  1782     'sintegrator.distributedpath.directdiffuse': 'true',
  1783     'sintegrator.distributedpath.directglossy': 'true',
  1784     'sintegrator.distributedpath.strategy': 'auto',
  1785     'sintegrator.distributedpath.specularrefractdepth': 5,
  1786 
  1787     'pixelfilter.type': 'mitchell',
  1788     'pixelfilter.mitchell.sharp': 0.333, 
  1789     'pixelfilter.mitchell.xwidth': 2.0, 
  1790     'pixelfilter.mitchell.ywidth': 2.0, 
  1791     'pixelfilter.mitchell.optmode': "slider" }
  1792 
  1793     presets['E Anim - Distributed/GI very high Q'] =  {
  1794     'film.displayinterval': 8,
  1795     'haltspp': 1,
  1796     'useparamkeys': 'false',
  1797     'sampler.showadvanced': 'false',
  1798     'sintegrator.showadvanced': 'false',
  1799     'pixelfilter.showadvanced': 'false',
  1800 
  1801     'sampler.type': 'lowdiscrepancy',
  1802     'sampler.lowdisc.pixelsamples': 512,
  1803     'sampler.lowdisc.pixelsampler': 'hilbert',
  1804 
  1805     'sintegrator.type': 'distributedpath',
  1806     'sintegrator.distributedpath.causticsonglossy': 'true',
  1807     'sintegrator.distributedpath.diffuserefractdepth': 5,
  1808     'sintegrator.distributedpath.indirectglossy': 'true',
  1809     'sintegrator.distributedpath.directsamples': 1,
  1810     'sintegrator.distributedpath.diffuserefractsamples': 1,
  1811     'sintegrator.distributedpath.glossyreflectdepth': 2,
  1812     'sintegrator.distributedpath.causticsondiffuse': 'false',
  1813     'sintegrator.distributedpath.directsampleall': 'true',
  1814     'sintegrator.distributedpath.indirectdiffuse': 'true',
  1815     'sintegrator.distributedpath.specularreflectdepth': 3,
  1816     'sintegrator.distributedpath.diffusereflectsamples': 1,
  1817     'sintegrator.distributedpath.glossyreflectsamples': 1,
  1818     'sintegrator.distributedpath.glossyrefractdepth': 5,
  1819     'sintegrator.distributedpath.diffusereflectdepth': '2',
  1820     'sintegrator.distributedpath.indirectsamples': 1,
  1821     'sintegrator.distributedpath.indirectsampleall': 'false',
  1822     'sintegrator.distributedpath.glossyrefractsamples': 1,
  1823     'sintegrator.distributedpath.directdiffuse': 'true',
  1824     'sintegrator.distributedpath.directglossy': 'true',
  1825     'sintegrator.distributedpath.strategy': 'auto',
  1826     'sintegrator.distributedpath.specularrefractdepth': 5,
  1827 
  1828     'pixelfilter.type': 'mitchell',
  1829     'pixelfilter.mitchell.sharp': 0.333, 
  1830     'pixelfilter.mitchell.xwidth': 2.0, 
  1831     'pixelfilter.mitchell.ywidth': 2.0, 
  1832     'pixelfilter.mitchell.optmode': "slider" }
  1833 
  1834     return presets
  1835 
  1836 def getMaterialPresets():
  1837     return getPresets('luxblend_materials')
  1838 
  1839 def savePreset(key, name, d):
  1840     try:
  1841         presets = getPresets(key)
  1842         if d:
  1843             presets[name] = d.copy()
  1844         else:
  1845             del presets[name]
  1846         Blender.Registry.SetKey(key, presets, True)
  1847     except: pass    
  1848 def saveScenePreset(name, d):
  1849     try:
  1850         for n in presetsExclude:
  1851             try: del d[n]
  1852             except: pass
  1853         savePreset('luxblend_presets', name, d)
  1854     except: pass
  1855 def saveMaterialPreset(name, d):
  1856     try:
  1857         for n in presetsExclude:
  1858             try: del d[n]
  1859             except: pass
  1860         savePreset('luxblend_materials', name, d)
  1861     except: pass
  1862 
  1863 
  1864 # **************************************************
  1865 
  1866 
  1867 
  1868 
  1869 
  1870 usedproperties = {} # global variable to collect used properties for storing presets
  1871 usedpropertiesfilterobj = None # assign a object to only collect the properties that are assigned to this object
  1872 
  1873 # class to access properties (for lux settings)
  1874 class luxProp:
  1875     def __init__(self, obj, name, default):
  1876         self.obj = obj
  1877         self.name = name
  1878 #        if len(name)>31: print("Warning: property-name \"%s\" has more than 31 chars."%(name))
  1879         self.hashmode = len(name)>31   # activate hash mode for keynames longer 31 chars (limited by blenders ID-prop)
  1880         self.hashname = "__hash:%x"%(name.__hash__())
  1881         self.default = default
  1882     def parseassignment(self, s, name):
  1883         l = s.split(" = ")
  1884         if l[0] != name: print("Warning: property-name \"%s\" has hash-collide with \"%s\"."%(name, l[0]))
  1885         return l[1]
  1886     def createassignment(self, name, value):
  1887         return "%s = %s"%(name, value)
  1888     def get(self):
  1889         global usedproperties, usedpropertiesfilterobj, luxdefaults
  1890         if self.obj:
  1891             try:
  1892                 value = self.obj.properties['luxblend'][self.name]
  1893                 if not(usedpropertiesfilterobj) or (usedpropertiesfilterobj == self.obj):
  1894                     usedproperties[self.name] = value
  1895                 return value
  1896             except KeyError:
  1897                 try:
  1898                     value = self.parseassignment(self.obj.properties['luxblend'][self.hashname], self.name)
  1899                     if not(usedpropertiesfilterobj) or (usedpropertiesfilterobj == self.obj):
  1900                         usedproperties[self.name] = value
  1901                     return value
  1902                 except KeyError:
  1903                     if self.obj.__class__.__name__ == "Scene": # luxdefaults only for global setting
  1904                         try:
  1905                             value = luxdefaults[self.name]
  1906                             if not(usedpropertiesfilterobj) or (usedpropertiesfilterobj == self.obj):
  1907                                 usedproperties[self.name] = value
  1908                             return value
  1909                         except KeyError:
  1910                             if not(usedpropertiesfilterobj) or (usedpropertiesfilterobj == self.obj):
  1911                                 usedproperties[self.name] = self.default
  1912                             return self.default
  1913                     if not(usedpropertiesfilterobj) or (usedpropertiesfilterobj == self.obj):
  1914                         usedproperties[self.name] = self.default
  1915                     return self.default
  1916         return None
  1917     def getobj(self):
  1918         if self.obj:
  1919             return self.obj
  1920         else:
  1921             return None
  1922     def getname(self):
  1923         if self.name:
  1924             return self.name
  1925         else:
  1926             return None
  1927     def set(self, value):
  1928         global newluxdefaults
  1929         if self.obj:
  1930             if self.hashmode: n, v = self.hashname, self.createassignment(self.name, value)
  1931             else: n, v = self.name, value
  1932             if value is not None:
  1933                 try: self.obj.properties['luxblend'][n] = v
  1934                 except (KeyError, TypeError):
  1935                     self.obj.properties['luxblend'] = {}
  1936                     self.obj.properties['luxblend'][n] = v
  1937             else:
  1938                 try: del self.obj.properties['luxblend'][n]
  1939                 except:    pass
  1940             if self.obj.__class__.__name__ == "Scene": # luxdefaults only for global setting
  1941                 # value has changed, so this are user settings, remove preset reference
  1942                 if not(self.name in defaultsExclude):
  1943                     newluxdefaults[self.name] = value
  1944                     try: self.obj.properties['luxblend']['preset']=""
  1945                     except: pass
  1946     def delete(self):
  1947         if self.obj:
  1948             try: del self.obj.properties['luxblend'][self.name]
  1949             except:    pass
  1950             try: del self.obj.properties['luxblend'][self.hashname]
  1951             except:    pass
  1952     def getFloat(self):
  1953         v = self.get()
  1954         if type(v) == types.FloatType: return float(v)
  1955         try:
  1956             if type(v) == types.StringType: return float(v.split(" ")[0])
  1957         except: pass
  1958         v = self.default
  1959         if type(v) == types.FloatType: return float(v)
  1960         try:
  1961             if type(v) == types.StringType: return float(v.split(" ")[0])
  1962         except: pass
  1963         return 0.0
  1964     def getInt(self):
  1965         try: return int(self.get())
  1966         except: return int(self.default)
  1967     def getRGB(self):
  1968         return self.getVector()
  1969     def getVector(self):
  1970         v = self.get()
  1971         if type(v) in [types.FloatType, types.IntType]: return (float(v), float(v), float(v))
  1972         l = None
  1973         try:
  1974             if type(v) == types.StringType: l = self.get().split(" ")
  1975         except: pass
  1976         try:
  1977             if (l==None) or (len(l) != 3): l = self.default.split(" ")
  1978             return (float(l[0]), float(l[1]), float(l[2]))
  1979         except AttributeError:
  1980             return (float(l[0]), float(l[0]), float(l[0]))
  1981         
  1982     def getVectorStr(self):
  1983         return "%f %f %f"%self.getVector()
  1984     def isFloat(self):
  1985         return type(self.get()) == types.FloatType
  1986     def getRGC(self):
  1987         col = self.getRGB()
  1988         return "%f %f %f"%(rg(col[0]), rg(col[1]),rg(col[2]))
  1989     def setRGB(self, value):
  1990         self.set("%f %f %f"%(value[0], value[1], value[2]))
  1991     def setVector(self, value):
  1992         self.set("%f %f %f"%(value[0], value[1], value[2]))
  1993 
  1994 
  1995 # class to access blender attributes (for lux settings)
  1996 class luxAttr:
  1997     def __init__(self, obj, name):
  1998         self.obj = obj
  1999         self.name = name
  2000     def get(self):
  2001         if self.obj:
  2002             return getattr(self.obj, self.name)
  2003         else:
  2004             return None
  2005     def getFloat(self):
  2006         return float(self.get())
  2007     def getInt(self):
  2008         return int(self.get())
  2009     def getobj(self):
  2010         if self.obj:
  2011             return self.obj
  2012         else:
  2013             return None
  2014     def getname(self):
  2015         if self.name:
  2016             return self.name
  2017         else:
  2018             return None
  2019     def set(self, value):
  2020         if self.obj:
  2021             setattr(self.obj, self.name, value)
  2022             Window.QRedrawAll()
  2023 
  2024 
  2025 # class for dynamic gui
  2026 class luxGui:
  2027     def __init__(self, y=200):
  2028         self.x = 110 # left start position after captions
  2029         self.xmax = 110+2*(140+4)
  2030         self.y = y
  2031         self.w = 140 # default element width in pixels
  2032         self.h = 18  # default element height in pixels
  2033         self.hmax = 0
  2034         self.xgap = 4
  2035         self.ygap = 4
  2036         self.resethmax = False
  2037     def getRect(self, wu, hu):
  2038         w = int(self.w * wu + self.xgap * (wu-1))
  2039         h = int(self.h * hu + self.ygap * (hu-1))
  2040         if self.x + w > self.xmax: self.newline()
  2041         if self.resethmax: self.hmax = 0; self.resethmax = False
  2042         rect = [int(self.x), int(self.y-h), int(w), int(h)]
  2043         self.x += int(w + self.xgap)
  2044         if h+self.ygap > self.hmax: self.hmax = int(h+self.ygap)
  2045         return rect
  2046     def newline(self, title="", distance=0, level=0, icon=None, color=None):
  2047         self.x = 110
  2048         if not(self.resethmax): self.y -= int(self.hmax + distance)
  2049         if color!=None:    BGL.glColor3f(color[0],color[1],color[2]); BGL.glRectf(0,self.y-self.hmax,self.xmax,self.y+distance); BGL.glColor3f(0.9, 0.9, 0.9)
  2050         if icon!=None: drawIcon(icon, 2+level*10, self.y-16)
  2051         self.resethmax = True
  2052         if title!="":
  2053             self.getRect(0, 1)
  2054             BGL.glColor3f(0.9,0.9,0.9); BGL.glRasterPos2i(20+level*10,self.y-self.h+5); Draw.Text(title)
  2055     
  2056 def luxHelp(name, lux, caption, hint, gui, width=1.0):
  2057     if gui:
  2058         r = gui.getRect(width, 1)
  2059         Draw.Toggle(caption, evtLuxGui, r[0], r[1], r[2], r[3], lux.get()=="true", hint, lambda e,v: lux.set(["false","true"][bool(v)]))
  2060         drawIcon(icon_help, r[0], r[1])
  2061 
  2062     return "\n   \"bool %s\" [\"%s\"]"%(name, lux.get())
  2063 
  2064 # lux parameter types
  2065 def luxOption(name, lux, options, caption, hint, gui, width=1.0):
  2066     if gui:
  2067         menustr = caption+": %t"
  2068         for i, v in enumerate(options): menustr = "%s %%x%d|%s"%(v, i, menustr)
  2069         try:
  2070             i = options.index(lux.get())
  2071         except ValueError:
  2072             try:
  2073                 lux.set(lux.default) # not found, so try default value
  2074                 i = options.index(lux.get())
  2075             except ValueError:
  2076                 print("value %s not found in options list"%(lux.get()))
  2077                 i = 0
  2078         r = gui.getRect(width, 1)
  2079         Draw.Menu(menustr, evtLuxGui, r[0], r[1], r[2], r[3], i, hint, lambda e,v: lux.set(options[v]))
  2080     return "\n   \"string %s\" [\"%s\"]"%(name, lux.get())
  2081 
  2082 def luxOptionRect(name, lux, options, caption, hint, gui, x, y, xx, yy):
  2083     if gui:
  2084         menustr = caption+": %t"
  2085         for i, v in enumerate(options): menustr = "%s %%x%d|%s"%(v, i, menustr)
  2086         try:
  2087             i = options.index(lux.get())
  2088         except ValueError:
  2089             try:
  2090                 lux.set(lux.default) # not found, so try default value
  2091                 i = options.index(lux.get())
  2092             except ValueError:
  2093                 print ("value %s not found in options list"%(lux.get()))
  2094                 i = 0
  2095         Draw.Menu(menustr, evtLuxGui, x, y, xx, yy, i, hint, lambda e,v: lux.set(options[v]))
  2096     return "\n   \"string %s\" [\"%s\"]"%(name, lux.get())
  2097 
  2098 def luxIdentifier(name, lux, options, caption, hint, gui, icon=None, width=1.0):
  2099     if gui: gui.newline(caption+":", 8, 0, icon, [0.75,0.5,0.25])
  2100     luxOption(name, lux, options, caption, hint, gui, width)
  2101     return "\n%s \"%s\""%(name, lux.get())
  2102 
  2103 def luxFloat(name, lux, min, max, caption, hint, gui, width=1.0, useslider=0):
  2104     if gui:
  2105         if (luxProp(Scene.GetCurrent(), "useparamkeys", "false").get()=="true"):
  2106             r = gui.getRect(width-0.12, 1)
  2107         else:
  2108             r = gui.getRect(width, 1)
  2109 
  2110         # Value
  2111         if(useslider==1):
  2112             Draw.Slider(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.getFloat(), min, max, 0, hint, lambda e,v: lux.set(v))
  2113         else:
  2114             Draw.Number(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.getFloat(), min, max, hint, lambda e,v: lux.set(v))
  2115         if (luxProp(Scene.GetCurrent(), "useparamkeys", "false").get()=="true"):
  2116             # IPO Curve
  2117             obj = lux.getobj()
  2118             keyname = lux.getname()
  2119     
  2120             useipo = luxProp(obj, keyname+".IPOuse", "false")
  2121             i = gui.getRect(0.12, 1)
  2122             Draw.Toggle("I", evtLuxGui, i[0], i[1], i[2], i[3], useipo.get()=="true", "Use IPO Curve", lambda e,v: useipo.set(["false","true"][bool(v)]))
  2123             
  2124             if useipo.get() == "true":
  2125                 if gui: gui.newline(caption+"IPO:", 8, 0, None, [0.5,0.45,0.35])
  2126                 curve = luxProp(obj, keyname+".IPOCurveName", "") 
  2127                 if curve.get() == "":
  2128                     c = gui.getRect(2.0, 1)
  2129                 else:
  2130                     c = gui.getRect(1.1, 1)
  2131                 
  2132                 Draw.String("Ipo:", evtLuxGui, c[0], c[1], c[2], c[3], curve.get(), 250, "Set IPO Name", lambda e,v: curve.set(v))
  2133                 
  2134                 usemapping = luxProp(obj, keyname+".IPOmap", "false")
  2135                 icu_value = 0
  2136     
  2137                 # Apply IPO to value
  2138                 if curve.get() != "":
  2139                     try:
  2140                         ipoob = Blender.Ipo.Get(curve.get())
  2141                     except: 
  2142                         curve.set("")
  2143                     pass
  2144                     if curve.get() != "":
  2145                         names = list([x[0] for x in ipoob.curveConsts.items()])
  2146                         ipotype = luxProp(obj, keyname+".IPOCurveType", "OB_LOCZ")
  2147                         luxOption("ipocurve", ipotype, names, "IPO Curve", "Set IPO Curve", gui, 0.6)
  2148     
  2149                         icu = ipoob[eval("Blender.Ipo.%s" % (ipotype.get()))]
  2150                         icu_value = icu[Blender.Get('curframe')]
  2151                         if usemapping.get() == "false": # if true is set during mapping below
  2152                             lux.set(icu_value)    
  2153     
  2154                         # Mapping options
  2155                         m = gui.getRect(0.3, 1)
  2156                         Draw.Toggle("Map", evtLuxGui, m[0], m[1], m[2], m[3], usemapping.get()=="true", "Edit Curve mapping", lambda e,v: usemapping.set(["false","true"][bool(v)]))
  2157                         if usemapping.get() == "true":
  2158                             if gui: gui.newline(caption+"IPO:", 8, 0, None, [0.5,0.45,0.35])
  2159                             fmin = luxProp(obj, keyname+".IPOCurvefmin", 0.0)
  2160                             luxFloatNoIPO("ipofmin", fmin, -100, 100, "fmin", "Map minimum value from Curve", gui, 0.5)
  2161                             fmax = luxProp(obj, keyname+".IPOCurvefmax", 1.0)
  2162                             luxFloatNoIPO("ipofmax", fmax, -100, 100, "fmax", "Map maximum value from Curve", gui, 0.5)
  2163                             tmin = luxProp(obj, keyname+".IPOCurvetmin", min)
  2164                             luxFloatNoIPO("ipotmin", tmin, min, max, "tmin", "Map miminum value to", gui, 0.5)
  2165                             tmax = luxProp(obj, keyname+".IPOCurvetmax", max)
  2166                             luxFloatNoIPO("ipotmax", tmax, min, max, "tmax", "Map maximum value to", gui, 0.5)
  2167     
  2168                             sval = (icu_value - fmin.getFloat()) / (fmax.getFloat() - fmin.getFloat())
  2169                             lux.set(tmin.getFloat() + (sval * (tmax.getFloat() - tmin.getFloat())))
  2170 
  2171                             # invert
  2172                             #v = gui.getRect(0.5, 1)
  2173                             #Draw.Toggle("Invert", evtLuxGui, v[0], v[1], v[2], v[3], useipo.get()=="true", "Invert Curve values", lambda e,v: useipo.set(["false","true"][bool(v)]))
  2174     else:
  2175         if (luxProp(Scene.GetCurrent(), "useparamkeys", "false").get()=="true"):
  2176             obj = lux.getobj()
  2177             keyname = lux.getname()
  2178             useipo = luxProp(obj, keyname+".IPOuse", "false")
  2179             if useipo.get() == "true":
  2180                 curve = luxProp(obj, keyname+".IPOCurveName", "") 
  2181                 try:
  2182                     ipoob = Blender.Ipo.Get(curve.get())
  2183                 except: 
  2184                     curve.set("")
  2185                 pass
  2186                 usemapping = luxProp(obj, keyname+".IPOmap", "false")
  2187                 icu_value = 0
  2188                 if curve.get() != "":
  2189                     names = list([x[0] for x in ipoob.curveConsts.items()])
  2190                     ipotype = luxProp(obj, keyname+".IPOCurveType", "OB_LOCZ")
  2191     
  2192                     icu = ipoob[eval("Blender.Ipo.%s" % (ipotype.get()))]
  2193                     icu_value = icu[Blender.Get('curframe')]
  2194                     if usemapping.get() == "false": # if true is set during mapping below
  2195                         lux.set(icu_value)    
  2196     
  2197                 if usemapping.get() == "true":
  2198                     if gui: gui.newline(caption+"IPO:", 8, 0, None, [0.5,0.45,0.35])
  2199                     fmin = luxProp(obj, keyname+".IPOCurvefmin", 0.0)
  2200                     fmax = luxProp(obj, keyname+".IPOCurvefmax", 1.0)
  2201                     tmin = luxProp(obj, keyname+".IPOCurvetmin", min)
  2202                     tmax = luxProp(obj, keyname+".IPOCurvetmax", max)
  2203                     sval = (icu_value - fmin.getFloat()) / (fmax.getFloat() - fmin.getFloat())
  2204                     lux.set(tmin.getFloat() + (sval * (tmax.getFloat() - tmin.getFloat())))
  2205 
  2206     return "\n   \"float %s\" [%f]"%(name, lux.getFloat())
  2207 
  2208 def luxFloatNoIPO(name, lux, min, max, caption, hint, gui, width=1.0, useslider=0):
  2209     if gui:
  2210         r = gui.getRect(width, 1)
  2211         if(useslider==1):
  2212             Draw.Slider(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.getFloat(), min, max, 0, hint, lambda e,v: lux.set(v))
  2213         else:
  2214             Draw.Number(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.getFloat(), min, max, hint, lambda e,v: lux.set(v))
  2215     return "\n   \"float %s\" [%f]"%(name, lux.getFloat())
  2216 
  2217 
  2218 
  2219 def luxInt(name, lux, min, max, caption, hint, gui, width=1.0):
  2220     if gui:
  2221         r = gui.getRect(width, 1)
  2222         Draw.Number(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.getInt(), min, max, hint, lambda e,v: lux.set(v))
  2223     return "\n   \"integer %s\" [%d]"%(name, lux.getInt())
  2224 
  2225 def luxBool(name, lux, caption, hint, gui, width=1.0):
  2226     if gui:
  2227         r = gui.getRect(width, 1)
  2228         Draw.Toggle(caption, evtLuxGui, r[0], r[1], r[2], r[3], lux.get()=="true", hint, lambda e,v: lux.set(["false","true"][bool(v)]))
  2229     return "\n   \"bool %s\" [\"%s\"]"%(name, lux.get())
  2230 
  2231 def luxLabel(caption, gui):
  2232     if gui:
  2233         r = gui.getRect(2,1); BGL.glRasterPos2i(r[0],r[1]+5)
  2234         Draw.Text(caption)
  2235 
  2236 def luxCollapse(name, lux, caption, hint, gui, width=1.0):
  2237     if gui:
  2238         r = gui.getRect(width, 1)
  2239         if lux.get() == "true":
  2240             drawArrow(arrow_down, r[0]-22, r[1]-2)
  2241         else:
  2242             drawArrow(arrow_right, r[0]-22, r[1]-2)
  2243         Draw.Toggle(caption, evtLuxGui, r[0], r[1], r[2], r[3], lux.get()=="true", hint, lambda e,v: lux.set(["false","true"][bool(v)]))
  2244     return "\n   \"bool %s\" [\"%s\"]"%(name, lux.get())
  2245 
  2246 def luxString(name, lux, caption, hint, gui, width=1.0):
  2247     if gui:
  2248         r = gui.getRect(width, 1)
  2249         Draw.String(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.get(), 250, hint, lambda e,v: lux.set(v))
  2250     if lux.get()==lux.default: return ""
  2251     else: return "\n   \"string %s\" [\"%s\"]"%(name, luxstr(lux.get()))
  2252 
  2253 def luxFile(name, lux, caption, hint, gui, width=1.0):
  2254     if gui:
  2255         r = gui.getRect(width, 1)
  2256         Draw.String(caption+": ", evtLuxGui, r[0], r[1], r[2]-r[3]-2, r[3], lux.get(), 250, hint, lambda e,v: lux.set(v))
  2257         Draw.Button("...", 0, r[0]+r[2]-r[3], r[1], r[3], r[3], "click to open file selector", lambda e,v:Window.FileSelector(lambda s:lux.set(s), "Select %s"%(caption), lux.get()))
  2258     return "\n   \"string %s\" [\"%s\"]"%(name, luxstr(luxFilePath(lux.get())))
  2259 
  2260 def luxPath(name, lux, caption, hint, gui, width=1.0):
  2261     if gui:
  2262         r = gui.getRect(width, 1)
  2263         Draw.String(caption+": ", evtLuxGui, r[0], r[1], r[2]-r[3]-2, r[3], lux.get(), 250, hint, lambda e,v: lux.set(Blender.sys.dirname(v)+os.sep))
  2264         Draw.Button("...", 0, r[0]+r[2]-r[3], r[1], r[3], r[3], "click to open file selector", lambda e,v:Window.FileSelector(lambda s:lux.set(s), "Select %s"%(caption), lux.get()))
  2265     return "\n   \"string %s\" [\"%s\"]"%(name, luxstr(lux.get()))
  2266 
  2267 def luxRGB(name, lux, max, caption, hint, gui, width=2.0):
  2268     if gui:
  2269         r = gui.getRect(width, 1)
  2270         scale = 1.0
  2271         rgb = lux.getRGB()
  2272         if max > 1.0:
  2273             for i in range(3):
  2274                 if rgb[i] > scale: scale = rgb[i]
  2275             rgb = (rgb[0]/scale, rgb[1]/scale, rgb[2]/scale)
  2276         Draw.ColorPicker(evtLuxGui, r[0], r[1], r[3], r[3], rgb, "click to select color", lambda e,v: lux.setRGB((v[0]*scale,v[1]*scale,v[2]*scale)))
  2277         w = int((r[2]-r[3])/3); m = max
  2278         if max > 1.0:
  2279             w = int((r[2]-r[3])/4); m = 1.0
  2280         drawR, drawG, drawB, drawS = Draw.Create(rgb[0]), Draw.Create(rgb[1]), Draw.Create(rgb[2]), Draw.Create(scale)
  2281         drawR = Draw.Number("R:", evtLuxGui, r[0]+r[3], r[1], w, r[3], drawR.val, 0.0, m, "red", lambda e,v: lux.setRGB((v*scale,drawG.val*scale,drawB.val*scale)))
  2282         drawG = Draw.Number("G:", evtLuxGui, r[0]+r[3]+w, r[1], w, r[3], drawG.val, 0.0, m, "green", lambda e,v: lux.setRGB((drawR.val*scale,v*scale,drawB.val*scale)))
  2283         drawB = Draw.Number("B:", evtLuxGui, r[0]+r[3]+2*w, r[1], w, r[3], drawB.val, 0.0, m, "blue", lambda e,v: lux.setRGB((drawR.val*scale,drawG.val*scale,v*scale)))
  2284         if max > 1.0:
  2285             Draw.Number("s:", evtLuxGui, r[0]+r[3]+3*w, r[1], w, r[3], drawS.val, 0.0, max, "color scale", lambda e,v: lux.setRGB((drawR.val*v,drawG.val*v,drawB.val*v)))
  2286     if max <= 1.0:
  2287         return "\n   \"color %s\" [%s]"%(name, lux.getRGC())
  2288     return "\n   \"color %s\" [%s]"%(name, lux.get())
  2289 
  2290 def luxVector(name, lux, min, max, caption, hint, gui, width=2.0):
  2291     if gui:
  2292         r = gui.getRect(width, 1)
  2293         vec = lux.getVector()
  2294         w = int(r[2]/3)
  2295         drawX, drawY, drawZ = Draw.Create(vec[0]), Draw.Create(vec[1]), Draw.Create(vec[2])
  2296         drawX = Draw.Number("x:", evtLuxGui, r[0], r[1], w, r[3], drawX.val, min, max, "", lambda e,v: lux.setVector((v,drawY.val,drawZ.val)))
  2297         drawY = Draw.Number("y:", evtLuxGui, r[0]+w, r[1], w, r[3], drawY.val, min, max, "", lambda e,v: lux.setVector((drawX.val,v,drawZ.val)))
  2298         drawZ = Draw.Number("z:", evtLuxGui, r[0]+2*w, r[1], w, r[3], drawZ.val, min, max, "", lambda e,v: lux.setVector((drawX.val,drawY.val,v)))
  2299     return "\n   \"vector %s\" [%s]"%(name, lux.get())
  2300 
  2301 def luxVectorUniform(name, lux, min, max, caption, hint, gui, width=2.0):
  2302     def setUniform(lux, value):
  2303         if value: lux.set(lux.getFloat())
  2304         else: lux.setVector(lux.getVector())
  2305     if gui:
  2306         r = gui.getRect(width, 1)
  2307         vec = lux.getVector()
  2308         Draw.Toggle("U", evtLuxGui, r[0], r[1], gui.h, gui.h, lux.isFloat(), "uniform", lambda e,v: setUniform(lux, v))
  2309         if lux.isFloat():
  2310             Draw.Number("v:", evtLuxGui, r[0]+gui.h, r[1], r[2]-gui.h, r[3], lux.getFloat(), min, max, "", lambda e,v: lux.set(v))
  2311         else:
  2312             w = int((r[2]-gui.h)/3)
  2313             drawX, drawY, drawZ = Draw.Create(vec[0]), Draw.Create(vec[1]), Draw.Create(vec[2])
  2314             drawX = Draw.Number("x:", evtLuxGui, r[0]+gui.h, r[1], w, r[3], drawX.val, min, max, "", lambda e,v: lux.setVector((v,drawY.val,drawZ.val)))
  2315             drawY = Draw.Number("y:", evtLuxGui, r[0]+w+gui.h, r[1], w, r[3], drawY.val, min, max, "", lambda e,v: lux.setVector((drawX.val,v,drawZ.val)))
  2316             drawZ = Draw.Number("z:", evtLuxGui, r[0]+2*w+gui.h, r[1], w, r[3], drawZ.val, min, max, "", lambda e,v: lux.setVector((drawX.val,drawY.val,v)))
  2317     return "\n   \"vector %s\" [%s]"%(name, lux.getVectorStr())
  2318 
  2319 
  2320 # lux individual identifiers
  2321 def luxCamera(cam, context, gui=None):
  2322     global icon_c_camera
  2323     str = ""
  2324     if cam:
  2325         camtype = luxProp(cam, "camera.type", "perspective")
  2326         # Radiance - remarked 'realistic' for v0.6 release
  2327         #str = luxIdentifier("Camera", camtype, ["perspective","orthographic","environment","realistic"], "CAMERA", "select camera type", gui, icon_c_camera)
  2328         str = luxIdentifier("Camera", camtype, ["perspective","orthographic","environment"], "CAMERA", "select camera type", gui, icon_c_camera)
  2329         scale = 1.0
  2330         if camtype.get() == "perspective":
  2331             if gui: gui.newline("  View:")
  2332             str += luxFloat("fov", luxAttr(cam, "angle"), 8.0, 170.0, "fov", "camera field-of-view angle", gui)
  2333             fl = luxAttr(cam, "lens")
  2334             if gui:
  2335                 luxFloat("lens", fl, 1.0, 250.0, "focallength", "camera focal length", gui)
  2336             
  2337         if camtype.get() == "orthographic" :
  2338             str += luxFloat("scale", luxAttr(cam, "scale"), 0.01, 1000.0, "scale", "orthographic camera scale", gui)
  2339             scale = cam.scale / 2
  2340         if camtype.get() == "realistic":
  2341             
  2342             if gui: gui.newline("  View:")
  2343             fov = luxAttr(cam, "angle")
  2344             str += luxFloat("fov", fov, 8.0, 170.0, "fov", "camera field-of-view angle", gui)
  2345             if gui: luxFloat("lens", luxAttr(cam, "lens"), 1.0, 250.0, "focallength", "camera focal length", gui)
  2346             
  2347             
  2348             if gui: gui.newline()
  2349             str += luxFile("specfile", luxProp(cam, "camera.realistic.specfile", ""), "spec-file", "", gui, 1.0)
  2350 #            if gui: gui.newline()
  2351 # auto calc        str += luxFloat("filmdistance", luxProp(cam, "camera.realistic.filmdistance", 70.0), 0.1, 1000.0, "film-dist", "film-distance [mm]", gui)
  2352             filmdiag = luxProp(cam, "camera.realistic.filmdiag", 35.0)
  2353             str += luxFloat("filmdiag", filmdiag, 0.1, 1000.0, "film-diag", "[mm]", gui)
  2354             if gui: gui.newline()
  2355             fstop = luxProp(cam, "camera.realistic.fstop", 1.0)
  2356             luxFloat("aperture_diameter", fstop, 0.1, 100.0, "f-stop", "", gui)
  2357             dofdist = luxAttr(cam, "dofDist")
  2358             luxFloat("focaldistance", dofdist, 0.0, 10000.0, "distance", "Distance from the camera at which objects will be in focus. Has no effect if Lens Radius is 0", gui)
  2359             if gui:
  2360                 Draw.Button("S", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, "focus selected object", lambda e,v:setFocus("S"))
  2361                 Draw.Button("C", evtLuxGui, gui.x+gui.h, gui.y-gui.h, gui.h, gui.h, "focus cursor", lambda e,v:setFocus("C"))
  2362             focal = filmdiag.get()*0.001 / math.tan(fov.get() * math.pi / 360.0) / 2.0
  2363             print("calculated focal length: %f mm"%(focal * 1000.0))
  2364             aperture_diameter = focal / fstop.get()
  2365             print("calculated aperture diameter: %f mm"%(aperture_diameter * 1000.0))
  2366             str += "\n   \"float aperture_diameter\" [%f]"%(aperture_diameter*1000.0)
  2367             filmdistance = dofdist.get() * focal / (dofdist.get() - focal)
  2368             print("calculated film distance: %f mm"%(filmdistance * 1000.0))
  2369             str += "\n   \"float filmdistance\" [%f]"%(filmdistance*1000.0)
  2370 
  2371         # Clipping
  2372         useclip = luxProp(cam, "useclip", "false")
  2373         luxCollapse("useclip", useclip, "Near & Far Clipping", "Enable Camera near and far clipping options", gui, 2.0)
  2374         if(useclip.get() == "true"):
  2375             if gui: gui.newline("  Clipping:")
  2376             str += luxFloat("hither", luxAttr(cam, "clipStart"), 0.0, 100.0, "start", "near clip distance", gui)
  2377             str += luxFloat("yon", luxAttr(cam, "clipEnd"), 1.0, 10000.0, "end", "far clip distance", gui)
  2378 
  2379         # Depth of Field
  2380         usedof = luxProp(cam, "usedof", "false")
  2381         
  2382         if camtype.get() in ["perspective", "orthographic"]:
  2383             luxCollapse("usedof", usedof, "Depth of Field & Bokeh", "Enable Depth of Field & Aperture options", gui, 2.0)
  2384             
  2385             
  2386             if usedof.get() == "true":
  2387                 
  2388                 if gui: gui.newline("  DOF:")
  2389                 
  2390                 lr = luxProp(cam, "camera.lensradius", 0.01)
  2391                 fs = luxProp(cam, "camera.fstop", 2.8)
  2392                 
  2393                 if camtype.get() == "perspective":
  2394                     
  2395                     usefstop = luxProp(cam, "usefstop", "false")
  2396                     luxBool("usefstop", usefstop, "Use f/stop", "Use f/stop to define DOF effect", gui, 1.0)
  2397                     
  2398                     LR_SCALE = 1000.0       # lr in metres -> mm
  2399                     FL_SCALE = 1.0          # fl in mm -> mm
  2400                     
  2401                     def lr_2_fs(fl, lr):
  2402                         lr += 0.00000001
  2403                         return fl / ( 2.0 * lr )
  2404                     
  2405                     def fs_2_lr(fl, fs):
  2406                         return fl / ( 2.0 * fs )
  2407                     
  2408                     if usefstop.get() == 'true':
  2409                         lr.set(fs_2_lr(fl.get() * FL_SCALE, fs.get()) / LR_SCALE)
  2410                         luxFloat("fstop", fs, 0.9, 64.0, "fstop", "Defines the lens aperture.", gui)
  2411                         str += luxFloat("lensradius", lr, 0.0, 1.0, "", "", None)
  2412                     else:
  2413                         fs.set(lr_2_fs(fl.get() * FL_SCALE, lr.get() * LR_SCALE))
  2414                         str += luxFloat("lensradius", lr, 0.0, 1.0, "lens-radius", "Defines the lens radius. Values higher than 0. enable DOF and control the amount", gui)
  2415                 else:
  2416                     str += luxFloat("lensradius", lr, 0.0, 1.0, "lens-radius", "Defines the lens radius. Values higher than 0. enable DOF and control the amount", gui)
  2417                 
  2418                 focustype = luxProp(cam, "camera.focustype", "autofocus")
  2419                 luxOption("focustype", focustype, ["autofocus", "manual", "object"], "Focus Type", "Choose the focus behaviour", gui)
  2420                 
  2421     
  2422                 if focustype.get() == "autofocus":
  2423                     str += luxBool("autofocus",luxProp(cam, "camera.autofocus", "true"), "autofocus", "Enable automatic focus", gui)
  2424                 if focustype.get() == "object":
  2425                     objectfocus = luxProp(cam, "camera.objectfocus", "")
  2426                     luxString("objectfocus", objectfocus, "object", "Always focus camera on named object", gui, 1.0)
  2427                     dofdist = luxAttr(cam, "dofDist")
  2428                     str += luxFloat("focaldistance", dofdist, 0.0, 100.0, "distance", "Distance from the camera at which objects will be in focus. Has no effect if Lens Radius is 0", gui)
  2429                     if objectfocus.get() != "":
  2430                         try:
  2431                             setFocus(objectfocus.get())
  2432                         except:
  2433                             luxProp(cam, "camera.objectfocus", "").set("")
  2434                             Draw.PupMenu("WARNING: focus-object does not match existing object-name")
  2435                             if LuxIsGUI: Draw.Redraw()
  2436                                                                   
  2437                 if focustype.get() == "manual":
  2438                     dofdist = luxAttr(cam, "dofDist")
  2439                     str += luxFloat("focaldistance", dofdist, 0.0, 100.0, "distance", "Distance from the camera at which objects will be in focus. Has no effect if Lens Radius is 0", gui)
  2440                     if gui:
  2441                         Draw.Button("S", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, "focus selected object", lambda e,v:setFocus("S"))
  2442                         Draw.Button("C", evtLuxGui, gui.x+gui.h, gui.y-gui.h, gui.h, gui.h, "focus cursor", lambda e,v:setFocus("C"))
  2443 
  2444         if camtype.get() == "perspective" and usedof.get() == "true":
  2445             str += luxInt("blades", luxProp(cam, "camera.blades", 6), 0, 16, "aperture blades", "Number of blade edges of the aperture, values 0 to 2 defaults to a circle", gui)
  2446             str += luxOption("distribution", luxProp(cam, "camera.distribution", "uniform"), ["uniform", "exponential", "inverse exponential", "gaussian", "inverse gaussian"], "distribution", "Choose the lens sampling distribution. Non-uniform distributions allow for ring effects.", gui)
  2447             str += luxInt("power", luxProp(cam, "camera.power", 1), 0, 512, "power", "Exponent for the expression in exponential distribution. Higher value gives a more pronounced ring effect.", gui)
  2448 
  2449         useaspect = luxProp(cam, "useaspectratio", "false")
  2450         aspectratio = luxProp(cam, "ratio", 1.3333)
  2451         if camtype.get() in ["perspective", "orthographic"]:
  2452             useshift = luxProp(cam, "camera.useshift", "false")
  2453             luxCollapse("useshift", useshift, "Architectural (Lens Shift) & Aspect Ratio", "Enable Lens Shift and Aspect Ratio options", gui, 2.0)
  2454             if(useshift.get() == "true"):
  2455                 if gui: gui.newline("  Shift:")
  2456                 luxFloat("X", luxAttr(cam, "shiftX"), -2.0, 2.0, "X", "horizontal lens shift", gui)
  2457                 luxFloat("Y", luxAttr(cam, "shiftY"), -2.0, 2.0, "Y", "vertical lens shift", gui)
  2458 
  2459                 if gui: gui.newline("  AspectRatio:")
  2460                 luxBool("useaspectratio", useaspect, "Custom", "Define a custom frame aspect ratio", gui)
  2461                 if useaspect.get() == "true":
  2462                     str += luxFloat("frameaspectratio", aspectratio, 0.0001, 3.0, "aspectratio", "Frame aspect ratio", gui)
  2463             if context:
  2464                 if useaspect.get() == "true":
  2465                     ratio = 1./aspectratio.get()
  2466                 else:
  2467                         ratio = float(context.sizeY)/float(context.sizeX)
  2468                 if ratio < 1.0:
  2469                     screenwindow = [(2*cam.shiftX-1)*scale, (2*cam.shiftX+1)*scale, (2*cam.shiftY-ratio)*scale, (2*cam.shiftY+ratio)*scale]
  2470                 else:
  2471                     screenwindow = [(2*cam.shiftX-1/ratio)*scale, (2*cam.shiftX+1/ratio)*scale, (2*cam.shiftY-1)*scale, (2*cam.shiftY+1)*scale]
  2472                 # render region option
  2473                 if context.borderRender:
  2474                     (x1,y1,x2,y2) = context.border
  2475                     screenwindow = [screenwindow[0]*(1-x1)+screenwindow[1]*x1, screenwindow[0]*(1-x2)+screenwindow[1]*x2,\
  2476                             screenwindow[2]*(1-y1)+screenwindow[3]*y1, screenwindow[2]*(1-y2)+screenwindow[3]*y2]
  2477                 str += "\n   \"float screenwindow\" [%f %f %f %f]"%(screenwindow[0], screenwindow[1], screenwindow[2], screenwindow[3])
  2478 
  2479         # Note - radiance - this is a work in progress
  2480         # Flash lamp option for perspective and ortho cams
  2481 #        if camtype.get() in ["perspective", "orthographic"]:
  2482 #            useflash = luxProp(cam, "useflash", "false")
  2483 #            luxBool("useflash", useflash, "Flash Lamp", "Enable Camera mounted flash lamp options", gui, 2.0)
  2484 
  2485         # Motion Blur Options (common to all cameras)
  2486         usemblur = luxProp(cam, "usemblur", "false")
  2487         luxCollapse("usemblur", usemblur, "Motion Blur", "Enable Motion Blur", gui, 2.0)
  2488         if(usemblur.get() == "true"):    
  2489             if gui: gui.newline("  Shutter:")
  2490             mblurpreset = luxProp(cam, "mblurpreset", "true")
  2491             luxBool("mblurpreset", mblurpreset, "Preset", "Enable use of Shutter Presets", gui, 0.4)
  2492             if(mblurpreset.get() == "true"):
  2493                 shutterpresets = ["full frame", "half frame", "quarter frame", "1/25", "1/30", "1/45", "1/60", "1/85", "1/125", "1/250", "1/500"]        
  2494                 shutterpreset = luxProp(cam, "camera.shutterspeedpreset", "full frame")
  2495                 luxOption("shutterpreset", shutterpreset, shutterpresets, "shutterspeed", "Choose the Shutter speed preset.", gui, 1.0)
  2496 
  2497                 fpspresets = ["10 FPS", "12 FPS", "20 FPS", "25 FPS", "29.99 FPS", "30 FPS", "50 FPS", "60 FPS"]
  2498                 shutfps = luxProp(cam, "camera.shutfps", "25 FPS")
  2499                 luxOption("shutfps", shutfps, fpspresets, "@", "Choose the number of frames per second as the time base.", gui, 0.6)
  2500 
  2501                 sfps = shutfps.get()
  2502                 fps = 25
  2503                 if sfps == "10 FPS": fps = 10
  2504                 elif sfps == "12 FPS": fps = 12
  2505                 elif sfps == "20 FPS": fps = 20
  2506                 elif sfps == "25 FPS": fps = 25
  2507                 elif sfps == "29.99 FPS": fps = 29.99
  2508                 elif sfps == "30 FPS": fps = 30
  2509                 elif sfps == "50 FPS": fps = 50
  2510                 elif sfps == "60 FPS": fps = 60
  2511 
  2512                 spre = shutterpreset.get()
  2513                 open = 0.0
  2514                 close = 1.0
  2515                 if spre == "full frame": close = 1.0
  2516                 elif spre == "half frame": close = 0.5
  2517                 elif spre == "quarter frame": close = 0.25
  2518                 elif spre == "1/25": close = 1.0 / 25.0 * fps
  2519                 elif spre == "1/30": close = 1.0 / 30.0 * fps
  2520                 elif spre == "1/45": close = 1.0 / 45.0 * fps
  2521                 elif spre == "1/60": close = 1.0 / 60.0 * fps
  2522                 elif spre == "1/85": close = 1.0 / 85.0 * fps
  2523                 elif spre == "1/125": close = 1.0 / 125.0 * fps
  2524                 elif spre == "1/250": close = 1.0 / 250.0 * fps
  2525                 elif spre == "1/500": close = 1.0 / 500.0 * fps
  2526 
  2527                 str += "\n   \"float shutteropen\" [%f]\n   \"float shutterclose\" [%f] "%(open,close)
  2528 
  2529             else:
  2530                 str += luxFloat("shutteropen", luxProp(cam, "camera.shutteropen", 0.0), 0.0, 100.0, "open", "time in seconds when shutter opens", gui, 0.8)
  2531                 str += luxFloat("shutterclose", luxProp(cam, "camera.shutterclose", 1.0), 0.0, 100.0, "close", "time in seconds when shutter closes", gui, 0.8)
  2532 
  2533             str += luxOption("shutterdistribution", luxProp(cam, "camera.shutterdistribution", "uniform"), ["uniform", "gaussian"], "distribution", "Choose the shutter sampling distribution.", gui, 2.0)
  2534             objectmblur = luxProp(cam, "objectmblur", "true")
  2535             luxBool("objectmblur", objectmblur, "Object", "Enable Motion Blur for scene object motions", gui, 1.0)
  2536             cammblur = luxProp(cam, "cammblur", "true")
  2537             luxBool("cammblur", cammblur, "Camera", "Enable Motion Blur for Camera motion", gui, 1.0)
  2538     return str
  2539 
  2540 
  2541 def get_render_resolution(scn, gui = None):
  2542     context = scn.getRenderingContext()
  2543     scale = luxProp(scn, "film.scale", "100 %")
  2544     scale = int(scale.get()[:-1])
  2545     xr = luxAttr(context, "sizeX").get()*scale/100
  2546     yr = luxAttr(context, "sizeY").get()*scale/100
  2547     
  2548     return xr, yr
  2549 
  2550 def luxFilm(scn, gui=None):
  2551     str = ""
  2552     if scn:
  2553         filmtype = luxProp(scn, "film.type", "fleximage")
  2554         str = luxIdentifier("Film", filmtype, ["fleximage"], "FILM", "select film type", gui)
  2555         if filmtype.get() == "fleximage":
  2556             context = scn.getRenderingContext()
  2557             if context:
  2558                 if gui: gui.newline("  Resolution:")
  2559                 
  2560                 xr,yr = get_render_resolution(scn, gui)
  2561                 
  2562                 luxInt("xresolution", luxAttr(context, "sizeX"), 0, 8192, "X", "width of the render", gui, 0.666)
  2563                 luxInt("yresolution", luxAttr(context, "sizeY"), 0, 8192, "Y", "height of the render", gui, 0.666)
  2564                 scale = luxProp(scn, "film.scale", "100 %")
  2565                 luxOption("", scale, ["400 %", "200 %", "100 %", "75 %", "50 %", "25 %"], "scale", "scale resolution", gui, 0.666)
  2566                 
  2567                 # render region option
  2568                 if context.borderRender:
  2569                     (x1,y1,x2,y2) = context.border
  2570                     if (x1==x2) and (y1==y2): print("WARNING: empty render-region, use SHIFT-B to set render region in Blender.")
  2571                     str += "\n   \"integer xresolution\" [%d] \n   \"integer yresolution\" [%d]"%(xr*(x2-x1), yr*(y2-y1))
  2572                 else:
  2573                     str += "\n   \"integer xresolution\" [%d] \n   \"integer yresolution\" [%d]"%(xr, yr)
  2574 
  2575             if gui: gui.newline("  Halt:")
  2576             str += luxInt("haltspp", luxProp(scn, "haltspp", 0), 0, 32768, "haltspp", "Stop rendering after specified amount of samples per pixel / 0 = never halt", gui)
  2577             palpha = luxProp(scn, "film.premultiplyalpha", "false")
  2578             str += luxBool("premultiplyalpha", palpha, "premultiplyalpha", "Pre multiply film alpha channel during normalization", gui)
  2579     
  2580             if gui: gui.newline("  Tonemap:")
  2581             tonemapkernel =    luxProp(scn, "film.tonemapkernel", "reinhard")
  2582             str += luxOption("tonemapkernel", tonemapkernel, ["reinhard", "linear", "contrast", "maxwhite"], "Tonemapping Kernel", "Select the tonemapping kernel to use", gui, 2.0)
  2583             if tonemapkernel.get() == "reinhard":
  2584                 autoywa = luxProp(scn, "film.reinhard.autoywa", "true")
  2585                 #str += luxBool("reinhard_autoywa", autoywa, "auto Ywa", "Automatically determine World Adaption Luminance", gui)
  2586                 if autoywa.get() == "false":
  2587                     str += luxFloat("reinhard_ywa", luxProp(scn, "film.reinhard.ywa", 0.1), 0.001, 1.0, "Ywa", "Display/World Adaption Luminance", gui)
  2588                 str += luxFloat("reinhard_prescale", luxProp(scn, "film.reinhard.prescale", 1.0), 0.0, 10.0, "preScale", "Image scale before tonemap operator", gui)
  2589                 str += luxFloat("reinhard_postscale", luxProp(scn, "film.reinhard.postscale", 1.2), 0.0, 10.0, "postScale", "Image scale after tonemap operator", gui)
  2590                 str += luxFloat("reinhard_burn", luxProp(scn, "film.reinhard.burn", 6.0), 0.1, 12.0, "burn", "12.0: no burn out, 0.1 lot of burn out", gui)
  2591             elif tonemapkernel.get() == "linear":
  2592                 str += luxFloat("linear_sensitivity", luxProp(scn, "film.linear.sensitivity", 50.0), 0.0, 1000.0, "sensitivity", "Adaption/Sensitivity", gui)
  2593                 str += luxFloat("linear_exposure", luxProp(scn, "film.linear.exposure", 1.0), 0.001, 1.0, "exposure", "Exposure duration in seconds", gui)
  2594                 str += luxFloat("linear_fstop", luxProp(scn, "film.linear.fstop", 2.8), 0.1, 64.0, "Fstop", "F-Stop", gui)
  2595                 str += luxFloat("linear_gamma", luxProp(scn, "film.linear.gamma", 1.0), 0.0, 8.0, "gamma", "Tonemap operator gamma correction", gui)
  2596             elif tonemapkernel.get() == "contrast":
  2597                 str += luxFloat("contrast_ywa", luxProp(scn, "film.contrast.ywa", 0.1), 0.001, 1.0, "Ywa", "Display/World Adaption Luminance", gui)
  2598 
  2599             if gui: gui.newline("  Display:")
  2600             str += luxInt("displayinterval", luxProp(scn, "film.displayinterval", 12), 4, 3600, "interval", "Set display Interval (seconds)", gui)
  2601             
  2602             if gui: gui.newline("  Write:")
  2603             str += luxInt("writeinterval", luxProp(scn, "film.writeinterval", 120), 12, 3600, "interval", "Set display Interval (seconds)", gui)
  2604 
  2605         # Image File Outputs
  2606 
  2607         # LDR clamping method
  2608         if gui: gui.newline("  Clamping:")
  2609         ldrclampmethod = luxProp(scn, "film.ldr_clamp_method", "lum")
  2610         str += luxOption("ldr_clamp_method", ldrclampmethod, ["lum", "hue", "cut"], "LDR clamping", "Method to clamp high luminance values for LDR output", gui, 0.5)
  2611         if gui: gui.newline()
  2612 
  2613         # OpenEXR Output
  2614         saveexr = luxProp(scn, "film.write_exr", "false")
  2615         str += luxCollapse("write_exr", saveexr, "OpenEXR Output", "Enable OpenEXR output", gui, 2.0)
  2616 
  2617         if saveexr.get() == "true":
  2618             if gui: gui.newline("  OpenEXR:")
  2619 
  2620             exrchannels = luxProp(scn, "film.write_exr_channels", "RGBA")
  2621             str += luxOption("write_exr_channels", exrchannels, ["Y", "YA", "RGB", "RGBA"], "Channels", "Select channels type to write", gui, 0.5)
  2622             exrres = luxProp(scn, "film.write_exr_halftype", "true")
  2623             str += luxBool("write_exr_halftype", exrres, "16bit Half", "Enable 16bit Half resolution output, otherwise 32bit float", gui, 0.5)
  2624             exrcompression = luxProp(scn, "film.write_exr_compression", "PIZ (lossless)")
  2625             str += luxOption("write_exr_compressiontype", exrcompression, ["RLE (lossless)", "PIZ (lossless)", "ZIP (lossless)", "Pxr24 (lossy)", "None"], "Compression", "Select OpenEXR Compression algorithm to use", gui, 1.0)
  2626 
  2627             exrimaging = luxProp(scn, "film.write_exr_imaging", "true")
  2628             str += luxBool("write_exr_applyimaging", exrimaging, "Apply Imaging/Tonemapping", "Apply Imaging and Tonemapping pipeline", gui, 1.2)
  2629         
  2630             if exrimaging.get()=="true":
  2631                 exrgamutclamp = luxProp(scn, "film.write_exr_gamutclamp", "true")
  2632                 str += luxBool("write_exr_gamutclamp", exrgamutclamp, "Gamut Clamp", "Clamp out of gamut (bright) pixel values", gui, 0.8)
  2633 
  2634             if gui: gui.newline()
  2635             # Zbuf output
  2636             exrZ = luxProp(scn, "film.write_exr_Z", "true")
  2637             str += luxBool("write_exr_ZBuf", exrZ, "ZBuf", "Enable Z Depth Buffer channel", gui, 0.8)
  2638             if exrZ.get() == "true":
  2639                 exrZNormalize = luxProp(scn, "film.write_exr_ZNorm", "None")
  2640                 str += luxOption("write_exr_zbuf_normalizationtype", exrZNormalize, ["Camera Start/End clip", "Min/Max", "None"], "ZBuf Normalization", "Select type of normalization to use for Zbuf Depth Map", gui, 1.2)
  2641 
  2642         # PNG Output
  2643         savepng = luxProp(scn, "film.write_png", "true")
  2644         str += luxCollapse("write_png", savepng, "PNG Output", "Enable PNG (Portable Network Graphics) output", gui, 2.0)
  2645 
  2646         if savepng.get() == "true":
  2647             if gui: gui.newline("  PNG:")
  2648             pngchannels = luxProp(scn, "film.write_png_channels", "RGB")
  2649             str += luxOption("write_png_channels", pngchannels, ["Y", "YA", "RGB", "RGBA"], "Channels", "Select channels type to write", gui, 0.5)
  2650             png16bit = luxProp(scn, "film.write_png_16bit", "false")
  2651             str += luxBool("write_png_16bit", png16bit, "16bit", "Enable 16bits per channel resolution PNG output", gui, 0.5)
  2652             pnggamutclamp = luxProp(scn, "film.write_png_gamutclamp", "true")
  2653             str += luxBool("write_png_gamutclamp", pnggamutclamp, "Gamut Clamp", "Clamp out of gamut (bright) pixel values", gui, 1.0)
  2654 
  2655         # Zbuf output
  2656         #pngZ = luxProp(scn, "film.write_png_ZBuf", "false")
  2657         #str += luxBool("write_png_ZBuf", pngZ, "ZBuf (Separate)", "Enable Z Depth Buffer channel", gui, 0.8)
  2658         #if pngZ.get() == "true":
  2659         #    pngZNormalize = luxProp(scn, "film.write_png_ZNorm", "Min/Max")
  2660         #    str += luxOption("write_png_zbuf_normalizationtype", pngZNormalize, ["Camera Start/End clip", "Min/Max", "None"], "ZBuf Normalization", "Select type of normalization to use for Zbuf Depth Map", gui, 1.2)
  2661 
  2662         # TGA Output
  2663         savetga = luxProp(scn, "film.write_tga", "false")
  2664         str += luxCollapse("write_tga", savetga, "TGA Output", "Enable TGA output", gui, 2.0)
  2665 
  2666         if savetga.get() == "true":
  2667             if gui: gui.newline("  TGA:")
  2668             tgachannels = luxProp(scn, "film.write_tga_channels", "RGB")
  2669             str += luxOption("write_tga_channels", tgachannels, ["Y", "RGB", "RGBA"], "Channels", "Select channels type to write", gui, 0.5)
  2670             tgagamutclamp = luxProp(scn, "film.write_tga_gamutclamp", "true")
  2671             str += luxBool("write_tga_gamutclamp", tgagamutclamp, "Gamut Clamp", "Clamp out of gamut (bright) pixel values", gui, 1.5)
  2672 
  2673         # Zbuf output
  2674         #tgaZ = luxProp(scn, "film.write_tga_ZBuf", "false")
  2675         #str += luxBool("write_tga_ZBuf", tgaZ, "ZBuf (Separate)", "Enable Z Depth Buffer channel", gui, 0.8)
  2676         #if tgaZ.get() == "true":
  2677         #    tgaZNormalize = luxProp(scn, "film.write_tga_ZNorm", "Min/Max")
  2678         #    str += luxOption("write_tga_zbuf_normalizationtype", tgaZNormalize, ["Camera Start/End clip", "Min/Max", "None"], "ZBuf Normalization", "Select type of normalization to use for Zbuf Depth Map", gui, 1.2)
  2679 
  2680 
  2681         # override output image dir in case of command line batch mode 
  2682         overrideop = luxProp(scn, "overrideoutputpath", "")
  2683         if overrideop.get() != "":
  2684             filebase = os.path.splitext(os.path.basename(Blender.Get('filename')))[0]
  2685             filename = overrideop.get() + "/" + filebase + "-%05d" %  (Blender.Get('curframe'))
  2686             str += "\n   \"string filename\" [\"%s\"]"%(filename)
  2687         else:
  2688             fn = luxProp(scn, "filename", "default-%05d" %  (Blender.Get('curframe')))
  2689             str += luxString("filename", fn, "File name", "save file name", None)
  2690     
  2691         if gui: gui.newline("  Resume:")
  2692         resumeflm = luxProp(scn, "film.write_resume_flm", "false")
  2693         str += luxBool("write_resume_flm", resumeflm, "Write/Use FLM", "Write a resume fleximage .flm file, or resume rendering if it already exists", gui)
  2694         restartflm = luxProp(scn, "film.restart_resume_flm", "true")
  2695         str += luxBool("restart_resume_flm", restartflm, "Restart/Erase", "Restart with a black flm, even it a previous flm exists", gui)
  2696         if gui: gui.newline("  Reject:")
  2697         str += luxInt("reject_warmup", luxProp(scn, "film.reject_warmup", 128), 0, 32768, "warmup_spp", "Specify amount of samples per pixel for high intensity rejection", gui)
  2698         debugmode = luxProp(scn, "film.debug", "false")
  2699         str += luxBool("debug", debugmode, "debug", "Turn on debug reporting and switch off reject", gui)
  2700     
  2701         # Colorspace
  2702         if gui: gui.newline("  Colorspace:")
  2703     
  2704         cspaceusepreset = luxProp(scn, "film.colorspaceusepreset", "true")
  2705         luxBool("colorspaceusepreset", cspaceusepreset, "Preset", "Select from a list of predefined presets", gui, 0.4)
  2706     
  2707         # Default values for 'sRGB - HDTV (ITU-R BT.709-5)'
  2708         cspacewhiteX = luxProp(scn, "film.cspacewhiteX", 0.314275)
  2709         cspacewhiteY = luxProp(scn, "film.cspacewhiteY", 0.329411)
  2710         cspaceredX = luxProp(scn, "film.cspaceredX", 0.63)
  2711         cspaceredY = luxProp(scn, "film.cspaceredY", 0.34)
  2712         cspacegreenX = luxProp(scn, "film.cspacegreenX", 0.31)
  2713         cspacegreenY = luxProp(scn, "film.cspacegreenY", 0.595)
  2714         cspaceblueX = luxProp(scn, "film.cspaceblueX", 0.155)
  2715         cspaceblueY = luxProp(scn, "film.cspaceblueY", 0.07)
  2716         gamma = luxProp(scn, "film.gamma", 2.2)
  2717     
  2718         if(cspaceusepreset.get() == "true"):
  2719             # preset controls
  2720             cspace = luxProp(scn, "film.colorspace", "sRGB - HDTV (ITU-R BT.709-5)")
  2721             cspaces = ["sRGB - HDTV (ITU-R BT.709-5)", "ROMM RGB", "Adobe RGB 98", "Apple RGB", "NTSC (FCC 1953, ITU-R BT.470-2 System M)", "NTSC (1979) (SMPTE C, SMPTE-RP 145)", "PAL/SECAM (EBU 3213, ITU-R BT.470-6)", "CIE (1931) E"]
  2722             luxOption("colorspace", cspace, cspaces, "Colorspace", "select output working colorspace", gui, 1.6)
  2723     
  2724             if cspace.get()=="ROMM RGB":
  2725                 cspacewhiteX.set(0.346); cspacewhiteY.set(0.359) # D50
  2726                 cspaceredX.set(0.7347); cspaceredY.set(0.2653)
  2727                 cspacegreenX.set(0.1596); cspacegreenY.set(0.8404)
  2728                 cspaceblueX.set(0.0366); cspaceblueY.set(0.0001)
  2729             elif cspace.get()=="Adobe RGB 98":
  2730                 cspacewhiteX.set(0.313); cspacewhiteY.set(0.329) # D65
  2731                 cspaceredX.set(0.64); cspaceredY.set(0.34)
  2732                 cspacegreenX.set(0.21); cspacegreenY.set(0.71)
  2733                 cspaceblueX.set(0.15); cspaceblueY.set(0.06)
  2734             elif cspace.get()=="Apple RGB":
  2735                 cspacewhiteX.set(0.313); cspacewhiteY.set(0.329) # D65
  2736                 cspaceredX.set(0.625); cspaceredY.set(0.34)
  2737                 cspacegreenX.set(0.28); cspacegreenY.set(0.595)
  2738                 cspaceblueX.set(0.155); cspaceblueY.set(0.07)
  2739             elif cspace.get()=="NTSC (FCC 1953, ITU-R BT.470-2 System M)":
  2740                 cspacewhiteX.set(0.310); cspacewhiteY.set(0.316) # C
  2741                 cspaceredX.set(0.67); cspaceredY.set(0.33)
  2742                 cspacegreenX.set(0.21); cspacegreenY.set(0.71)
  2743                 cspaceblueX.set(0.14); cspaceblueY.set(0.08)
  2744             elif cspace.get()=="NTSC (1979) (SMPTE C, SMPTE-RP 145)":
  2745                 cspacewhiteX.set(0.313); cspacewhiteY.set(0.329) # D65
  2746                 cspaceredX.set(0.63); cspaceredY.set(0.34)
  2747                 cspacegreenX.set(0.31); cspacegreenY.set(0.595)
  2748                 cspaceblueX.set(0.155); cspaceblueY.set(0.07)
  2749             elif cspace.get()=="PAL/SECAM (EBU 3213, ITU-R BT.470-6)":
  2750                 cspacewhiteX.set(0.313); cspacewhiteY.set(0.329) # D65
  2751                 cspaceredX.set(0.64); cspaceredY.set(0.33)
  2752                 cspacegreenX.set(0.29); cspacegreenY.set(0.60)
  2753                 cspaceblueX.set(0.15); cspaceblueY.set(0.06)
  2754             elif cspace.get()=="CIE (1931) E":
  2755                 cspacewhiteX.set(0.333); cspacewhiteY.set(0.333) # E
  2756                 cspaceredX.set(0.7347); cspaceredY.set(0.2653)
  2757                 cspacegreenX.set(0.2738); cspacegreenY.set(0.7174)
  2758                 cspaceblueX.set(0.1666); cspaceblueY.set(0.0089)
  2759     
  2760             whitepointusecspace = luxProp(scn, "film.whitepointusecolorspace", "true")
  2761             luxBool("whitepointusecolorspace", whitepointusecspace, "Colorspace Whitepoint", "Use default whitepoint for selected colorspace", gui, 1.0)
  2762             gammausecspace = luxProp(scn, "film.gammausecolorspace", "true")
  2763             luxBool("gammausecolorspace", gammausecspace, "Colorspace Gamma", "Use default output gamma for selected colorspace", gui, 1.0)
  2764     
  2765             if(whitepointusecspace.get() == "false"):
  2766                 if gui: gui.newline("  Whitepoint:")
  2767                 whitepointusepreset = luxProp(scn, "film.whitepointusepreset", "true")
  2768                 luxBool("whitepointusepreset", whitepointusepreset, "Preset", "Select from a list of predefined presets", gui, 0.4)
  2769     
  2770                 if(whitepointusepreset.get() == "true"):
  2771                     whitepointpresets = ["E", "D50", "D55", "D65", "D75", "A", "B", "C", "9300", "F2", "F7", "F11"]
  2772                     whitepointpreset = luxProp(scn, "film.whitepointpreset", "D65")
  2773                     luxOption("whitepointpreset", whitepointpreset, whitepointpresets, "  PRESET", "select Whitepoint preset", gui, 1.6)
  2774     
  2775                     if whitepointpreset.get()=="E": cspacewhiteX.set(0.333); cspacewhiteY.set(0.333)
  2776                     elif whitepointpreset.get()=="D50": cspacewhiteX.set(0.346); cspacewhiteY.set(0.359)
  2777                     elif whitepointpreset.get()=="D55": cspacewhiteX.set(0.332); cspacewhiteY.set(0.347)
  2778                     elif whitepointpreset.get()=="D65": cspacewhiteX.set(0.313); cspacewhiteY.set(0.329)
  2779                     elif whitepointpreset.get()=="D75": cspacewhiteX.set(0.299); cspacewhiteY.set(0.315)
  2780                     elif whitepointpreset.get()=="A": cspacewhiteX.set(0.448); cspacewhiteY.set(0.407)
  2781                     elif whitepointpreset.get()=="B": cspacewhiteX.set(0.348); cspacewhiteY.set(0.352)
  2782                     elif whitepointpreset.get()=="C": cspacewhiteX.set(0.310); cspacewhiteY.set(0.316)
  2783                     elif whitepointpreset.get()=="9300": cspacewhiteX.set(0.285); cspacewhiteY.set(0.293)
  2784                     elif whitepointpreset.get()=="F2": cspacewhiteX.set(0.372); cspacewhiteY.set(0.375)
  2785                     elif whitepointpreset.get()=="F7": cspacewhiteX.set(0.313); cspacewhiteY.set(0.329)
  2786                     elif whitepointpreset.get()=="F11": cspacewhiteX.set(0.381); cspacewhiteY.set(0.377)
  2787                 else:
  2788                     luxFloat("white X", cspacewhiteX, 0.0, 1.0, "white X", "Whitepoint X weight", gui, 0.8)
  2789                     luxFloat("white Y", cspacewhiteY, 0.0, 1.0, "white Y", "Whitepoint Y weight", gui, 0.8)
  2790     
  2791             if(gammausecspace.get() == "false"):
  2792                 if gui: gui.newline("  Gamma:")
  2793                 luxFloat("gamma", gamma, 0.1, 6.0, "gamma", "Output and RGC Gamma", gui, 2.0)
  2794         else:
  2795             # manual controls
  2796             luxFloat("white X", cspacewhiteX, 0.0, 1.0, "white X", "Whitepoint X weight", gui, 0.8)
  2797             luxFloat("white Y", cspacewhiteY, 0.0, 1.0, "white Y", "Whitepoint Y weight", gui, 0.8)
  2798             luxFloat("red X", cspaceredX, 0.0, 1.0, "red X", "Red component X weight", gui, 1.0)
  2799             luxFloat("red Y", cspaceredY, 0.0, 1.0, "red Y", "Red component Y weight", gui, 1.0)
  2800             luxFloat("green X", cspacegreenX, 0.0, 1.0, "green X", "Green component X weight", gui, 1.0)
  2801             luxFloat("green Y", cspacegreenY, 0.0, 1.0, "green Y", "Green component Y weight", gui, 1.0)
  2802             luxFloat("blue X", cspaceblueX, 0.0, 1.0, "blue X", "Blue component X weight", gui, 1.0)
  2803             luxFloat("blue Y", cspaceblueY, 0.0, 1.0, "blue Y", "Blue component Y weight", gui, 1.0)
  2804             if gui: gui.newline("  Gamma:")
  2805             luxFloat("gamma", gamma, 0.1, 6.0, "gamma", "Output and RGC Gamma", gui, 2.0)
  2806             
  2807         str += "\n   \"float colorspace_white\" [%f %f]"%(cspacewhiteX.get(), cspacewhiteY.get())
  2808         str += "\n   \"float colorspace_red\" [%f %f]"%(cspaceredX.get(), cspaceredY.get())
  2809         str += "\n   \"float colorspace_green\" [%f %f]"%(cspacegreenX.get(), cspacegreenY.get())
  2810         str += "\n   \"float colorspace_blue\" [%f %f]"%(cspaceblueX.get(), cspaceblueY.get())
  2811         str += "\n   \"float gamma\" [%f]"%(gamma.get())
  2812 
  2813     return str
  2814 
  2815 
  2816 def luxPixelFilter(scn, gui=None):
  2817     global icon_c_filter
  2818     str = ""
  2819     if scn:
  2820         filtertype = luxProp(scn, "pixelfilter.type", "mitchell")
  2821         str = luxIdentifier("PixelFilter", filtertype, ["box", "gaussian", "mitchell", "sinc", "triangle"], "FILTER", "select pixel filter type", gui, icon_c_filter)
  2822 
  2823         # Advanced toggle
  2824         parammodeadvanced = luxProp(scn, "parammodeadvanced", "false")
  2825         showadvanced = luxProp(scn, "pixelfilter.showadvanced", parammodeadvanced.get())
  2826         luxBool("advanced", showadvanced, "Advanced", "Show advanced options", gui, 0.6)
  2827         # Help toggle
  2828         showhelp = luxProp(scn, "pixelfilter.showhelp", "false")
  2829         luxHelp("help", showhelp, "Help", "Show Help Information", gui, 0.4)
  2830 
  2831         if filtertype.get() == "box":
  2832             if showadvanced.get()=="true":
  2833                 # Advanced parameters
  2834                 if gui: gui.newline()
  2835                 str += luxFloat("xwidth", luxProp(scn, "pixelfilter.box.xwidth", 0.5), 0.0, 10.0, "x-width", "Width of the filter in the x direction", gui)
  2836                 str += luxFloat("ywidth", luxProp(scn, "pixelfilter.box.ywidth", 0.5), 0.0, 10.0, "y-width", "Width of the filter in the y direction", gui)
  2837         if filtertype.get() == "gaussian":
  2838             if showadvanced.get()=="true":
  2839                 # Advanced parameters
  2840                 if gui: gui.newline()
  2841                 str += luxFloat("xwidth", luxProp(scn, "pixelfilter.gaussian.xwidth", 2.0), 0.0, 10.0, "x-width", "Width of the filter in the x direction", gui)
  2842                 str += luxFloat("ywidth", luxProp(scn, "pixelfilter.gaussian.ywidth", 2.0), 0.0, 10.0, "y-width", "Width of the filter in the y direction", gui)
  2843                 if gui: gui.newline()
  2844                 str += luxFloat("alpha", luxProp(scn, "pixelfilter.gaussian.alpha", 2.0), 0.0, 10.0, "alpha", "Gaussian rate of falloff. Lower values give blurrier images", gui)
  2845         if filtertype.get() == "mitchell":
  2846             if showadvanced.get()=="false":
  2847                 # Default parameters
  2848                 if gui: gui.newline("", 8, 0, None, [0.4,0.4,0.4])
  2849                 slidval = luxProp(scn, "pixelfilter.mitchell.sharp", 0.25)
  2850                 luxFloat("sharpness", slidval, 0.0, 1.0, "sharpness", "Specify amount between blurred (left) and sharp/ringed (right)", gui, 2.0, 1)
  2851                 # rule: B + 2*c = 1.0
  2852                 C = slidval.getFloat() * 0.5
  2853                 B = 1.0 - slidval.getFloat()
  2854                 str += "\n   \"float B\" [%f]"%(B)
  2855                 str += "\n   \"float C\" [%f]"%(C)
  2856 
  2857             if showadvanced.get()=="true":
  2858                 # Advanced parameters
  2859                 if gui: gui.newline()
  2860                 str += luxFloat("xwidth", luxProp(scn, "pixelfilter.mitchell.xwidth", 2.0), 0.0, 10.0, "x-width", "Width of the filter in the x direction", gui)
  2861                 str += luxFloat("ywidth", luxProp(scn, "pixelfilter.mitchell.ywidth", 2.0), 0.0, 10.0, "y-width", "Width of the filter in the y direction", gui)
  2862                 if gui: gui.newline()
  2863     
  2864                 optmode = luxProp(scn, "pixelfilter.mitchell.optmode", "slider")
  2865                 luxOption("optmode", optmode, ["slider", "preset", "manual"], "Mode", "Mode of configuration", gui, 0.5)
  2866     
  2867                 if(optmode.get() == "slider"):
  2868                     slidval = luxProp(scn, "pixelfilter.mitchell.sharp", 0.33)
  2869                     luxFloat("sharpness", slidval, 0.0, 1.0, "sharpness", "Specify amount between blurred (left) and sharp/ringed (right)", gui, 1.5, 1)
  2870                     # rule: B + 2*c = 1.0
  2871                     C = slidval.getFloat() * 0.5
  2872                     B = 1.0 - slidval.getFloat()
  2873                     str += "\n   \"float B\" [%f]"%(B)
  2874                     str += "\n   \"float C\" [%f]"%(C)
  2875                 elif(optmode.get() == "preset"):
  2876                     print("not implemented")
  2877                 else:
  2878                     str += luxFloat("B", luxProp(scn, "pixelfilter.mitchell.B", 0.3333), 0.0, 1.0, "B", "Specify the shape of the Mitchell filter. Often best result is when B + 2C = 1", gui, 0.75)
  2879                     str += luxFloat("C", luxProp(scn, "pixelfilter.mitchell.C", 0.3333), 0.0, 1.0, "C", "Specify the shape of the Mitchell filter. Often best result is when B + 2C = 1", gui, 0.75)
  2880 
  2881         if filtertype.get() == "sinc":
  2882             if showadvanced.get()=="true":
  2883                 # Advanced parameters
  2884                 if gui: gui.newline()
  2885                 str += luxFloat("xwidth", luxProp(scn, "pixelfilter.sinc.xwidth", 4.0), 0.0, 10.0, "x-width", "Width of the filter in the x direction", gui)
  2886                 str += luxFloat("ywidth", luxProp(scn, "pixelfilter.sinc.ywidth", 4.0), 0.0, 10.0, "y-width", "Width of the filter in the y direction", gui)
  2887                 if gui: gui.newline()
  2888                 str += luxFloat("tau", luxProp(scn, "pixelfilter.sinc.tau", 3.0), 0.0, 10.0, "tau", "Permitted number of cycles of the sinc function before it is clamped to zero", gui)
  2889         if filtertype.get() == "triangle":
  2890             if showadvanced.get()=="true":
  2891                 # Advanced parameters
  2892                 if gui: gui.newline()
  2893                 str += luxFloat("xwidth", luxProp(scn, "pixelfilter.triangle.xwidth", 2.0), 0.0, 10.0, "x-width", "Width of the filter in the x direction", gui)
  2894                 str += luxFloat("ywidth", luxProp(scn, "pixelfilter.triangle.ywidth", 2.0), 0.0, 10.0, "y-width", "Width of the filter in the y direction", gui)
  2895     return str            
  2896 
  2897 def luxSampler(scn, gui=None):
  2898     global icon_c_sampler, icon_help
  2899     str = ""
  2900     if scn:
  2901         samplertype = luxProp(scn, "sampler.type", "metropolis")
  2902         str = luxIdentifier("Sampler", samplertype, ["metropolis", "erpt", "lowdiscrepancy", "random"], "SAMPLER", "select sampler type", gui, icon_c_sampler)
  2903 
  2904         # Advanced toggle
  2905         parammodeadvanced = luxProp(scn, "parammodeadvanced", "false")
  2906         showadvanced = luxProp(scn, "sampler.showadvanced", parammodeadvanced.get())
  2907         luxBool("advanced", showadvanced, "Advanced", "Show advanced options", gui, 0.6)
  2908         # Help toggle
  2909         showhelp = luxProp(scn, "sampler.showhelp", "false")
  2910         luxHelp("help", showhelp, "Help", "Show Help Information", gui, 0.4)
  2911 
  2912         if samplertype.get() == "metropolis":
  2913             if showadvanced.get()=="false":
  2914                 # Default parameters
  2915                 if gui: gui.newline("  Mutation:", 8, 0, None, [0.4,0.4,0.4])
  2916                 strength = luxProp(scn, "sampler.metro.strength", 0.6)
  2917                 luxFloat("strength", strength, 0.0, 1.0, "strength", "Mutation Strength (lmprob = 1.0-strength)", gui, 2.0, 1)
  2918                 v = 1.0 - strength.get()
  2919                 str += "\n   \"float largemutationprob\" [%f]"%v
  2920             if showadvanced.get()=="true":
  2921                 # Advanced parameters
  2922                 if gui: gui.newline("  Mutation:")
  2923                 str += luxFloat("largemutationprob", luxProp(scn, "sampler.metro.lmprob", 0.4), 0.0, 1.0, "LM.prob.", "Probability of generating a large sample (mutation)", gui)
  2924                 str += luxInt("maxconsecrejects", luxProp(scn, "sampler.metro.maxrejects", 512), 0, 32768, "max.rejects", "number of consecutive rejects before a new mutation is forced", gui)
  2925                 if gui: gui.newline("  Screen:")
  2926                 #str += luxInt("initsamples", luxProp(scn, "sampler.metro.initsamples", 262144), 1, 1000000, "initsamples", "", gui)
  2927                 str += luxBool("usevariance",luxProp(scn, "sampler.metro.usevariance", "false"), "usevariance", "Accept based on variance", gui, 1.0)
  2928 
  2929             if showhelp.get()=="true":
  2930                 if gui: gui.newline("  Description:", 8, 0, icon_help, [0.4,0.5,0.56])
  2931                 r = gui.getRect(2,1); BGL.glRasterPos2i(r[0],r[1]+5) 
  2932                 Draw.Text("A Metropolis-Hastings mutating sampler which implements MLT", 'small')    
  2933 
  2934         if samplertype.get() == "erpt":
  2935             #str += luxInt("initsamples", luxProp(scn, "sampler.erpt.initsamples", 100000), 1, 1000000, "initsamples", "", gui)
  2936             if gui: gui.newline("  Mutation:")
  2937             str += luxInt("chainlength", luxProp(scn, "sampler.erpt.chainlength", 512), 1, 32768, "chainlength", "The number of mutations from a given seed", gui)
  2938             if gui: gui.newline()
  2939             str += luxInt("stratawidth", luxProp(scn, "sampler.erpt.stratawidth", 256), 1, 32768, "stratawidth", "The number of x/y strata for stratified sampling of seeds", gui)
  2940 
  2941         if samplertype.get() == "lowdiscrepancy":
  2942             if gui: gui.newline("  PixelSampler:")
  2943             str += luxOption("pixelsampler", luxProp(scn, "sampler.lowdisc.pixelsampler", "lowdiscrepancy"), ["linear", "tile", "random", "vegas","lowdiscrepancy","hilbert"], "pixel-sampler", "select pixel-sampler", gui)
  2944             str += luxInt("pixelsamples", luxProp(scn, "sampler.lowdisc.pixelsamples", 4), 1, 2048, "samples", "Average number of samples taken per pixel. More samples create a higher quality image at the cost of render time", gui)
  2945 
  2946         if samplertype.get() == "random":
  2947             if gui: gui.newline("  PixelSampler:")
  2948             str += luxOption("pixelsampler", luxProp(scn, "sampler.random.pixelsampler", "vegas"), ["linear", "tile", "random", "vegas","lowdiscrepancy","hilbert"], "pixel-sampler", "select pixel-sampler", gui)
  2949             if gui: gui.newline()
  2950             str += luxInt("pixelsamples", luxProp(scn, "sampler.random.pixelsamples", 4), 1, 512, "pixelsamples", "Allows you to specify how many samples per pixel are computed", gui)
  2951     return str            
  2952 
  2953 def luxSurfaceIntegrator(scn, gui=None):
  2954     global icon_c_integrator
  2955     str = ""
  2956     if scn:
  2957         integratortype = luxProp(scn, "sintegrator.type", "bidirectional")
  2958         
  2959         str = luxIdentifier("SurfaceIntegrator", integratortype, ["directlighting", "path", "bidirectional", "exphotonmap", "distributedpath", "igi" ], "INTEGRATOR", "select surface integrator type", gui, icon_c_integrator)
  2960 
  2961         # Advanced toggle
  2962         parammodeadvanced = luxProp(scn, "parammodeadvanced", "false")
  2963         showadvanced = luxProp(scn, "sintegrator.showadvanced", parammodeadvanced.get())
  2964         luxBool("advanced", showadvanced, "Advanced", "Show advanced options", gui, 0.6)
  2965         # Help toggle
  2966         showhelp = luxProp(scn, "sintegrator.showhelp", "false")
  2967         luxHelp("help", showhelp, "Help", "Show Help Information", gui, 0.4)
  2968 
  2969         if integratortype.get() == "directlighting":
  2970             if showadvanced.get()=="false":
  2971                 # Default parameters
  2972                 if gui: gui.newline("  Depth:", 8, 0, None, [0.4,0.4,0.4])
  2973                 str += luxInt("maxdepth", luxProp(scn, "sintegrator.dlighting.maxdepth", 8), 0, 2048, "bounces", "The maximum recursion depth for ray casting", gui, 2.0)
  2974 
  2975             if showadvanced.get()=="true":
  2976                 # Advanced parameters
  2977                 str += luxOption("strategy", luxProp(scn, "sintegrator.dlighting.strategy", "auto"), ["one", "all", "auto"], "strategy", "select directlighting strategy", gui)
  2978                 if gui: gui.newline("  Depth:")
  2979                 str += luxInt("maxdepth", luxProp(scn, "sintegrator.dlighting.maxdepth", 8), 0, 2048, "max-depth", "The maximum recursion depth for ray casting", gui)
  2980                 if gui: gui.newline()
  2981 
  2982         if integratortype.get() == "path":
  2983             if showadvanced.get()=="false":
  2984                 # Default parameters
  2985                 if gui: gui.newline("  Depth:", 8, 0, None, [0.4,0.4,0.4])
  2986                 str += luxInt("maxdepth", luxProp(scn, "sintegrator.path.maxdepth", 10), 0, 2048, "bounces", "The maximum recursion depth for ray casting", gui, 1.0)
  2987                 ienv = luxProp(scn, "sintegrator.path.ienvironment", "true")
  2988                 str += luxBool("includeenvironment", ienv, "Include Environment", "Enable/Disable rendering of environment lightsources", gui)
  2989 
  2990             if showadvanced.get()=="true":
  2991                 # Advanced parameters
  2992                 if gui: gui.newline("  Depth:")
  2993                 str += luxInt("maxdepth", luxProp(scn, "sintegrator.path.maxdepth", 10), 0, 2048, "maxdepth", "The maximum recursion depth for ray casting", gui)
  2994                 str += luxOption("strategy", luxProp(scn, "sintegrator.path.strategy", "auto"), ["one", "all", "auto"], "strategy", "select directlighting strategy", gui)
  2995                 if gui: gui.newline("  RR:")
  2996                 rrstrat = luxProp(scn, "sintegrator.path.rrstrategy", "efficiency")
  2997                 str += luxOption("rrstrategy", rrstrat, ["efficiency", "probability", "none"], "RR strategy", "select Russian Roulette path termination strategy", gui)
  2998                 if rrstrat.get() == "probability":
  2999                     str += luxFloat("rrcontinueprob", luxProp(scn, "sintegrator.path.rrcontinueprob", 0.65), 0.0, 1.0, "rrprob", "Russian roulette continue probability", gui)
  3000                 ienv = luxProp(scn, "sintegrator.path.ienvironment", "true")
  3001                 str += luxBool("includeenvironment", ienv, "Include Environment", "Enable/Disable rendering of environment lightsources", gui)
  3002 
  3003         if integratortype.get() == "bidirectional":
  3004             if showadvanced.get()=="false":
  3005                 # Default parameters
  3006                 if gui: gui.newline("  Depth:", 8, 0, None, [0.4,0.4,0.4])
  3007                 bounces = luxProp(scn, "sintegrator.bidir.bounces", 16)
  3008                 luxInt("bounces", bounces, 5, 32, "bounces", "The maximum recursion depth for ray casting (in both directions)", gui, 2.0)
  3009                 str += "\n   \"integer eyedepth\" [%i]\n"%bounces.get()
  3010                 str += "   \"integer lightdepth\" [%i]"%bounces.get()
  3011 
  3012             if showadvanced.get()=="true":
  3013                 # Advanced parameters
  3014                 if gui: gui.newline("  Depth:")
  3015                 str += luxInt("eyedepth", luxProp(scn, "sintegrator.bidir.eyedepth", 16), 0, 2048, "eyedepth", "The maximum recursion depth for ray casting", gui)
  3016                 str += luxInt("lightdepth", luxProp(scn, "sintegrator.bidir.lightdepth", 16), 0, 2048, "lightdepth", "The maximum recursion depth for light ray casting", gui)
  3017                 str += luxOption("strategy", luxProp(scn, "sintegrator.bidir.strategy", "auto"), ["one", "all", "auto"], "strategy", "select directlighting strategy", gui)
  3018                 
  3019                 str += luxFloat('eyerrthreshold', luxProp(scn, "sintegrator.bidir.eyerrthreshold", 0), 0, 1, "eyerrthreshold", "The minimum probability for russian roulette eye subpath termination ", gui)
  3020                 str += luxFloat('lightrrthreshold', luxProp(scn, "sintegrator.bidir.lightrrthreshold", 0), 0, 1, "lightrrthreshold", "The minimum probability for russian roulette light subpath termination ", gui)
  3021 
  3022         if integratortype.get() == "exphotonmap":
  3023             if gui: gui.newline("  Render:")
  3024             str += luxOption("renderingmode", luxProp(scn, "sintegrator.photonmap.renderingmode", "directlighting"), ["directlighting", "path"], "renderingmode", "select rendering mode", gui)
  3025             str += luxOption("strategy", luxProp(scn, "sintegrator.photonmap.strategy", "auto"), ["one", "all", "auto"], "strategy", "select directlighting strategy", gui)
  3026             str += luxInt("maxphotondepth", luxProp(scn, "sintegrator.photonmap.maxphotondepth", 10), 1, 1024, "maxphotondepth", "The maximum recursion depth of photon tracing", gui)
  3027             str += luxInt("maxdepth", luxProp(scn, "sintegrator.photonmap.maxdepth", 6), 1, 1024, "maxdepth", "The maximum recursion depth of specular reflection and refraction", gui)
  3028             str += luxFloat("maxdist", luxProp(scn, "sintegrator.photonmap.maxdist", 0.1), 0.0, 10.0, "maxdist", "The maximum distance between a point being shaded and a photon that can contribute to that point", gui)
  3029             str += luxInt("nused", luxProp(scn, "sintegrator.photonmap.nused", 50), 0, 1000000, "nused", "The number of photons to use in density estimation", gui)
  3030 
  3031             if gui: gui.newline("  Photons:")
  3032             str += luxInt("indirectphotons", luxProp(scn, "sintegrator.photonmap.idphotons", 200000), 0, 10000000, "indirect", "The number of photons to shoot for indirect lighting during preprocessing of the photon map", gui)
  3033             str += luxInt("maxdirectphotons", luxProp(scn, "sintegrator.photonmap.maxdphotons", 1000000), 0, 10000000, "maxdirect", "The maximum number of photons to shoot for direct lighting during preprocessing of the photon map", gui)
  3034             str += luxInt("causticphotons", luxProp(scn, "sintegrator.photonmap.cphotons", 20000), 0, 10000000, "caustic", "The number of photons to shoot for caustics during preprocessing of the photon map", gui)
  3035             if gui: gui.newline("  FinalGather:")
  3036             fg = luxProp(scn, "sintegrator.photonmap.fgather", "true")
  3037             str += luxBool("finalgather", fg, "finalgather", "Enable use of final gather during rendering", gui)
  3038             if fg.get() == "true":
  3039                 rrstrat = luxProp(scn, "sintegrator.photonmap.gatherrrstrategy", "efficiency")
  3040                 str += luxOption("gatherrrstrategy", rrstrat, ["efficiency", "probability", "none"], "RR strategy", "select Russian Roulette gather termination strategy", gui)
  3041                 str += luxInt("finalgathersamples", luxProp(scn, "sintegrator.photonmap.fgathers", 32), 1, 1024, "samples", "The number of finalgather samples to take per pixel during rendering", gui)
  3042                 str += luxFloat("gatherangle", luxProp(scn, "sintegrator.photonmap.gangle", 10.0), 0.0, 360.0, "gatherangle", "Angle for final gather", gui)
  3043                 if rrstrat.get() == "probability":
  3044                     str += luxFloat("gatherrrcontinueprob", luxProp(scn, "sintegrator.photonmap.gatherrrcontinueprob", 0.65), 0.0, 1.0, "rrcontinueprob", "Probability for russian roulette particle tracing termination", gui)
  3045 
  3046         if integratortype.get() == "distributedpath":
  3047             str += luxOption("strategy", luxProp(scn, "sintegrator.distributedpath.strategy", "auto"), ["one", "all", "auto"], "strategy", "select directlighting strategy", gui)
  3048             if gui: gui.newline("  Direct:")
  3049             str += luxBool("directsampleall",luxProp(scn, "sintegrator.distributedpath.directsampleall", "true"), "Direct ALL", "Include diffuse direct light sample at first vertex", gui, 0.7)
  3050             str += luxInt("directsamples", luxProp(scn, "sintegrator.distributedpath.directsamples", 1), 0, 1024, "s", "The number of direct light samples to take at the eye vertex", gui, 0.3)
  3051             str += luxBool("indirectsampleall",luxProp(scn, "sintegrator.distributedpath.indirectsampleall", "false"), "Indirect ALL", "Include diffuse direct light sample at first vertex", gui, 0.7)
  3052             str += luxInt("indirectsamples", luxProp(scn, "sintegrator.distributedpath.indirectsamples", 1), 0, 1024, "s", "The number of direct light samples to take at the remaining vertices", gui, 0.3)
  3053             if gui: gui.newline("  Diffuse:")
  3054             str += luxInt("diffusereflectdepth", luxProp(scn, "sintegrator.distributedpath.diffusereflectdepth", 3), 0, 2048, "Reflect", "The maximum recursion depth for diffuse reflection ray casting", gui, 0.5)
  3055             str += luxInt("diffusereflectsamples", luxProp(scn, "sintegrator.distributedpath.diffusereflectsamples", 1), 0, 1024, "s", "The number of diffuse reflection samples to take at the eye vertex", gui, 0.3)
  3056             str += luxInt("diffuserefractdepth", luxProp(scn, "sintegrator.distributedpath.diffuserefractdepth", 5), 0, 2048, "Refract", "The maximum recursion depth for diffuse refraction ray casting", gui, 0.5)
  3057             str += luxInt("diffuserefractsamples", luxProp(scn, "sintegrator.distributedpath.diffuserefractsamples", 1), 0, 1024, "s", "The number of diffuse refraction samples to take at the eye vertex", gui, 0.3)
  3058             str += luxBool("directdiffuse",luxProp(scn, "sintegrator.distributedpath.directdiffuse", "true"), "DL", "Include diffuse direct light sample at first vertex", gui, 0.20)
  3059             str += luxBool("indirectdiffuse",luxProp(scn, "sintegrator.distributedpath.indirectdiffuse", "true"), "IDL", "Include diffuse indirect light sample at first vertex", gui, 0.20)
  3060             if gui: gui.newline("  Glossy:")
  3061             str += luxInt("glossyreflectdepth", luxProp(scn, "sintegrator.distributedpath.glossyreflectdepth", 2), 0, 2048, "Reflect", "The maximum recursion depth for glossy reflection ray casting", gui, 0.50)
  3062             str += luxInt("glossyreflectsamples", luxProp(scn, "sintegrator.distributedpath.glossyreflectsamples", 1), 0, 1024, "s", "The number of glossy reflection samples to take at the eye vertex", gui, 0.3)
  3063             str += luxInt("glossyrefractdepth", luxProp(scn, "sintegrator.distributedpath.glossyrefractdepth", 5), 0, 2048, "Refract", "The maximum recursion depth for glossy refraction ray casting", gui, 0.50)
  3064             str += luxInt("glossyrefractsamples", luxProp(scn, "sintegrator.distributedpath.glossyrefractsamples", 1), 0, 1024, "s", "The number of glossy refraction samples to take at the eye vertex", gui, 0.3)
  3065             str += luxBool("directglossy",luxProp(scn, "sintegrator.distributedpath.directglossy", "true"), "DL", "Include glossy direct light sample at first vertex", gui, 0.20)
  3066             str += luxBool("indirectglossy",luxProp(scn, "sintegrator.distributedpath.indirectglossy", "true"), "IDL", "Include glossy indirect light sample at first vertex", gui, 0.20)
  3067             if gui: gui.newline("  Specular:")
  3068             str += luxInt("specularreflectdepth", luxProp(scn, "sintegrator.distributedpath.specularreflectdepth", 3), 0, 2048, "Reflect", "The maximum recursion depth for specular reflection ray casting", gui, 1.0)
  3069             str += luxInt("specularrefractdepth", luxProp(scn, "sintegrator.distributedpath.specularrefractdepth", 5), 0, 2048, "Refract", "The maximum recursion depth for specular refraction ray casting", gui, 1.0)
  3070             #if gui: gui.newline("  Caustics:")
  3071             #str += luxBool("causticsondiffuse",luxProp(scn, "sintegrator.distributedpath.causticsondiffuse", "false"), "Caustics on Diffuse", "Enable caustics on diffuse surfaces (warning: might generate bright pixels)", gui, 1.0)
  3072             #str += luxBool("causticsonglossy",luxProp(scn, "sintegrator.distributedpath.causticsonglossy", "true"), "Caustics on Glossy", "Enable caustics on glossy surfaces (warning: might generate bright pixels)", gui, 1.0)
  3073 
  3074             usereject = luxProp(scn, "sintegrator.distributedpath.usereject", "false")
  3075             luxCollapse("usereject", usereject, "Rejection", "Enable Rejection system to eliminate bright contributions", gui, 2.0)
  3076 
  3077             if usereject.get()=="true":
  3078                 if gui: gui.newline("  Diffuse:")
  3079                 
  3080                 diffusereflectreject = luxProp(scn, "sintegrator.distributedpath.difreflreject", "false")
  3081                 str += luxBool("diffusereflectreject", diffusereflectreject, "Reflect", "Enable Rejection for Diffuse Reflection", gui, 0.4)
  3082                 if diffusereflectreject.get()=="true":
  3083                     str += luxFloat("diffusereflectreject_threshold", luxProp(scn, "sintegrator.distributedpath.difreflrejectthr", 10.0), 0.01, 10.0, "Thr", "The Average Threshold to reject", gui, 0.6)
  3084             
  3085                 diffuserefractreject = luxProp(scn, "sintegrator.distributedpath.difrefrreject", "false")
  3086                 str += luxBool("diffuserefractreject", diffuserefractreject, "Refract", "Enable Rejection for Diffuse Refraction", gui, 0.4)
  3087                 if diffuserefractreject.get()=="true":
  3088                     str += luxFloat("diffuserefractreject_threshold", luxProp(scn, "sintegrator.distributedpath.difrefrrejectthr", 10.0), 0.01, 10.0, "Thr", "The Average Threshold to reject", gui, 0.6)
  3089             
  3090                 if gui: gui.newline("  Glossy:")
  3091                 
  3092                 glossyreflectreject = luxProp(scn, "sintegrator.distributedpath.glosreflreject", "false")
  3093                 str += luxBool("glossyreflectreject", glossyreflectreject, "Reflect", "Enable Rejection for Glossy Reflection", gui, 0.4)
  3094                 if glossyreflectreject.get()=="true":
  3095                     str += luxFloat("glossyreflectreject_threshold", luxProp(scn, "sintegrator.distributedpath.glosreflrejectthr", 10.0), 0.01, 10.0, "Thr", "The Average Threshold to reject", gui, 0.6)
  3096             
  3097                 glossyrefractreject = luxProp(scn, "sintegrator.distributedpath.glosrefrreject", "false")
  3098                 str += luxBool("glossyrefractreject", glossyrefractreject, "Refract", "Enable Rejection for Glossy Refraction", gui, 0.4)
  3099                 if glossyrefractreject.get()=="true":
  3100                     str += luxFloat("glossyrefractreject_threshold", luxProp(scn, "sintegrator.distributedpath.glosrefrrejectthr", 10.0), 0.01, 10.0, "Thr", "The Average Threshold to reject", gui, 0.6)
  3101     
  3102         if integratortype.get() == "igi":
  3103             if gui: gui.newline("  Depth:", 8, 0, None, [0.4,0.4,0.4])
  3104             depth = luxProp(scn, "sintegrator.igi.maxdepth", 5)
  3105             luxInt("maxdepth", depth, 1, 32, "maxdepth", "The maximum recursion depth for ray casting", gui, 2.0)
  3106             if showadvanced.get()=="true":
  3107                 # Advanced parameters
  3108                 if gui: gui.newline("  VLights:")
  3109                 str += luxInt("nsets", luxProp(scn, "sintegrator.igi.nsets", 4), 1, 100, "nsets", "The number of virtual lights sets", gui)
  3110                 str += luxInt("nlights", luxProp(scn, "sintegrator.igi.nlights", 64), 1, 1000, "nlights", "The number of light paths per light set", gui)
  3111                 str += luxFloat("strategy", luxProp(scn, "sintegrator.igi.mindist", 0.1), 0.01, 10.0, "mindist", "The minimal distance to a virtual light to take it into account", gui)
  3112 
  3113     
  3114     return str
  3115 
  3116 def luxVolumeIntegrator(scn, gui=None):
  3117     global icon_c_volumeintegrator
  3118     str = ""
  3119     if scn:
  3120         integratortype = luxProp(scn, "vintegrator.type", "single")
  3121         str = luxIdentifier("VolumeIntegrator", integratortype, ["emission", "single"], "VOLUME INT", "select volume integrator type", gui, icon_c_volumeintegrator)
  3122         if integratortype.get() == "emission":
  3123             str += luxFloat("stepsize", luxProp(scn, "vintegrator.emission.stepsize", 1.0), 0.0, 100.0, "stepsize", "Stepsize for volumes", gui)
  3124         if integratortype.get() == "single":
  3125             str += luxFloat("stepsize", luxProp(scn, "vintegrator.emission.stepsize", 1.0), 0.0, 100.0, "stepsize", "Stepsize for volumes", gui)
  3126     return str
  3127 
  3128 def luxEnvironment(scn, gui=None):
  3129     global icon_c_environment
  3130     str = ""
  3131     if scn:
  3132         envtype = luxProp(scn, "env.type", "infinite")
  3133         lsstr = luxIdentifier("LightSource", envtype, ["none", "infinite", "sunsky"], "ENVIRONMENT", "select environment light type", gui, icon_c_environment)
  3134         if gui: gui.newline()
  3135         str = ""
  3136         
  3137         if envtype.get() != "none":
  3138             
  3139             if envtype.get() in ["infinite", "sunsky"]:
  3140                 env_lg = luxProp(scn, "env.lightgroup", "default")
  3141                 luxString("env.lightgroup", env_lg, "lightgroup", "Environment light group", gui)
  3142                 if luxProp(scn, "nolg", "false").get()!="true":
  3143                     lsstr = '\nLightGroup "' + env_lg.get() + '"' + lsstr
  3144                 rotZ = luxProp(scn, "env.rotation", 0.0)
  3145                 rotY = luxProp(scn, "env.rotationY", 0.0)
  3146                 rotX = luxProp(scn, "env.rotationX", 0.0)
  3147                 if gui: gui.newline()
  3148                 luxFloat("rotation", rotX, 0.0, 360.0, "rot X", "environment rotation X", gui, 0.66)
  3149                 luxFloat("rotation", rotY, 0.0, 360.0, "rot Y", "environment rotation Y", gui, 0.66)
  3150                 luxFloat("rotation", rotZ, 0.0, 360.0, "rot Z", "environment rotation Z", gui, 0.66)
  3151                 if rotZ.get() != 0 or rotY.get() != 0 or rotX.get() != 0:
  3152                     str += "\tRotate %d 1 0 0\n"%(rotX.get())
  3153                     str += "\tRotate %d 0 1 0\n"%(rotY.get())
  3154                     str += "\tRotate %d 0 0 1\n"%(rotZ.get())
  3155             str += "\t"+lsstr
  3156 
  3157             infinitehassun = 0
  3158             if envtype.get() == "infinite":
  3159                 mapping = luxProp(scn, "env.infinite.mapping", "latlong")
  3160                 mappings = ["latlong","angular","vcross"]
  3161                 mapstr = luxOption("mapping", mapping, mappings, "mapping", "Select mapping type", gui, 0.5)
  3162                 map = luxProp(scn, "env.infinite.mapname", "")
  3163                 mapstr += luxFile("mapname", map, "map-file", "filename of the environment map", gui, 1.5)
  3164                 mapstr += luxFloat("gamma", luxProp(scn, "env.infinite.gamma", 1.0), 0.0, 6.0, "gamma", "", gui, 1.0)
  3165                 
  3166                 if map.get() != "":
  3167                     str += mapstr
  3168                 else:
  3169                     try:
  3170                         worldcolor = Blender.World.Get('World').getHor()
  3171                         str += "\n   \"color L\" [%g %g %g]" %(worldcolor[0], worldcolor[1], worldcolor[2])
  3172                     except: pass
  3173 
  3174                 str += luxFloat("gain", luxProp(scn, "env.infinite.gain", 1.0), 0.0001, 100.0, "gain", "Infinite Env Gain", gui, 1.0)
  3175 
  3176                 infinitesun = luxProp(scn, "env.infinite.hassun", "false")
  3177                 luxCollapse("infinitesun", infinitesun, "Sun Component", "Add Sunlight Component", gui, 2.0)
  3178                 if(infinitesun.get() == "true"):
  3179                     sun_lg = luxProp(scn, "env.sun_lightgroup", "default")
  3180                     luxString("env.lightgroup", sun_lg, "lightgroup", "Sun component light group", gui)
  3181                     if luxProp(scn, "nolg", "false").get()!="true":
  3182                         str += '\nLightGroup "' + sun_lg.get() + '"'
  3183                     str += "\nLightSource \"sun\" "
  3184                     infinitehassun = 1
  3185 
  3186 
  3187             if envtype.get() == "sunsky" or infinitehassun == 1:
  3188                 
  3189                 
  3190                 sun = None
  3191                 for obj in scn.objects:
  3192                     if (obj.getType() == "Lamp") and ((obj.Layers & scn.Layers) > 0):
  3193                         if obj.getData(mesh=1).getType() == 1: # sun object # data
  3194                             sun = obj
  3195                 if sun:
  3196                     str += luxFloat("gain", luxProp(scn, "env.sunsky.gain", 1.0), 0.0001, 100.0, "gain", "Sky gain", gui)
  3197                     
  3198                     invmatrix = Mathutils.Matrix(sun.getInverseMatrix())
  3199                     str += "\n   \"vector sundir\" [%f %f %f]\n" %(invmatrix[0][2], invmatrix[1][2], invmatrix[2][2])
  3200                     str += luxFloat("relsize", luxProp(scn, "env.sunsky.relsize", 1.0), 0.0, 100.0, "rel.size", "relative sun size", gui)
  3201                     str += luxFloat("turbidity", luxProp(scn, "env.sunsky.turbidity", 2.2), 2.0, 50.0, "turbidity", "Sky turbidity", gui)
  3202                     
  3203                     showGeo = luxProp(sun, 'sc.show', 'false')
  3204                     if gui:
  3205                         luxCollapse("sc.show", showGeo, "Geographic Sun", "Set sun position by world location, date and time", gui, 2.0)
  3206                     if gui and showGeo.get() == 'true':
  3207                         gui.newline("Geographic:")
  3208                         sc = sun_calculator(sun)
  3209                         
  3210                         luxInt("sc.day", luxProp(sun, "sc.day", 1), 1, 31, "day", "Local date: day", gui, 0.66)
  3211                         luxInt("sc.month", luxProp(sun, "sc.month", 1), 1, 12, "month", "Local date: month", gui, 0.67)
  3212                         luxInt("sc.year", luxProp(sun, "sc.year", 2009), 1800, 2100, "year", "Local date: year", gui, 0.66)
  3213                         
  3214                         luxInt("sc.hour", luxProp(sun, "sc.hour", 0), 0, 23, "hour", "Local time: hour", gui, 0.72)
  3215                         luxInt("sc.minute", luxProp(sun, "sc.minute", 0), 0, 59, "minute", "Local time: minute", gui, 0.72)
  3216                         luxBool("sc.dst", luxProp(sun, "sc.dst", 'false'), "DST", "DST", gui, 0.28)
  3217                         r = gui.getRect(0.28,1)
  3218                         Draw.Button("NOW", 0, r[0], r[1], r[2], r[3], "Set to current time", lambda e,v: sc.now())
  3219                         
  3220                         r = gui.getRect(0.3,1)
  3221                         Draw.Button("Preset", 0, r[0], r[1], r[2], r[3], "Choose a preset location", lambda e,v: sc.set_location(
  3222                             Draw.PupTreeMenu(sun_calculator.location_list)
  3223                         ))
  3224                         
  3225                         luxFloat("sc.lat", luxProp(sun, "sc.lat", 0.0), -90.0, 90.0, "lat", "Location: latitude", gui, 0.56)
  3226                         luxFloat("sc.long", luxProp(sun, "sc.long", 0.0), -180.0, 180.0, "long", "Location: longitude", gui, 0.56)
  3227                         luxInt("sc.tz", luxProp(sun, "sc.tz", 0), -12, 12, "timezone", "Local time: timezone offset from GMT", gui, 0.56)
  3228                         
  3229                         r = gui.getRect(2,1)
  3230                         Draw.Button("Calculate", 0, r[0], r[1], r[2], r[3], "Calculate sun's position", lambda e,v: sc.compute())
  3231                     
  3232                 else:
  3233                     if gui:
  3234                         gui.newline(); r = gui.getRect(2,1); BGL.glRasterPos2i(r[0],r[1]+5) 
  3235                         Draw.Text("create a blender Sun Lamp")
  3236 
  3237 
  3238             str += "\n"
  3239         #if gui: gui.newline("GLOBAL:", 8, 0, None, [0.75,0.5,0.25])
  3240         #luxFloat("scale", luxProp(scn, "global.scale", 1.0), 0.0, 10.0, "scale", "global world scale", gui)
  3241         
  3242     return str
  3243 
  3244 class sun_calculator:
  3245     #Based on SunLight v1.0 by Miguel Kabantsov (miguelkab@gmail.com)
  3246     #Replaces the faulty sun position calculation algorythm with a precise calculation (Source for algorythm: http://de.wikipedia.org/wiki/Sonnenstand),
  3247     #Co-Ordinates: http://www.bcca.org/misc/qiblih/latlong.html
  3248     #Author: Nils-Peter Fischer (Nils-Peter.Fischer@web.de)
  3249     
  3250     sun = None
  3251     
  3252     lat = 0
  3253     long = 0
  3254     
  3255     hour = 0
  3256     min = 0
  3257     tz = 0
  3258     dst = 'false'
  3259     
  3260     day = 0
  3261     month = 0
  3262     year = 0
  3263     
  3264     location_list = [
  3265         ("EUROPE",[
  3266             ("Antwerp, Belgium",          67),
  3267             ("Berlin, Germany",            1),
  3268             ("Bratislava, Slovak Republic", 70),
  3269             ("Brno, Czech Republic",      72),
  3270             ("Brussles, Belgium",         68),
  3271             ("Geneva, Switzerland",       65),
  3272             ("Helsinki, Finland",          7),
  3273             ("Innsbruck, Austria",        62),
  3274             ("Kyiv, Ukraine",             64),
  3275             ("London, England",           10),
  3276             ("Lyon, France",              66),
  3277             ("Nitra, Slovak Republic",    69),
  3278             ("Oslo, Norway",              58),
  3279             ("Paris, France",             15),
  3280             ("Praha, Czech Republic",     71),
  3281             ("Rome, Italy",               18),
  3282             ("Telfs, Austria",            63),
  3283             ("Warsaw, Poland",            74),
  3284             ("Wroclaw, Poland",           73),
  3285             ("Zurich, Switzerland",       21),
  3286         ]),
  3287     
  3288         ("WORLD CITIES", [
  3289             ("Beijing, China",             0),
  3290             ("Bombay, India",              2),
  3291             ("Buenos Aires, Argentina",    3),
  3292             ("Cairo, Egypt",               4),
  3293             ("Cape Town, South Africa",    5),
  3294             ("Caracas, Venezuela",         6),
  3295             ("Curitiba, Brazil",          60),
  3296             ("Hong Kong, China",           8),
  3297             ("Jerusalem, Israel",          9),
  3298             ("Joinville, Brazil",         61),
  3299             ("Mexico City, Mexico",       11),
  3300             ("Moscow, Russia",            12),
  3301             ("New Delhi, India",          13),
  3302             ("Ottawa, Canada",            14),
  3303             ("Rio de Janeiro, Brazil",    16),
  3304             ("Riyadh, Saudi Arabia",      17),
  3305             ("Sao Paulo, Brazil",         59),
  3306             ("Sydney, Australia",         19),
  3307             ("Tokyo, Japan",              20), 
  3308         ]),
  3309         
  3310         ("US CITIES", [
  3311             ("Albuquerque, NM",           22),
  3312             ("Anchorage, AK",             23),
  3313             ("Atlanta, GA",               24),
  3314             ("Austin, TX",                25),
  3315             ("Birmingham, AL",            26),
  3316             ("Bismarck, ND",              27),
  3317             ("Boston, MA",                28),
  3318             ("Boulder, CO",               29),
  3319             ("Chicago, IL",               30),
  3320             ("Dallas, TX",                31),
  3321             ("Denver, CO",                32),
  3322             ("Detroit, MI",               33),
  3323             ("Honolulu, HI",              34),
  3324             ("Houston, TX",               35),
  3325             ("Indianapolis, IN",          36),
  3326             ("Jackson, MS",               37),
  3327             ("Kansas City, MO",           38),
  3328             ("Los Angeles, CA",           39),
  3329             ("Menomonee Falls, WI",       40),
  3330             ("Miami, FL",                 41),
  3331             ("Minneapolis, MN",           42),
  3332             ("New Orleans, LA",           43),
  3333             ("New York City, NY",         44),
  3334             ("Oklahoma City, OK",         45),
  3335             ("Philadelphia, PA",          46),
  3336             ("Phoenix, AZ",               47),
  3337             ("Pittsburgh, PA",            48),
  3338             ("Portland, ME",              49),
  3339             ("Portland, OR",              50),
  3340             ("Raleigh, NC",               51),
  3341             ("Richmond, VA",              52),
  3342             ("Saint Louis, MO",           53),
  3343             ("San Diego, CA",             54),
  3344             ("San Francisco, CA",         55),
  3345             ("Seattle, WA",               56),
  3346             ("Washington DC",             57),
  3347         ])
  3348     ]
  3349 
  3350     location_data = {
  3351         # Europe
  3352         67:   ( 51.2167, 4.4, 1),
  3353         1:    ( 52.33, 13.30, 1),
  3354         70:   ( 48.17, 17.17, 1),
  3355         72:   ( 49.2, 16.63, 1),
  3356         68:   ( 58.8467, 4.3525, 1),
  3357         65:   ( 46.217, 6.150, 1),
  3358         7:    ( 60.1667, 24.9667,2),
  3359         62:   ( 47.2672, 11.3928, 1),
  3360         64:   ( 50.75, 30.0833, 2),
  3361         10:   ( 51.50, 0.0, 0),
  3362         66:   ( 45.767, 4.833, 1),
  3363         69:   ( 48.32, 18.07, 1),
  3364         58:   ( 59.56, 10.41, 1),
  3365         15:   ( 48.8667, 2.667, 1),
  3366         71:   ( 50.08, 14.46, 1),
  3367         18:   ( 41.90, 12.4833, 1),
  3368         63:   ( 47.3, 11.0667, 1),
  3369         74:   ( 52.232, 21.008, 1),
  3370         73:   ( 51.108, 17.038, 1),
  3371         21:   ( 47.3833, 8.5333, 1),
  3372     
  3373         # World Cities
  3374         0:    ( 39.9167, 116.4167, 8),
  3375         2:    ( 18.9333, 72.8333, 5.5),
  3376         3:    (-34.60, -58.45, -3),
  3377         4:    ( 30.10, 31.3667, 2),
  3378         5:    (-33.9167, 18.3667, 2),
  3379         6:    ( 10.50, -66.9333, -4),
  3380         60:   (-25.4278, -49.2731, -3),
  3381         8:    ( 22.25, 114.1667, 8),
  3382         9:    ( 31.7833, 35.2333, 2),
  3383         61:   (-29.3044, -48.8456, -3),
  3384         11:   ( 19.4, -99.15, -6),
  3385         12:   ( 55.75, 37.5833, 3),
  3386         13:   ( 28.6, 77.2, 5.5),
  3387         14:   ( 45.41667, -75.7, -5),
  3388         16:   (-22.90, -43.2333, -3),
  3389         17:   ( 24.633, 46.71667, 3),
  3390         59:   ( -23.5475, -46.6361, -3),
  3391         19:   (-33.8667,151.2167,10),
  3392         20:   ( 35.70, 139.7667, 9), 
  3393     
  3394         # US Cities
  3395         22:   ( 35.0833, -106.65, -7),
  3396         23:   ( 61.217, -149.90, -9),
  3397         24:   ( 33.733, -84.383, -5),
  3398         25:   ( 30.283, -97.733, -6),
  3399         26:   ( 33.521, -86.8025, -6),
  3400         27:   ( 46.817, -100.783, -6),
  3401         28:   ( 42.35, -71.05, -5),
  3402         29:   ( 40.125, -105.237, -7),
  3403         30:   ( 41.85, -87.65, -6),
  3404         31:   ( 32.46, -96.47, -6),
  3405         32:   ( 39.733, -104.983, -7),
  3406         33:   ( 42.333, -83.05, -5),
  3407         34:   ( 21.30, -157.85, -10),
  3408         35:   ( 29.75, -95.35, -6),
  3409         36:   ( 39.767, -86.15, -5),
  3410         37:   ( 32.283, -90.183, -6),
  3411         38:   ( 39.083, -94.567, -6),
  3412         39:   ( 34.05, -118.233, -8),
  3413         40:   ( 43.11, -88.10, -6),
  3414         41:   ( 25.767, -80.183, -5),
  3415         42:   ( 44.967, -93.25, -6),
  3416         43:   ( 29.95, -90.067, -6),
  3417         44:   ( 40.7167, -74.0167, -5),
  3418         45:   ( 35.483, -97.533, -6),
  3419         46:   ( 39.95, -75.15, -5),
  3420         47:   ( 33.433, -112.067,-7),
  3421         48:   ( 40.433, -79.9833, -5),
  3422         49:   ( 43.666, -70.283, -5),
  3423         50:   ( 45.517, -122.65, -8),
  3424         51:   ( 35.783, -78.65, -5),
  3425         52:   ( 37.5667, -77.450, -5),
  3426         53:   ( 38.6167, -90.1833, -6),
  3427         54:   ( 32.7667, -117.2167, -8),
  3428         55:   ( 37.7667, -122.4167, -8),
  3429         56:   ( 47.60, -122.3167, -8),
  3430         57:   ( 38.8833, -77.0333, -5),
  3431     }
  3432 
  3433     def __init__(self, sun):
  3434         self.sun = sun
  3435     
  3436     def now(self):
  3437         ct = time.localtime()
  3438         
  3439         if ct[8] == 0:
  3440             dst = 'false'
  3441         else:
  3442             dst = 'true'
  3443         
  3444         luxProp(self.sun, 'sc.day', 0).set(ct[2])
  3445         luxProp(self.sun, 'sc.month', 0).set(ct[1])
  3446         luxProp(self.sun, 'sc.year', 0).set(ct[0])
  3447         luxProp(self.sun, 'sc.hour', 0).set(ct[3])
  3448         luxProp(self.sun, 'sc.minute', 0).set(ct[4])
  3449         luxProp(self.sun, 'sc.dst', 0).set(dst)
  3450         
  3451         self.compute()
  3452         
  3453     def set_location(self, location):
  3454         if location < 0: return
  3455         
  3456         lat, long, tz = self.location_data[location]
  3457         luxProp(self.sun, "sc.lat", 0).set(lat)
  3458         luxProp(self.sun, "sc.long", 0).set(long)
  3459         luxProp(self.sun, "sc.tz", 0).set(tz)
  3460         
  3461         self.compute()
  3462     
  3463     def compute(self):
  3464         
  3465         self.lat  = luxProp(self.sun, "sc.lat", 0).get()
  3466         self.long = luxProp(self.sun, "sc.long", 0).get()
  3467         self.tz   = luxProp(self.sun, "sc.tz", 0).get()
  3468         
  3469         self.hour = luxProp(self.sun, "sc.hour", 0).get()
  3470         self.min  = luxProp(self.sun, "sc.minute", 0).get()
  3471         self.dst  = luxProp(self.sun, "sc.dst", 'false').get()
  3472         if self.dst == 'true':
  3473             self.dst = 1
  3474         else:
  3475             self.dst = 0
  3476         
  3477         self.day   = luxProp(self.sun, "sc.day", 0).get()
  3478         self.month = luxProp(self.sun, "sc.month", 0).get()
  3479         self.year  = luxProp(self.sun, "sc.year", 0).get()
  3480         
  3481         
  3482         az,el = self.geoSunData(
  3483             self.lat,
  3484             self.long,
  3485             self.year,
  3486             self.month,
  3487             self.day,
  3488             self.hour + self.min/60.0,
  3489             -self.tz + self.dst
  3490         )
  3491         
  3492         self.sun.rot = math.radians(90-el), 0, math.radians(-az)
  3493         
  3494         Window.Redraw()
  3495         
  3496         
  3497     # --- THE FOLLOWING METHODS ARE ADAPTED FROM LUXMAYA ---
  3498     
  3499     # mathematical helpers
  3500     def sind(self, deg):
  3501         return math.sin(math.radians(deg))
  3502     
  3503     def cosd(self, deg):
  3504         return math.cos(math.radians(deg))
  3505     
  3506     def tand(self, deg):
  3507         return math.tan(math.radians(deg))
  3508     
  3509     def asind(self, deg):
  3510         return math.degrees(math.asin(deg))
  3511     
  3512     def atand(self, deg):
  3513         return math.degrees(math.atan(deg))
  3514     
  3515     
  3516     def geo_sun_astronomicJulianDate(self, Year, Month, Day, LocalTime, Timezone):
  3517         """
  3518         See quoted source in class header for explanation
  3519         """
  3520         
  3521         if Month > 2.0:
  3522             Y = Year
  3523             M = Month
  3524         else:
  3525             Y = Year - 1.0
  3526             M = Month + 12.0
  3527             
  3528         UT = LocalTime - Timezone
  3529         hour = UT / 24.0
  3530         A = int(Y/100.0)
  3531         B = 2.0 - A+int(A/4.0)
  3532         
  3533         JD = math.floor(365.25*(Y+4716.0)) + math.floor(30.6001*(M+1.0)) + Day + hour + B - 1524.4
  3534         
  3535         return JD
  3536     
  3537     def geoSunData(self, Latitude, Longitude, Year, Month, Day, LocalTime, Timezone):
  3538         """
  3539         See quoted source in class header for explanation
  3540         """
  3541         
  3542         JD = self.geo_sun_astronomicJulianDate(Year, Month, Day, LocalTime, Timezone)
  3543         
  3544         phi = Latitude
  3545         llambda = Longitude
  3546                 
  3547         n = JD - 2451545.0
  3548         LDeg = (280.460 + 0.9856474*n) - (math.floor((280.460 + 0.9856474*n)/360.0) * 360.0)
  3549         gDeg = (357.528 + 0.9856003*n) - (math.floor((357.528 + 0.9856003*n)/360.0) * 360.0)
  3550         LambdaDeg = LDeg + 1.915 * self.sind(gDeg) + 0.02 * self.sind(2.0*gDeg)
  3551         
  3552         epsilonDeg = 23.439 - 0.0000004*n
  3553         
  3554         alphaDeg = self.atand( (self.cosd(epsilonDeg) * self.sind(LambdaDeg)) / self.cosd(LambdaDeg) )
  3555         if self.cosd(LambdaDeg) < 0.0:
  3556             alphaDeg += 180.0
  3557             
  3558         deltaDeg = self.asind( self.sind(epsilonDeg) * self.sind(LambdaDeg) )
  3559         
  3560         JDNull = self.geo_sun_astronomicJulianDate(Year, Month, Day, 0.0, 0.0)
  3561         
  3562         TNull = (JDNull - 2451545.0) / 36525.0
  3563         T = LocalTime - Timezone
  3564         
  3565         thetaGh = 6.697376 + 2400.05134*TNull + 1.002738*T
  3566         thetaGh -= math.floor(thetaGh/24.0) * 24.0
  3567         
  3568         thetaG = thetaGh * 15.0
  3569         theta = thetaG + llambda
  3570         
  3571         tau = theta - alphaDeg
  3572         
  3573         a = self.atand( self.sind(tau) / ( self.cosd(tau)*self.sind(phi) - self.tand(deltaDeg)*self.cosd(phi)) )
  3574         if self.cosd(tau)*self.sind(phi) - self.tand(deltaDeg)*self.cosd(phi) < 0.0:
  3575             a += 180.0
  3576         
  3577         h = self.asind( self.cosd(deltaDeg)*self.cosd(tau)*self.cosd(phi) + self.sind(deltaDeg)*self.sind(phi) )
  3578         
  3579         R = 1.02 / (self.tand (h+(10.3/(h+5.11))))
  3580         hR = h + R/60.0
  3581         
  3582         azimuth = a
  3583         elevation = hR
  3584         
  3585         return azimuth, elevation
  3586 
  3587 def luxAccelerator(scn, gui=None):
  3588     str = ""
  3589     if scn:
  3590         acceltype = luxProp(scn, "accelerator.type", "tabreckdtree")
  3591         str = luxIdentifier("Accelerator", acceltype, ["none", "tabreckdtree", "grid", "bvh", "qbvh"], "ACCEL", "select accelerator type", gui)
  3592         if acceltype.get() == "tabreckdtree":
  3593             if gui: gui.newline()
  3594             str += luxInt("intersectcost", luxProp(scn, "accelerator.kdtree.interscost", 80), 0, 1000, "inters.cost", "specifies how expensive ray-object intersections are", gui)
  3595             str += luxInt("traversalcost", luxProp(scn, "accelerator.kdtree.travcost", 1), 0, 1000, "trav.cost", "specifies how expensive traversing a ray through the kdtree is", gui)
  3596             if gui: gui.newline()
  3597             str += luxFloat("emptybonus", luxProp(scn, "accelerator.kdtree.emptybonus", 0.2), 0.0, 100.0, "empty.b", "promotes kd-tree nodes that represent empty space", gui)
  3598             if gui: gui.newline()
  3599             str += luxInt("maxprims", luxProp(scn, "accelerator.kdtree.maxprims", 1), 0, 1000, "maxprims", "maximum number of primitives in a kdtree volume before further splitting of the volume occurs", gui)
  3600             str += luxInt("maxdepth", luxProp(scn, "accelerator.kdtree.maxdepth", -1), -1, 100, "maxdepth", "If positive, the maximum depth of the tree. If negative this value is set automatically", gui)
  3601         if acceltype.get() == "unsafekdtree":
  3602             if gui: gui.newline()
  3603             str += luxInt("intersectcost", luxProp(scn, "accelerator.kdtree.interscost", 80), 0, 1000, "inters.cost", "specifies how expensive ray-object intersections are", gui)
  3604             str += luxInt("traversalcost", luxProp(scn, "accelerator.kdtree.travcost", 1), 0, 1000, "trav.cost", "specifies how expensive traversing a ray through the kdtree is", gui)
  3605             if gui: gui.newline()
  3606             str += luxFloat("emptybonus", luxProp(scn, "accelerator.kdtree.emptybonus", 0.2), 0.0, 100.0, "empty.b", "promotes kd-tree nodes that represent empty space", gui)
  3607             if gui: gui.newline()
  3608             str += luxInt("maxprims", luxProp(scn, "accelerator.kdtree.maxprims", 1), 0, 1000, "maxprims", "maximum number of primitives in a kdtree volume before further splitting of the volume occurs", gui)
  3609             str += luxInt("maxdepth", luxProp(scn, "accelerator.kdtree.maxdepth", -1), -1, 100, "maxdepth", "If positive, the maximum depth of the tree. If negative this value is set automatically", gui)
  3610         if acceltype.get() == "grid":
  3611             str += luxBool("refineimmediately", luxProp(scn, "accelerator.grid.refine", "false"), "refine immediately", "Makes the primitive intersectable as soon as it is added to the grid", gui)
  3612         if acceltype.get() == "qbvh":
  3613             if gui: gui.newline()
  3614             str += luxInt("maxprimsperleaf", luxProp(scn, "accelerator.qbvh.maxprimsperleaf", 4), 1, 64, "maxprimsperleaf", "Maximum number of primitives to leave in one leaf node", gui)
  3615     return str
  3616 
  3617 def luxSystem(scn, gui=None):
  3618     if scn:
  3619         if gui: gui.newline("PATHS:", 10)
  3620         lp = luxProp(scn, "lux", "")
  3621         lp.set(Blender.sys.dirname(lp.get())+os.sep)
  3622         luxPath("LUX dir", lp, "lux binary dir", "Lux installation path", gui, 2.0)
  3623 
  3624 #        luxFile("GUI filename", luxProp(scn, "lux", ""), "lux-file", "filename and path of the lux GUI executable", gui, 2.0)
  3625 #        luxFile("Console filename", luxProp(scn, "luxconsole", ""), "lux-file-console", "filename and path of the lux console executable", gui, 2.0)
  3626         if gui: gui.newline()
  3627         luxFile("datadir", luxProp(scn, "datadir", ""), "default out dir", "default.lxs save path", gui, 2.0)
  3628 
  3629         if gui: gui.newline()
  3630         pm = ["absolute","relative","flat"]
  3631         luxOption("pathmode", luxProp(scn, "pathmode", "absolute"), pm, "path-mode", "select format for paths on export", gui, 2.0)
  3632 
  3633         if gui: gui.newline("PRIORITY:", 10)
  3634         luxnice = luxProp(scn, "luxnice", 10)
  3635         if osys.platform=="win32":
  3636             r = gui.getRect(2, 1)
  3637             Draw.Menu("priority%t|abovenormal%x-10|normal%x0|belownormal%x10|low%x19", evtLuxGui, r[0], r[1], r[2], r[3], luxnice.get(), "", lambda e,v: luxnice.set(v))
  3638         else: luxInt("nice", luxnice, -20, 19, "nice", "nice value. Range goes from -20 (highest priority) to 19 (lowest)", gui)
  3639 
  3640         luxBool("noopengl", luxProp(scn, "noopengl", "false"), "Disable OpenGL", "(workaround for some buggy display drivers)", gui, 1.0)
  3641 
  3642 
  3643         if gui: gui.newline("THREADS:", 10)
  3644         autothreads = luxProp(scn, "autothreads", "true")
  3645         luxBool("autothreads", autothreads, "Auto Detect", "Automatically use all available processors", gui, 1.0)
  3646         if autothreads.get()=="false":
  3647             luxInt("threads", luxProp(scn, "threads", 1), 1, 100, "threads", "number of threads used for rendering", gui, 1.0)
  3648 #        luxBool('export.threaded', luxProp(scn, 'export.threaded', 'true'), 'Pipe in background', 'When using pipe export, do not block Blender UI', gui, 1.0)
  3649 
  3650         if gui: gui.newline("ANIM:", 10)
  3651         useparamkeys = luxProp(scn, "useparamkeys", "false")
  3652         luxBool("useparamkeys", useparamkeys, "Enable Parameter IPO Keyframing", "Enables keyframing of luxblend parameters", gui, 2.0)
  3653 
  3654         if gui: gui.newline("PARAMS:", 10)
  3655         parammodeadvanced = luxProp(scn, "parammodeadvanced", "false")
  3656         luxBool("parammodeadvanced", parammodeadvanced, "Default Advanced Parameters", "Always use advanced parameters by default", gui, 2.0)
  3657 
  3658         if gui: gui.newline("PREVIEW:", 10)
  3659         qs = ["low","medium","high","very high"]
  3660         defprevmat = luxProp(scn, "defprevmat", "high")
  3661         luxOption("defprevmat", defprevmat, qs, "Materials", "Select default preview quality in material editor for materials", gui, 1.0)
  3662 
  3663         if gui: gui.newline("GAMMA:", 10)
  3664         luxBool("RGC", luxProp(scn, "RGC", "true"), "RGC", "use reverse gamma correction", gui)
  3665         luxBool("ColClamp", luxProp(scn, "colorclamp", "false"), "ColClamp", "clamp all colors to 0.0-0.9", gui)
  3666         if gui: gui.newline("MESH:", 10)
  3667         luxBool("mesh_optimizing", luxProp(scn, "mesh_optimizing", "true"), "optimize meshes", "Optimize meshes during export", gui, 2.0)
  3668         #luxInt("trianglemesh thr", luxProp(scn, "trianglemesh_thr", 0), 0, 10000000, "trianglemesh threshold", "Vertex threshold for exporting (wald) trianglemesh object(s)", gui, 2.0)
  3669         #if gui: gui.newline()
  3670         #luxInt("barytrianglemesh thr", luxProp(scn, "barytrianglemesh_thr", 300000), 0, 100000000, "barytrianglemesh threshold", "Vertex threshold for exporting barytrianglemesh object(s) (slower but uses less memory)", gui, 2.0)
  3671         if gui: gui.newline("INSTANCING:", 10)
  3672         luxInt("instancing_threshold", luxProp(scn, "instancing_threshold", 2), 0, 1000000, "object instancing threshold", "Threshold to created instanced objects", gui, 2.0)
  3673         
  3674         # dougal2 packed images, enable this when implemented in Lux itself
  3675         #if gui: gui.newline('TEXTURES:',10)
  3676         #impack = luxProp(scn, 'packtextures', 'false')
  3677         #luxBool('impack', impack, 'Pack All Images', '', gui, 2.0)
  3678         
  3679         if gui: 
  3680             network=luxProp(scn,"network","false")
  3681             gui.newline("NETWORK:", 10)
  3682             luxCollapse("network",network, "network", "enable network option", gui, 2.0)
  3683             if(network.get() == "true"):
  3684                 network_use_file=luxProp(scn,"network_use_file","false")
  3685                 luxBool ("use file",network_use_file,"use file", "get list of servers from file; one per line",gui,2.0)
  3686                 if (network_use_file.get() == "true"):
  3687                     luxFile("file", luxProp(scn, "network_file_path", ""), "file", "file where servers are defined", gui, 1.0)         
  3688                 else :     
  3689                     #gui.newline("")
  3690                     luxString("Servers",luxProp(scn,"network_servers",""),"servers","coma separated list of servers",gui,1.0)
  3691                 #gui.newline("")
  3692                 luxInt("network_interval",luxProp(scn,"newtork_interval",180),0,300,"update interval","interval between network refresh",gui)
  3693 
  3694 
  3695 def scalelist(list, factor):
  3696     for i in range(len(list)): list[i] = list[i] * factor
  3697     return list
  3698 
  3699 
  3700 def luxMapping(key, mat, gui, level=0):
  3701     global icon_map2d, icon_map2dparam
  3702     if gui: gui.newline("2Dmap:", -2, level, icon_map2d)
  3703     mapping = luxProp(mat, key+".mapping", "uv")
  3704     mappings = ["uv","spherical","cylindrical","planar"]
  3705     str = luxOption("mapping", mapping, mappings, "mapping", "", gui, 0.5)
  3706     if mapping.get() == "uv":
  3707     	if gui: gui.newline()
  3708         str += luxFloat("uscale", luxProp(mat, key+".uscale", 1.0), -100.0, 100.0, "Us", "u-scale", gui, 0.5)
  3709         str += luxFloat("vscale", luxProp(mat, key+".vscale", -1.0), -100.0, 100.0, "Vs", "v-scale", gui, 0.5)
  3710         str += luxFloat("udelta", luxProp(mat, key+".udelta", 0.0), -100.0, 100.0, "Ud", "u-delta", gui, 0.5)
  3711         str += luxFloat("vdelta", luxProp(mat, key+".vdelta", 0.0), -100.0, 100.0, "Vd", "v-delta", gui, 0.5)
  3712     if mapping.get() == "planar":
  3713         str += luxFloat("udelta", luxProp(mat, key+".udelta", 0.0), -100.0, 100.0, "Ud", "u-delta", gui, 0.75)
  3714         str += luxFloat("vdelta", luxProp(mat, key+".vdelta", 0.0), -100.0, 100.0, "Vd", "v-delta", gui, 0.75)
  3715         if gui: gui.newline("v1:", -2, level+1, icon_map2dparam)
  3716         str += luxVector("v1", luxProp(mat, key+".v1", "1 0 0"), -100.0, 100.0, "v1", "v1-vector", gui, 2.0)
  3717         if gui: gui.newline("v2:", -2, level+1, icon_map2dparam)
  3718         str += luxVector("v2", luxProp(mat, key+".v2", "0 1 0"), -100.0, 100.0, "v2", "v2-vector", gui, 2.0)
  3719     return str
  3720 
  3721 def lux3DMapping(key, mat, gui, level=0):
  3722     global icon_map3dparam
  3723     str = ""
  3724     if gui: gui.newline("scale:", -2, level, icon_map3dparam)
  3725     str += luxVectorUniform("scale", luxProp(mat, key+".3dscale", 1.0), 0.001, 1000.0, "scale", "scale-vector", gui, 2.0)
  3726     if gui: gui.newline("rot:", -2, level, icon_map3dparam)
  3727     str += luxVector("rotate", luxProp(mat, key+".3drotate", "0 0 0"), -360.0, 360.0, "rotate", "rotate-vector", gui, 2.0)
  3728     if gui: gui.newline("move:", -2, level, icon_map3dparam)
  3729     str += luxVector("translate", luxProp(mat, key+".3dtranslate", "0 0 0"), -1000.0, 1000.0, "move", "translate-vector", gui, 2.0)
  3730     return str
  3731     
  3732 def getTreeNameById(tree, i): # helper function to retrive name of the selected treemenu-item
  3733     for t in tree:
  3734         if type(t)==types.TupleType:
  3735             if type(t[1])==types.ListType: 
  3736                 n=getTreeNameById(t[1], i)
  3737                 if n: return n
  3738             elif t[1]==i: return t[0]
  3739     return None    
  3740 
  3741 def luxTexture(name, parentkey, type, default, min, max, caption, hint, mat, gui, matlevel, texlevel=0, lightsource=0, overrideicon=""):
  3742     global icon_tex, icon_texcol, icon_texmix, icon_texmixcol, icon_texparam, icon_spectex
  3743     def c(t1, t2):
  3744         return (t1[0]+t2[0], t1[1]+t2[1])
  3745     def alternativedefault(type, default):
  3746         if type=="float": return 0.0
  3747         else: return "0.0 0.0 0.0"
  3748     level = matlevel + texlevel
  3749     keyname = "%s:%s"%(parentkey, name)
  3750     texname = "%s:%s"%(mat.getName(), keyname)
  3751 #    if gui: gui.newline(caption+":", 0, level)
  3752     if(lightsource == 0):
  3753         if texlevel == 0: texture = luxProp(mat, keyname+".texture", "imagemap")
  3754         else: texture = luxProp(mat, keyname+".texture", "constant")
  3755     else:
  3756         texture = luxProp(mat, keyname+".texture", "blackbody")
  3757 
  3758     textures = ["constant","blackbody", "lampspectrum", "equalenergy", "frequency", "gaussian", "regulardata", "irregulardata", "imagemap","mix","scale","bilerp","uv", "checkerboard","brick","dots","fbm","marble","wrinkled", "windy", "blender_marble", "blender_musgrave", "blender_wood", "blender_clouds", "blender_blend", "blender_distortednoise", "blender_noise", "blender_magic", "blender_stucci", "blender_voronoi", "harlequin"]
  3759 
  3760     if gui:
  3761         if(overrideicon != ""):
  3762             icon = overrideicon
  3763         else:
  3764             icon = icon_tex
  3765             if texture.get() in ["mix", "scale", "checkerboard", "dots"]:
  3766                 if type=="color": icon = icon_texmixcol
  3767                 else: icon = icon_texmix
  3768             elif texture.get() in ["constant", "blackbody", "equalenergy", "frequency", "gaussian", "regulardata", "irregulardata"]:
  3769                 icon = icon_spectex
  3770             else:
  3771                 if type=="color": icon = icon_texcol
  3772                 else: icon = icon_tex
  3773         if (texlevel > 0): gui.newline(caption+":", -2, level, icon, scalelist([0.5,0.5,0.5],2.0/(level+2)))
  3774         else: gui.newline("texture:", -2, level, icon, scalelist([0.5,0.5,0.5],2.0/(level+2)))
  3775     luxOption("texture", texture, textures, "texture", "", gui, 2)
  3776     str = "Texture \"%s\" \"%s\" \"%s\""%(texname, type, texture.get())
  3777 
  3778     if gui: Draw.PushButton(">", evtLuxGui, gui.xmax+gui.h, gui.y-gui.h, gui.h, gui.h, "Menu", lambda e,v: showMatTexMenu(mat,keyname,True))
  3779     if gui: # Draw Texture level Material preview
  3780         luxPreview(mat, parentkey, 1, False, False, name, gui, texlevel, [0.5, 0.5, 0.5])
  3781         # Add an offset for next controls
  3782         #r = gui.getRect(1.0, 1)
  3783         #gui.x += 140
  3784 
  3785     if texture.get() == "constant":
  3786         value = luxProp(mat, keyname+".value", default)
  3787         if type == "float": luxFloat("value", value, min, max, "", "", gui, 1.1)
  3788         elif type == "color": luxRGB("value", value, max, "", "", gui, 2)
  3789 # direct version
  3790         if type == "color": return ("", " \"%s %s\" [%s]"%(type, name, value.getRGC()))
  3791         return ("", " \"%s %s\" [%s]"%(type, name, value.get()))
  3792 # indirect version
  3793 #        if type == "color": str += " \"%s value\" [%s]"%(type, value.getRGC())
  3794 #        else: str += " \"%s value\" [%s]"%(type, value.get())
  3795 
  3796     if texture.get() == "blackbody":
  3797         if gui:
  3798             if gui.xmax-gui.x < gui.w: gui.newline()
  3799             r = gui.getRect(1.0, 1)
  3800             gui.newline()
  3801             drawBar(bar_blackbody, gui.xmax-gui.w-7, r[1])
  3802         str += luxFloat("temperature", luxProp(mat, keyname+".bbtemp", 6500.0), 1000.0, 10000.0, "temperature", "Black Body temperature in degrees Kelvin", gui, 2.0, 1)
  3803 
  3804     if texture.get() == "lampspectrum":
  3805         lampstring = luxProp(mat, keyname+".lampstring", "Incandescent2")
  3806         lamppreset = luxProp(mat, keyname+".lampspectrum", "PHILIPS [Argenta] 200W Incandescent Lamp")
  3807         if gui:
  3808             def setLamp(i, value, preset, tree, dict): # callback function to set ior value after selection
  3809                 if i >= 0:
  3810                     value.set(dict[i])
  3811                     preset.set(getTreeNameById(tree, i))
  3812 
  3813             measuredtree = [ 	("Natural Daylight", 	[ ("Natural Daylight", 1) ] ), ("Incandescent", 	[ ("Paraffin Candle Flame", 2), ("Generic 7W Incandescent Lamp", 3), ("PHILIPS [Argenta] 200W Incandescent Lamp", 4), ("Welsbach Gas Mantle (modern, without Thorium)", 5), ("Incandescent Anti-Insect Lamp", 6) ] ), ("Fluorescent/Compact Fluorescent",	[ ("PHILIPS [TL-D 30W/55] Regular Daylight Fluorescent", 7), ("Sylvania [F4T5 4W] Regular Warm White Fluorescent", 8), ("OSRAM [DULUXSTAR 21W/827] Regular Compact Triphosphor Fluorescent", 9), ("Cold Cathode Warm White CFL Triphosphor Fluorescent.", 10), ("NARVA [COLOURLUX plus daylight 20W/860] Daylight CFL Triphosphor Fluorescent", 11), ("Sylvania [GroLux] Fluorescent Aquarium/Plant Lamp", 12), ("Laptop LCD Screen", 13), ("PHILIPS [ActiViva] \"Natural\" Triphosphor Fluorescent", 14), ("PHILIPS [ActiViva] \"Active\" Triphosphor Fluorescent", 16) ] ), ("High Pressure Mercury",		[ ("OSRAM [HQA 80W] Clear HPM Lamp", 17), ("PHILIPS [HPL 125W] HPM Lamp with improved color", 18), ("OSRAM [HQL 80W] HPM Lamp with improved warm deluxe color", 19), ("PHILIPS [ML 160W] Self-Ballasted HPM Vapor Lamp", 20), ("NARVA [160W] Self-ballasted HPM Vapor Lamp", 21) ] ), ("Low/High Pressure Sodium",		[ ("Regular High Pressure Sodium Lamp, warmup after 5-7 sec", 22), ("Regular High Pressure Sodium Lamp, warmup after 10-12 sec", 23), ("SOX Low Pressure Sodium Discharge Lamp", 24), ("Medium Pressure Sodium Discharge Lamp, warmup after ~35 sec", 25), ("GE [Lucalox 35W] High Pressure Sodium Lamp", 26), ("PHILIPS [SDW-T 100W] Super High Pressure White Sodium Lamp", 27) ] ), ("Metal Halide",		[ ("PHILIPS [HPI-T 400W] MH Lamp with Mercury, Sodium, Thallium and Indium iodides", 28), ("OSRAM [HQI-TS 75W/WDL] Metal Halide lamp with Mercury, sodium, thallium, indium and tin iodides, from ", 29), ("GE [MVR325IUWM 325 Watt I-Line Multi-Vapor® Metal Halide - Clear Watt Miser®] MH Lamp with Mercury, Sodium and Scandium iodides", 30), ("OSRAM [HQI-T 400W/D] MH Lamp with Mercury, Thallium, Dysprosium, Holmium, Thulium and Caesium iodides", 31), ("PHILIPS Diazo MH Lamp with Mercury, iron and cobalt iodides", 32), ("Sylvania Diazo MH Lamp with Mercury, gallium and lead iodides", 33), ("OSRAM [HQI-T 400W/Blau] Blue colored MH Lamp with Mercury and indium iodides", 34), ("RADIUM [HRI-T 400W/Planta] Plant growing MH Lamp with Mercury, indium and sodium iodides", 35), ("OSRAM [HQI-T 400W/Grun] Green colored MH Lamp with Mercury and thallium iodides", 36) ] ), ("Diode",		[ ("Regular High Brightness Blue LED", 37), ("Monochromatic emission from a Red Laser diode", 38), ("Monochromatic emission from a Green Laser diode.", 39) ] ), ("Spectral",		[ ("PHILIPS Spectral Xenon Lamp - Continuous Xenon low pressure thermionic discharge", 40), ("PHILIPS spectral Rubidium Lamp - Continuous Rubidium low pressure thermionic discharge", 41), ("PHILIPS spectral Cadmium Lamp - Continuous Cadmium low pressure thermionic discharge", 42), ("PHILIPS spectral zinc Lamp - Continuous Zinc low pressure thermionic discharge", 43) ] ), ("Glow Discharge",		[ ("Neon glow discharge", 44), ("Neon and Krypton glow discharge and green phosphor (night-lights/indicators)", 45), ("Neon and Xenon glow discharge and green phosphor (night-lights/indicators)", 46), ("Neon and Xenon glow discharge and blue phosphor (night-lights/indicators)", 48), ("Argon glow discharge", 49), ("Self-ballasted High Pressure Mercury Vapor Lamp, with yttrium vanadate phosphate fluorescent phosphors, in glow discharge mode", 50) ] ), ("Molecular",		[ ("Butane Gas Flame", 51), ("Alcohol Flame", 52) ] ), ("General Fluorescence",		[ ("Print quality A4 Xerox paper wrapped around a blacklight Lamp", 53), ("Neon green dye, bombarded with black light", 54), ("Regular Modern Color TV CRT", 55) ] ), ("Various",		[ ("Stroboscopic flash. Xenon I, likely II and perhaps III", 56), ("Carbon Arc Spectrum", 57), ("OSRAM [XBO 75W/2] Short Arc Xenon Lamp", 58) ] ), ("Blacklight/Ultraviolet",		[ ("Sylvania [G8T5 8W] Germicidal lamp", 59), ("Sylvania [F6T5/BLB 8W] Black light blue fluorescent", 60), ("PHILIPS [HPW 125W] High Pressure Mercury Black Light", 61), ("Sylvania [Blacklite 350 F8W/BL350] Black Light fluorescent", 62) ] ), ("Mercury UV Spectrum",		[ ("The near visible UVA emissions from a high pressure Mercury clear lamp", 63) ] ), ("Absorption/Mixed Spectra",		[ ("High Pressure Mercury Warm Deluxe light ([1.4.3]) absorbed through blue Cobalt glass", 64), ("Incandescent light ([1.2.3]) absorbed through blue Cobalt glass", 65), ("High Pressure Mercury Warm Deluxe light ([1.4.3]) absorbed through ciel dye #42053", 66), ("Incandescent light ([1.2.3]) absorbed through ciel dye #42053", 67), ("High Pressure Mercury Warm Deluxe light ([1.4.3]) absorbed through red glass", 68), ("Incandescent light ([1.2.3]) absorbed through red glass.m", 69), ("Incandescent light ([1.2.3]) absorbed through olive oil. ", 70) ] ) ] 
  3814 
  3815             measureddict  = {1:"Daylight", 2:"Candle", 3:"Incandescent1", 4:"Incandescent2", 5:"Welsbach", 6:"AntiInsect", 7:"FLD2", 8:"FL37K", 9:"CFL27K", 10:"CFL4K", 11:"CFL6K", 12:"GroLux", 13:"LCDS", 14:"FLAV8K", 15:"none", 16:"FLAV17K", 17:"HPM2", 18:"HPMFL1", 19:"HPMFL2", 20:"HPMSB", 21:"HPMSBFL", 22:"SS1", 23:"SS2", 24:"LPS", 25:"MPS", 26:"HPS", 27:"SHPS", 28:"MHN", 29:"MHWWD", 30:"MHSc", 31:"MHD", 32:"FeCo", 33:"GaPb", 34:"BLAU", 35:"PLANTA", 36:"GRUN", 37:"LEDB", 38:"RedLaser", 39:"GreenLaser", 40:"XeI", 41:"Rb", 42:"Cd", 43:"Zn", 44:"Ne", 45:"NeKrFL", 46:"NeXeFL1", 47:"none", 48:"NeXeFL2", 49:"Ar", 50:"HPMFL2Glow", 51:"Butane", 52:"Alcohol", 53:"BLP", 54:"BLNG", 55:"TV", 56:"Xe", 57:"CarbonArc", 58:"HPX", 59:"LPM2", 60:"FLBLB", 61:"HPMBL", 62:"FLBL", 63:"UVA", 64:"HPMFLCobaltGlass", 65:"CobaltGlass", 66:"HPMFLCL42053", 67:"CL42053", 68:"HPMFLRedGlass", 69:"RedGlass", 70:"OliveOil" }
  3816 
  3817             r = gui.getRect(2.0, 1)
  3818             Draw.Button(lamppreset.get(), evtLuxGui, r[0], r[1], r[2], r[3], "select lamp spectrum", lambda e,v: setLamp(Draw.PupTreeMenu(measuredtree), lampstring, lamppreset, measuredtree, measureddict))
  3819         str += luxString("name", lampstring, "Lamp", "Choose measured Lamp Spectrum", None, 2.0)
  3820 
  3821     if texture.get() == "equalenergy":
  3822         if gui:
  3823             if gui.xmax-gui.x < gui.w: gui.newline()
  3824             r = gui.getRect(1.0, 1)
  3825             gui.newline()
  3826             drawBar(bar_equalenergy, gui.xmax-gui.w-7, r[1])
  3827         str += luxFloat("energy", luxProp(mat, keyname+".energy", 1.0), 0.0, 1.0, "energy", "Energy of each spectral band", gui, 2.0, 1)
  3828 
  3829     if texture.get() == "frequency":
  3830         str += luxFloat("freq", luxProp(mat, keyname+".freq", 0.01), 0.01, 100.0, "frequency", "Frequency in nm", gui, 2.0, 1)
  3831         str += luxFloat("phase", luxProp(mat, keyname+".phase", 0.5), 0.0, 1.0, "phase", "Phase", gui, 1.1, 1)
  3832         str += luxFloat("energy", luxProp(mat, keyname+".energy", 1.0), 0.0, 1.0, "energy", "Amount of mean energy", gui, 0.9, 1)
  3833 
  3834     if texture.get() == "gaussian":
  3835         if gui:
  3836             if gui.xmax-gui.x < gui.w: gui.newline()
  3837             r = gui.getRect(1.0, 1)
  3838             gui.newline()
  3839             drawBar(bar_spectrum, gui.xmax-gui.w-7, r[1])
  3840         str += luxFloat("wavelength", luxProp(mat, keyname+".wavelength", 550.0), 380.0, 720.0, "wavelength", "Mean Wavelength in visible spectrum in nm", gui, 2.0, 1)
  3841         str += luxFloat("width", luxProp(mat, keyname+".width", 50.0), 20.0, 300.0, "width", "Width of gaussian distribution in nm", gui, 1.1, 1)
  3842         str += luxFloat("energy", luxProp(mat, keyname+".energy", 1.0), 0.0, 1.0, "energy", "Amount of mean energy", gui, 0.9, 1)
  3843 
  3844     if texture.get() == "imagemap":
  3845         if gui: gui.newline("IM-clip:", -2, level)
  3846         str += luxOption("wrap", luxProp(mat, keyname+".wrap", "repeat"), ["repeat","black","clamp"], "repeat", "", gui, 1.0)
  3847 
  3848         if gui: gui.newline("IM-source:", -2, level)
  3849 
  3850         # ZANQDO
  3851         texturefilename = luxProp(mat, keyname+".filename", "")
  3852         extimage = luxProp(mat, keyname+'.externalimage', "true")
  3853         luxBool("External Image", extimage, "External Image", "External Image", gui, 1.0)
  3854         if gui: gui.newline("IM-path:", -2, level)
  3855         if extimage.get() == "true":
  3856             luxFile("filename", texturefilename, "file", "texture file path", gui, 2.0)
  3857         else:
  3858             bil = [i.filename for i in Image.Get() if '.' in i.filename]
  3859             try:
  3860                 uti = [i.filename for i in Image.Get() if '.' not in i.filename]
  3861                 if len(uti) > 0:
  3862                     luxLabel("INFO: Images not listed here must be saved first", gui)
  3863             except: pass    
  3864             if len(bil) > 0:
  3865                 luxOption("Image", texturefilename, bil, "Blender Images", "Blender Image", gui, 2.0)
  3866             else:
  3867                 luxLabel("No Blender Images - Load Image in the Image Editor", gui)
  3868         # dougal2 image file packing
  3869         impack = luxProp(Scene.GetCurrent(), 'packtextures', 'false')
  3870         
  3871         if impack.get() == 'false':
  3872             str += luxFile("filename", texturefilename, "file", "texture file path", None, 2.0)
  3873         else:
  3874             import zlib, base64
  3875             def get_image_data(filename):
  3876                 try:
  3877                     f=open(filename,'rb')
  3878                     d=f.read()
  3879                     f.close()
  3880                 except:
  3881                     print('Error reading image data from %s' % filename)
  3882                     d = ''
  3883                 return base64.b64encode(zlib.compress(d))
  3884             imdata = get_image_data(texturefilename.get())
  3885             str += '\r\n   "string imagedata" ["%s"]' % imdata
  3886         
  3887         useseq = luxProp(mat, keyname+".useseq", "false")
  3888         luxCollapse("usesew", useseq, "Sequence", "", gui, 2.0)
  3889     
  3890         if useseq.get() == "true":
  3891             seqframes = luxProp(mat, keyname+".seqframes", 100)
  3892             luxInt("frames", seqframes, 1, 100000, "Frames", "", gui, 0.5)
  3893             seqoffset = luxProp(mat, keyname+".seqoffset", 0)
  3894             luxInt("offset", seqoffset, 0, 100000, "Offset", "", gui, 0.5)
  3895             seqstartframe = luxProp(mat, keyname+".seqsframe", 1)
  3896             luxInt("startframe", seqstartframe, 1, 100000, "StartFr", "", gui, 0.5)
  3897             seqcyclic = luxProp(mat, keyname+".seqcycl", "false")
  3898             luxBool("cyclic", seqcyclic, "Cyclic", "", gui, 0.5)
  3899     
  3900             
  3901             totalframes = seqframes.get()
  3902             currentframe = Blender.Get('curframe')
  3903     
  3904             if(currentframe < seqstartframe.get()):
  3905                 fnumber = 1 + seqoffset.get()
  3906             else:
  3907                 fnumber = (currentframe - (seqstartframe.get()-1)) + seqoffset.get()
  3908     
  3909             if(fnumber > seqframes.get()):
  3910                 if(seqcyclic.get() == "false"):
  3911                     fnumber = seqframes.get()
  3912                 else:
  3913                     fnumber = currentframe % seqframes.get()
  3914     
  3915             import re
  3916             def get_seq_filename(number, filename):
  3917                 m = re.findall(r'(\d+)', filename)
  3918                 if len(m) == 0:
  3919                     return "ERR: Can't find pattern"
  3920     
  3921                 rightmost_number = m[len(m)-1]
  3922                 seq_length = len(rightmost_number)
  3923     
  3924                 nstr = "%i" %number
  3925                 new_seq_number = nstr.zfill(seq_length)
  3926      
  3927                 return filename.replace(rightmost_number, new_seq_number)
  3928      
  3929             texturefilename.set(get_seq_filename(fnumber, texturefilename.get()))
  3930             if gui: gui.newline()
  3931     
  3932         str += luxFloat("gamma", luxProp(mat, keyname+".gamma", texturegamma()), 0.0, 6.0, "gamma", "", gui, 0.75)
  3933         str += luxFloat("gain", luxProp(mat, keyname+".gain", 1.0), 0.0, 10.0, "gain", "", gui, 0.5)
  3934         filttype = luxProp(mat, keyname+".filtertype", "bilinear")
  3935         filttypes = ["mipmap_ewa","mipmap_trilinear","bilinear","nearest"]
  3936         str += luxOption("filtertype", filttype, filttypes, "filtertype", "Choose the filtering method to use for the image texture", gui, 0.75)
  3937         
  3938         if filttype.get() == "mipmap_ewa" or filttype.get() == "mipmap_trilinear":    
  3939             str += luxFloat("maxanisotropy", luxProp(mat, keyname+".maxanisotropy", 8.0), 1.0, 512.0, "maxaniso", "", gui, 1.0)
  3940             str += luxInt("discardmipmaps", luxProp(mat, keyname+".discardmipmaps", 0), 0, 1, "discardmips", "", gui, 1.0)
  3941     
  3942         str += luxMapping(keyname, mat, gui, level+1)
  3943 
  3944     if texture.get() == "mix":
  3945         (s, l) = c(("", ""), luxTexture("amount", keyname, "float", 0.5, 0.0, 1.0, "amount", "The degree of mix between the two textures", mat, gui, matlevel, texlevel+1, lightsource))
  3946         (s, l) = c((s, l), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  3947         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  3948         str = s + str + l
  3949 
  3950     if texture.get() == "scale":
  3951         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  3952         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  3953         str = s + str + l
  3954 
  3955     if texture.get() == "bilerp":
  3956         if type == "float":
  3957             str += luxFloat("v00", luxProp(mat, keyname+".v00", 0.0), min, max, "v00", "", gui, 1.0)
  3958             str += luxFloat("v01", luxProp(mat, keyname+".v01", 1.0), min, max, "v01", "", gui, 1.0)
  3959             if gui: gui.newline("", -2)
  3960             str += luxFloat("v10", luxProp(mat, keyname+".v10", 0.0), min, max, "v10", "", gui, 1.0)
  3961             str += luxFloat("v11", luxProp(mat, keyname+".v11", 1.0), min, max, "v11", "", gui, 1.0)
  3962         elif type == "color":
  3963             if gui: gui.newline("          v00:", -2)
  3964             str += luxRGB("v00", luxProp(mat, keyname+".v00", "0.0 0.0 0.0"), max, "v00", "", gui, 2.0)
  3965             if gui: gui.newline("          v01:", -2)
  3966             str += luxRGB("v01", luxProp(mat, keyname+".v01", "1.0 1.0 1.0"), max, "v01", "", gui, 2.0)
  3967             if gui: gui.newline("          v10:", -2)
  3968             str += luxRGB("v10", luxProp(mat, keyname+".v10", "0.0 0.0 0.0"), max, "v10", "", gui, 2.0)
  3969             if gui: gui.newline("          v11:", -2)
  3970             str += luxRGB("v11", luxProp(mat, keyname+".v11", "1.0 1.0 1.0"), max, "v11", "", gui, 2.0)
  3971         str += luxMapping(keyname, mat, gui, level+1)
  3972 
  3973     if texture.get() == "windy":
  3974         str += lux3DMapping(keyname, mat, gui, level+1)
  3975         # this texture has no options 
  3976 
  3977     if texture.get() == "checkerboard":
  3978         dim = luxProp(mat, keyname+".dim", 2)
  3979         str += luxInt("dimension", dim, 2, 3, "dim", "", gui, 1)
  3980         if dim.get() == 2: str += luxOption("aamode", luxProp(mat, keyname+".aamode", "closedform"), ["closedform","supersample","none"], "aamode", "antialiasing mode", gui, 0.6)
  3981         if gui: gui.newline("", -2)
  3982         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  3983         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  3984         str = s + str + l
  3985         if dim.get() == 2: str += luxMapping(keyname, mat, gui, level+1) 
  3986         if dim.get() == 3: str += lux3DMapping(keyname, mat, gui, level+1)
  3987 
  3988     if texture.get() == "dots":
  3989         (s, l) = c(("", ""), luxTexture("inside", keyname, type, default, min, max, "inside", "", mat, gui, matlevel, texlevel+1, lightsource))
  3990         (s, l) = c((s, l), luxTexture("outside", keyname, type, alternativedefault(type, default), min, max, "outside", "", mat, gui, matlevel, texlevel+1, lightsource))
  3991         str = s + str + l
  3992         str += luxMapping(keyname, mat, gui, level+1)
  3993 
  3994     if texture.get() == "fbm":
  3995         str += luxInt("octaves", luxProp(mat, keyname+".octaves", 8), 1, 100, "octaves", "", gui, 1)
  3996         # if gui: gui.newline("", -2)
  3997         str += luxFloat("roughness", luxProp(mat, keyname+".roughness", 0.5), 0.0, 1.0, "roughness", "", gui, 1, 1)
  3998         if gui: gui.newline("", -2)
  3999         str += lux3DMapping(keyname, mat, gui, level+1)
  4000 
  4001     if texture.get() == "marble":
  4002         str += luxInt("octaves", luxProp(mat, keyname+".octaves", 8), 1, 100, "octaves", "", gui, 1)
  4003         # if gui: gui.newline("", -2)
  4004         str += luxFloat("roughness", luxProp(mat, keyname+".roughness", 0.5), 0.0, 1.0, "roughness", "", gui, 1, 1)
  4005         if gui: gui.newline("", -2)
  4006         str += luxFloat("nscale", luxProp(mat, keyname+".nscale", 1.0), 0.0, 100.0, "nscale", "Scaling factor for the noise input", gui, 1.0)
  4007         str += luxFloat("variation", luxProp(mat, keyname+".variation", 0.2), 0.0, 100.0, "variation", "A scaling factor for the noise input function", gui, 1.0)
  4008         if gui: gui.newline("", -2)
  4009         str += lux3DMapping(keyname, mat, gui, level+1)
  4010 
  4011     if texture.get() == "wrinkled":
  4012         str += luxInt("octaves", luxProp(mat, keyname+".octaves", 8), 1, 100, "octaves", "", gui, 1)
  4013         # if gui: gui.newline("", -2)
  4014         str += luxFloat("roughness", luxProp(mat, keyname+".roughness", 0.5), 0.0, 1.0, "roughness", "", gui, 1, 1)
  4015         if gui: gui.newline("", -2)
  4016         str += lux3DMapping(keyname, mat, gui, level+1)
  4017 
  4018     if texture.get() == "brick":
  4019         if gui: gui.newline("brick:", -2, level+1, icon_texparam)
  4020 
  4021         str += luxFloat("brickwidth", luxProp(mat, keyname+".brickwidth", 0.3), 0.0, 10.0, "brickwidth (X)", "", gui, 1.0)
  4022         str += luxFloat("brickheight", luxProp(mat, keyname+".brickheight", 0.1), 0.0, 10.0, "brickheight (Z)", "", gui, 1.0)
  4023         str += luxFloat("brickdepth", luxProp(mat, keyname+".brickdepth", 0.15), 0.0, 10.0, "brickdepth (Y)", "", gui, 1.0)
  4024 
  4025         if gui: gui.newline("mortar:", -2, level+1, icon_texparam)
  4026 
  4027         str += luxFloat("mortarsize", luxProp(mat, keyname+".mortarsize", 0.01), 0.0, 1.0, "mortarsize", "", gui, 1.0)
  4028 
  4029         (s, l) = c(("", ""), luxTexture("bricktex", keyname, type, default, min, max, "bricktex", "", mat, gui, matlevel, texlevel+1, lightsource))
  4030         (s, l) = c((s, l), luxTexture("mortartex", keyname, type, alternativedefault(type, default), min, max, "mortartex", "", mat, gui, matlevel, texlevel+1, lightsource))
  4031         str = s + str + l
  4032 
  4033         str += lux3DMapping(keyname, mat, gui, level+1)
  4034 
  4035     if texture.get() == "blender_marble":
  4036         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4037 
  4038         mtype = luxProp(mat, keyname+".mtype", "soft")
  4039         mtypes = ["soft","sharp","sharper"]
  4040         str += luxOption("type", mtype, mtypes, "type", "", gui, 0.5)
  4041 
  4042         noisetype = luxProp(mat, keyname+".noisetype", "hard_noise")
  4043         noisetypes = ["soft_noise","hard_noise"]
  4044         str += luxOption("noisetype", noisetype, noisetypes, "noisetypes", "", gui, 0.75)
  4045 
  4046         str += luxInt("noisedepth", luxProp(mat, keyname+".noisedepth", 2), 0, 6, "noisedepth", "", gui, 0.75)
  4047 
  4048         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4049         str += luxFloat("turbulance", luxProp(mat, keyname+".turbulance", 5.0), 0.0, 200.0, "turbulance", "", gui, 1.0)
  4050 
  4051         if gui: gui.newline("basis:", -2, level+1, icon_texparam)
  4052         noisebasis2 = luxProp(mat, keyname+".noisebasis2", "sin")
  4053         noisebasises2 = ["sin","saw","tri"]
  4054         str += luxOption("noisebasis2", noisebasis2, noisebasises2, "noisebasis2", "", gui, 0.7)
  4055 
  4056         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4057         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4058         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 1.3)
  4059 
  4060         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4061         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4062         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4063 
  4064         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4065         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4066         str = s + str + l
  4067 
  4068         str += lux3DMapping(keyname, mat, gui, level+1)
  4069 
  4070     if texture.get() == "blender_musgrave":
  4071         if gui: gui.newline("type:", -2, level+1, icon_texparam)
  4072         mtype = luxProp(mat, keyname+".mtype", "multifractal")
  4073         mtypes = ["multifractal","ridged_multifractal", "hybrid_multifractal", "hetero_terrain", "fbm"]
  4074         str += luxOption("type", mtype, mtypes, "type", "", gui, 2.0)
  4075 
  4076         str += luxFloat("h", luxProp(mat, keyname+".h", 1.0), 0.0, 2.0, "h", "", gui, 0.5)
  4077         str += luxFloat("lacu", luxProp(mat, keyname+".lacu", 2.0), 0.0, 6.0, "lacu", "", gui, 0.75)
  4078         str += luxFloat("octs", luxProp(mat, keyname+".octs", 2.0), 0.0, 8.0, "octs", "", gui, 0.75)
  4079 
  4080         if mtype.get() == "hetero_terrain":
  4081             str += luxFloat("offset", luxProp(mat, keyname+".offset", 2.0), 0.0, 6.0, "offset", "", gui, 2.0)
  4082         if mtype.get() == "ridged_multifractal":
  4083             str += luxFloat("offset", luxProp(mat, keyname+".offset", 2.0), 0.0, 6.0, "offset", "", gui, 1.25)
  4084             str += luxFloat("gain", luxProp(mat, keyname+".gain", 2.0), 0.0, 6.0, "gain", "", gui, 0.75)
  4085         if mtype.get() == "hybrid_multifractal":
  4086             str += luxFloat("offset", luxProp(mat, keyname+".offset", 2.0), 0.0, 6.0, "offset", "", gui, 1.25)
  4087             str += luxFloat("gain", luxProp(mat, keyname+".gain", 2.0), 0.0, 6.0, "gain", "", gui, 0.75)
  4088 
  4089         str += luxFloat("outscale", luxProp(mat, keyname+".outscale", 1.0), 0.0, 10.0, "iscale", "", gui, 1.0)
  4090         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4091 
  4092         if gui: gui.newline("basis:", -2, level+1, icon_texparam)
  4093         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4094         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4095         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 2.0)
  4096 
  4097         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4098         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4099         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4100 
  4101         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4102         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4103         str = s + str + l
  4104 
  4105         str += lux3DMapping(keyname, mat, gui, level+1)
  4106 
  4107     if texture.get() == "blender_wood":
  4108         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4109 
  4110         mtype = luxProp(mat, keyname+".mtype", "bands")
  4111         mtypes = ["bands","rings","bandnoise", "ringnoise"]
  4112         str += luxOption("type", mtype, mtypes, "type", "", gui, 0.5)
  4113 
  4114         noisetype = luxProp(mat, keyname+".noisetype", "hard_noise")
  4115         noisetypes = ["soft_noise","hard_noise"]
  4116         str += luxOption("noisetype", noisetype, noisetypes, "noisetypes", "", gui, 0.75)
  4117 
  4118         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4119         str += luxFloat("turbulance", luxProp(mat, keyname+".turbulance", 5.0), 0.0, 200.0, "turbulance", "", gui, 1.0)
  4120 
  4121         if gui: gui.newline("basis:", -2, level+1, icon_texparam)
  4122         noisebasis2 = luxProp(mat, keyname+".noisebasis2", "sin")
  4123         noisebasises2 = ["sin","saw","tri"]
  4124         str += luxOption("noisebasis2", noisebasis2, noisebasises2, "noisebasis2", "", gui, 0.7)
  4125 
  4126         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4127         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4128         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 1.3)
  4129 
  4130         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4131         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4132         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4133 
  4134         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4135         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4136         str = s + str + l
  4137     
  4138         str += lux3DMapping(keyname, mat, gui, level+1)
  4139 
  4140     if texture.get() == "blender_clouds":
  4141         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4142 
  4143         mtype = luxProp(mat, keyname+".mtype", "default")
  4144         mtypes = ["default","color"]
  4145         str += luxOption("type", mtype, mtypes, "type", "", gui, 0.5)
  4146 
  4147         noisetype = luxProp(mat, keyname+".noisetype", "hard_noise")
  4148         noisetypes = ["soft_noise","hard_noise"]
  4149         str += luxOption("noisetype", noisetype, noisetypes, "noisetypes", "", gui, 0.75)
  4150 
  4151         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4152         str += luxInt("noisedepth", luxProp(mat, keyname+".noisedepth", 2), 0, 6, "noisedepth", "", gui, 1.0)
  4153 
  4154         if gui: gui.newline("basis:", -2, level+1, icon_texparam)
  4155         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4156         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4157         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 1.3)
  4158 
  4159         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4160         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4161         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4162 
  4163         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4164         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4165         str = s + str + l
  4166     
  4167         str += lux3DMapping(keyname, mat, gui, level+1)
  4168 
  4169     if texture.get() == "blender_blend":
  4170         if gui: gui.newline("type:", -2, level+1, icon_texparam)
  4171 
  4172         mtype = luxProp(mat, keyname+".mtype", "lin")
  4173         mtypes = ["lin","quad","ease","diag","sphere","halo","radial"]
  4174         str += luxOption("type", mtype, mtypes, "type", "", gui, 0.5)
  4175         
  4176         mflag = luxProp(mat, keyname+".flag", "false")
  4177         str += luxBool("flipxy", mflag, "flipXY", "", gui, 0.5)
  4178 
  4179         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4180         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4181         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4182 
  4183         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4184         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4185         str = s + str + l
  4186         
  4187         str += lux3DMapping(keyname, mat, gui, level+1)
  4188 
  4189     if texture.get() == "blender_distortednoise":
  4190         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4191         
  4192         str += luxFloat("distamount", luxProp(mat, keyname+".distamount", 1.0), 0.0, 10.0, "distamount", "", gui, 1.0)
  4193         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4194         str += luxFloat("nabla", luxProp(mat, keyname+".nabla", 0.025), 0.000, 2.0, "nabla", "", gui, 1.0)
  4195         
  4196         if gui: gui.newline("distortion:", -2, level+1, icon_texparam)
  4197         ntype = luxProp(mat, keyname+".type", "blender_original")
  4198         ntypes = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4199         str += luxOption("type", ntype, ntypes, "type", "", gui, 1.3)
  4200         
  4201         if gui: gui.newline("basis:", -2, level+1, icon_texparam)
  4202         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4203         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4204         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 1.3)
  4205 
  4206         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4207         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4208         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4209 
  4210         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4211         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4212         str = s + str + l
  4213         
  4214         str += lux3DMapping(keyname, mat, gui, level+1)
  4215 
  4216     if texture.get() == "blender_noise":        
  4217         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4218         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4219         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4220 
  4221         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4222         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4223         str = s + str + l
  4224         
  4225         str += lux3DMapping(keyname, mat, gui, level+1)
  4226         
  4227     if texture.get() == "blender_magic":
  4228         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4229         
  4230         str += luxInt("noisedepth", luxProp(mat, keyname+".noisedepth", 2), 0.0, 10.0, "noisedepth", "", gui, 1.0)
  4231         str += luxFloat("turbulance", luxProp(mat, keyname+".turbulance", 5.0), 0.0, 2.0, "turbulance", "", gui, 1.0)
  4232 
  4233         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4234         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4235         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4236 
  4237         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4238         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4239         str = s + str + l
  4240         
  4241         str += lux3DMapping(keyname, mat, gui, level+1)
  4242         
  4243     if texture.get() == "blender_stucci":
  4244         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4245         mtype = luxProp(mat, keyname+".mtype", "Plastic")
  4246         mtypes = ["Plastic","Wall In","Wall Out"]
  4247         str += luxOption("type", mtype, mtypes, "type", "", gui, 0.5)
  4248 
  4249         noisetype = luxProp(mat, keyname+".noisetype", "soft_noise")
  4250         noisetypes = ["soft_noise","hard_noise"]
  4251         str += luxOption("noisetype", noisetype, noisetypes, "noisetypes", "", gui, 0.75)
  4252         
  4253         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 10.0, "noisesize", "", gui, 1.0)
  4254         str += luxFloat("turbulance", luxProp(mat, keyname+".turbulance", 5.0), 0.0, 200.0, "turbulance", "", gui, 1.0)
  4255 
  4256         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4257         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4258         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 1.3)
  4259 
  4260         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4261         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4262         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4263 
  4264         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4265         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4266         str = s + str + l
  4267 
  4268         str += lux3DMapping(keyname, mat, gui, level+1)
  4269 
  4270     if texture.get() == "blender_voronoi":
  4271         #if gui: gui.newline("distmetric:", -2, level+1, icon_texparam)
  4272         mtype = luxProp(mat, keyname+".distmetric", "actual_distance")
  4273         mtypes = ["actual_distance","distance_squared","manhattan", "chebychev", "minkovsky_half", "minkovsky_four", "minkovsky"]
  4274         str += luxOption("distmetric", mtype, mtypes, "distmetric", "", gui, 1.1)
  4275 
  4276         if gui: gui.newline("param:", -2, level+1, icon_texparam)
  4277         str += luxFloat("minkovsky_exp", luxProp(mat, keyname+".minkovsky_exp", 2.5), 0.001, 10.0, "minkovsky_exp", "", gui, 1.0)
  4278         str += luxFloat("outscale", luxProp(mat, keyname+".outscale", 1.0), 0.01, 10.0, "outscale", "", gui, 1.0)
  4279         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4280         str += luxFloat("nabla", luxProp(mat, keyname+".nabla", 0.025), 0.001, 0.1, "nabla", "", gui, 1.0)
  4281         if gui: gui.newline("wparam:", -2, level+1, icon_texparam)
  4282         str += luxFloat("w1", luxProp(mat, keyname+".w1", 1.0), -2.0, 2.0, "w1", "", gui, 1.0)
  4283         str += luxFloat("w2", luxProp(mat, keyname+".w2", 0.0), -2.0, 2.0, "w2", "", gui, 1.0)
  4284         str += luxFloat("w3", luxProp(mat, keyname+".w3", 0.0), -2.0, 2.0, "w3", "", gui, 1.0)
  4285         str += luxFloat("w4", luxProp(mat, keyname+".w4", 0.0), -2.0, 2.0, "w4", "", gui, 1.0)
  4286 
  4287         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4288         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4289         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4290 
  4291         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4292         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4293         str = s + str + l
  4294 
  4295         str += lux3DMapping(keyname, mat, gui, level+1)
  4296 
  4297 
  4298 
  4299     return (str+"\n", " \"texture %s\" [\"%s\"]"%(name, texname))
  4300 
  4301 
  4302 def luxSpectrumTexture(name, key, default, max, caption, hint, mat, gui, level=0):
  4303     global icon_col
  4304     if gui: gui.newline(caption, 4, level, icon_col, scalelist([0.5,0.6,0.5],2.0/(level+2)))
  4305     str = ""
  4306     keyname = "%s:%s"%(key, name)
  4307     texname = "%s:%s"%(mat.getName(), keyname)
  4308     value = luxProp(mat, keyname, default)
  4309     link = luxRGB(name, value, max, "", hint, gui, 2.0)
  4310     tex = luxProp(mat, keyname+".textured", False)
  4311     if gui: Draw.Toggle("T", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, tex.get()=="true", "use texture", lambda e,v:tex.set(["false","true"][bool(v)]))
  4312     if tex.get()=="true":
  4313         if gui: gui.newline("", -2)
  4314         (str, link) = luxTexture(name, key, "color", default, 0, max, caption, hint, mat, gui, level+1)
  4315         if value.getRGB() != (1.0, 1.0, 1.0):
  4316             if str == "": # handle special case if texture is a just a constant
  4317                 str += "Texture \"%s\" \"color\" \"scale\" \"color tex1\" [%s] \"color tex2\" [%s]\n"%(texname+".scale", (link.rpartition("[")[2])[0:-1], value.get())
  4318             else: str += "Texture \"%s\" \"color\" \"scale\" \"texture tex1\" [\"%s\"] \"color tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4319             link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4320     return (str, link)
  4321 
  4322 def luxLightSpectrumTexture(name, key, default, max, caption, hint, mat, gui, level=0):
  4323     #if gui: gui.newline(caption, 4, level, icon_emission, scalelist([0.6,0.5,0.5],2.0/(level+2)))
  4324     str = ""
  4325     keyname = "%s:%s"%(key, name)
  4326     texname = "%s:%s"%(mat.getName(), keyname)
  4327     (str, link) = luxTexture(name, key, "color", default, 0, max, caption, hint, mat, gui, level+1, 0, 1)
  4328     return (str, link)
  4329 
  4330 def luxFloatTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4331     global icon_float
  4332     if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4333     str = ""
  4334     keyname = "%s:%s"%(key, name)
  4335     texname = "%s:%s"%(mat.getName(), keyname)
  4336     value = luxProp(mat, keyname, default)
  4337     link = luxFloat(name, value, min, max, "", hint, gui, 2.0)
  4338     tex = luxProp(mat, keyname+".textured", False)
  4339     if gui: Draw.Toggle("T", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, tex.get()=="true", "use texture", lambda e,v:tex.set(["false","true"][bool(v)]))
  4340     if tex.get()=="true":
  4341         if gui: gui.newline("", -2)
  4342         (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4343         if value.get() != 1.0:
  4344             if str == "": # handle special case if texture is a just a constant
  4345                 str += "Texture \"%s\" \"float\" \"scale\" \"float tex1\" [%s] \"float tex2\" [%s]\n"%(texname+".scale", (link.rpartition("[")[2])[0:-1], value.get())
  4346             else: str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4347             link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4348     return (str, link)
  4349 
  4350 def luxFloatSliderTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4351         global icon_float
  4352         if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4353         str = ""
  4354         keyname = "%s:%s"%(key, name)
  4355         texname = "%s:%s"%(mat.getName(), keyname)
  4356         value = luxProp(mat, keyname, default)
  4357         link = luxFloat(name, value, min, max, caption, hint, gui, 2.0, 1)
  4358         tex = luxProp(mat, keyname+".textured", False)
  4359         if gui: Draw.Toggle("T", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, tex.get()=="true", "use texture", lambda e,v:tex.set(["false","true"][bool(v)]))
  4360         if tex.get()=="true":
  4361                 if gui: gui.newline("", -2)
  4362                 (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4363                 if value.get() != 1.0:
  4364                         if str == "": # handle special case if texture is a just a constant
  4365                                 str += "Texture \"%s\" \"float\" \"scale\" \"float tex1\" [%s] \"float tex2\" [%s]\n"%(texname+".scale", (link.rpartition("[")[2])[0:-1], value.get())
  4366                         else: str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4367                         link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4368         return (str, link)
  4369 
  4370 
  4371 def luxExponentTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4372     global icon_float
  4373     if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4374     str = ""
  4375     keyname = "%s:%s"%(key, name)
  4376     texname = "%s:%s"%(mat.getName(), keyname)
  4377     value = luxProp(mat, keyname, default)
  4378 
  4379     if(value.get() == None): value.set(0.002)
  4380 
  4381 #    link = luxFloat(name, value, min, max, "", hint, gui, 2.0)
  4382     if gui:
  4383         r = gui.getRect(2.0, 1)
  4384         Draw.Number("", evtLuxGui, r[0], r[1], r[2], r[3], float(1.0/value.getFloat()), 1.0, 1000000.0, hint, lambda e,v: value.set(1.0/v))
  4385     link = " \"float %s\" [%f]"%(name, value.getFloat())
  4386 
  4387     tex = luxProp(mat, keyname+".textured", False)
  4388     if gui: Draw.Toggle("T", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, tex.get()=="true", "use texture", lambda e,v:tex.set(["false","true"][bool(v)]))
  4389     if tex.get()=="true":
  4390         if gui: gui.newline("", -2)
  4391         (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4392         if value.get() != 1.0:
  4393             if str == "": # handle special case if texture is a just a constant
  4394                 str += "Texture \"%s\" \"float\" \"scale\" \"float tex1\" [%s] \"float tex2\" [%s]\n"%(texname+".scale", (link.rpartition("[")[2])[0:-1], value.get())
  4395             else: str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4396             link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4397     return (str, link)
  4398 
  4399 
  4400 def luxDispFloatTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4401     global icon_float
  4402     if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4403     str = ""
  4404     keyname = "%s:%s"%(key, name)
  4405     texname = "%s:%s"%(mat.getName(), keyname)
  4406     value = luxProp(mat, keyname, default)
  4407     link = luxFloat(name, value, min, max, "", hint, gui, 2.0)
  4408     tex = luxProp(mat, keyname+".textured", False)
  4409     if gui: Draw.Toggle("T", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, tex.get()=="true", "use texture", lambda e,v:tex.set(["false","true"][bool(v)]))
  4410     if tex.get()=="true":
  4411         if gui: gui.newline("", -2)
  4412         (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4413         str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4414         link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4415     return (str, link)
  4416 
  4417 def luxIORFloatTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4418     # IOR preset data
  4419     iornames = ["0Z *** Gases @ 0 C ***", "01 - Vacuum", "02 - Air @ STP", "03 - Air", "04 - Helium", "05 - Hydrogen", "06 - Carbon dioxide",
  4420     "1Z *** LIQUIDS @ 20 C ***", "11 - Benzene", "12 - Water", "13 - Ethyl alcohol", "14 - Carbon tetrachloride", "15 - Carbon disulfide", 
  4421     "2Z *** SOLIDS at room temperature ***", "21 - Diamond", "22 - Strontium titanate", "23 - Amber", "24 - Fused silica glass", "25 - sodium chloride", 
  4422     "3Z *** OTHER Materials ***", "31 - Pyrex (Borosilicate glass)", "32 - Ruby", "33 - Water ice", "34 - Cryolite", "35 - Acetone", "36 - Ethanol", "37 - Teflon", "38 - Glycerol", "39 - Acrylic glass", "40 - Rock salt", "41 - Crown glass (pure)", "42 - Salt (NaCl)", "43 - Polycarbonate", "44 - PMMA", "45 - PETg", "46 - PET", "47 - Flint glass (pure)", "48 - Crown glass (impure)", "49 - Fused Quartz", "50 - Bromine", "51 - Flint glass (impure)", "52 - Cubic zirconia", "53 - Moissanite", "54 - Cinnabar (Mercury sulfide)", "55 - Gallium(III) prosphide", "56 - Gallium(III) arsenide", "57 - Silicon"]
  4423     iorvals = [1.0, 1.0, 1.0002926, 1.000293, 1.000036, 1.000132, 1.00045,
  4424     1.501, 1.501, 1.333, 1.361, 1.461, 1.628,
  4425     2.419, 2.419, 2.41, 1.55, 1.458, 1.50,
  4426     1.470, 1.470, 1.760, 1.31, 1.388, 1.36, 1.36, 1.35, 1.4729, 1.490, 1.516, 1.50, 1.544, 1.584, 1.4893, 1.57, 1.575, 1.60, 1.485, 1.46, 1.661, 1.523, 2.15, 2.419, 2.65, 3.02, 3.5, 3.927, 4.01]
  4427 
  4428     global icon_float
  4429     if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4430     str = ""
  4431     keyname = "%s:%s"%(key, name)
  4432     texname = "%s:%s"%(mat.getName(), keyname)
  4433     value = luxProp(mat, keyname, default)
  4434 
  4435     iorusepreset = luxProp(mat, keyname+".iorusepreset", "true")
  4436     luxBool("iorusepreset", iorusepreset, "Preset", "Select from a list of predefined presets", gui, 0.4)
  4437 
  4438     if(iorusepreset.get() == "true"):
  4439         iorpreset = luxProp(mat, keyname+".iorpreset", "24 - Fused silica glass")
  4440         if gui:
  4441             def setIor(i, value, preset, tree, dict): # callback function to set ior value after selection                
  4442                 if i >= 0:
  4443                     value.set(dict[i])
  4444                     preset.set(getTreeNameById(tree, i))
  4445             iortree = [ ("Liquids", [("Acetone", 1), ("Alcohol, Ethyl (grain)", 2), ("Alcohol, Methyl (wood)", 3), ("Beer", 4), ("Benzene", 5), ("Carbon tetrachloride", 6), ("Carbon disulfide", 7), ("Carbonated Beverages", 8), ("Chlorine (liq)", 9), ("Cranberry Juice (25%)", 10), ("Glycerin", 11), ("Honey, 13% water content", 12), ("Honey, 17% water content", 13), ("Honey, 21% water content", 14), ("Ice", 15), ("Milk", 16), ("Oil, Clove", 17), ("Oil, Lemon", 18), ("Oil, Neroli", 19), ("Oil, Orange", 20), ("Oil, Safflower", 21), ("Oil, vegetable (50 C)", 22), ("Oil of Wintergreen", 23), ("Rum, White", 24), ("Shampoo", 25), ("Sugar Solution 30%", 26), ("Sugar Solution 80%", 27), ("Turpentine", 28), ("Vodka", 29), ("Water (0 C)", 30), ("Water (100 C)", 31), ("Water (20 C)", 32), ("Whisky", 33) ] ), ("Gases", [("Vacuum", 101), ("Air @ STP", 102), ("Air", 103), ("Helium", 104), ("Hydrogen", 105), ("Carbon dioxide", 106) ]), ("Transparent\x20", [("Eye, Aqueous humor", 201), ("Eye, Cornea", 202), ("Eye, Lens", 203), ("Eye, Vitreous humor", 204), ("Glass, Arsenic Trisulfide", 205), ("Glass, Crown (common)", 206), ("Glass, Flint, 29% lead", 207), ("Glass, Flint, 55% lead", 208), ("Glass, Flint, 71% lead", 209), ("Glass, Fused Silica", 210), ("Glass, Pyrex", 211), ("Lucite", 212), ("Nylon", 213), ("Obsidian", 214), ("Plastic", 215), ("Plexiglas", 216), ("Salt", 217)  ]), ("Gemstones", [("Agate", 301), ("Alexandrite", 302), ("Almandine", 303), ("Amber", 304), ("Amethyst", 305), ("Ammolite", 306), ("Andalusite", 307), ("Apatite", 308), ("Aquamarine", 309), ("Axenite", 310), ("Beryl", 311), ("Beryl, Red", 312), ("Chalcedony", 313), ("Chrome Tourmaline", 314), ("Citrine", 315), ("Clinohumite", 316), ("Coral", 317), ("Crystal", 318), ("Crysoberyl, Catseye", 319), ("Danburite", 320), ("Diamond", 321), ("Emerald", 322), ("Emerald Catseye", 323), ("Flourite", 324), ("Garnet, Grossular", 325), ("Garnet, Andradite", 326), ("Garnet, Demantiod", 327), ("Garnet, Mandarin", 328), ("Garnet, Pyrope", 329), ("Garnet, Rhodolite", 330), ("Garnet, Tsavorite", 331), ("Garnet, Uvarovite", 332), ("Hauyn", 333), ("Iolite", 334), ("Jade, Jadeite", 335), ("Jade, Nephrite", 336), ("Jet", 337), ("Kunzite", 338), ("Labradorite", 339), ("Lapis Lazuli", 340), ("Moonstone", 341), ("Morganite", 342), ("Obsidian", 343), ("Opal, Black", 344), ("Opal, Fire", 345), ("Opal, White", 346), ("Oregon Sunstone", 347), ("Padparadja", 348), ("Pearl", 349), ("Peridot", 350), ("Quartz", 351), ("Ruby", 352), ("Sapphire", 353), ("Sapphire, Star", 354), ("Spessarite", 355), ("Spinel", 356), ("Spinel, Blue", 357), ("Spinel, Red", 358), ("Star Ruby", 359), ("Tanzanite", 360), ("Topaz", 361), ("Topaz, Imperial", 362), ("Tourmaline", 363), ("Tourmaline, Blue", 364), ("Tourmaline, Catseye", 365), ("Tourmaline, Green", 366), ("Tourmaline, Paraiba", 367), ("Tourmaline, Red", 368), ("Zircon", 369), ("Zirconia, Cubic", 370) ] ), ("Other ", [("Pyrex (Borosilicate glass)", 401), ("Ruby", 402), ("Water ice", 403), ("Cryolite", 404), ("Acetone", 405), ("Ethanol", 406), ("Teflon", 407), ("Glycerol", 408), ("Acrylic glass", 409), ("Rock salt", 410), ("Crown glass (pure)", 411), ("Salt (NaCl)", 412), ("Polycarbonate", 413), ("PMMA", 414), ("PETg", 415), ("PET", 416), ("Flint glass (pure)", 417), ("Crown glass (impure)", 418), ("Fused Quartz", 419), ("Bromine", 420), ("Flint glass (impure)", 421), ("Cubic zirconia", 422), ("Moissanite", 423), ("Cinnabar (Mercury sulfide)", 424), ("Gallium(III) prosphide", 425), ("Gallium(III) arsenide", 426), ("Silicon", 427) ] ) ]
  4446             iordict = {1:1.36, 2:1.36, 3:1.329, 4:1.345, 5:1.501, 6:1.000132, 7:1.00045, 8:1.34, 9:1.385, 10:1.351, 11:1.473, 12:1.504, 13:1.494, 14:1.484, 15:1.309, 16:1.35, 17:1.535, 18:1.481, 19:1.482, 20:1.473, 21:1.466, 22:1.47, 23:1.536, 24:1.361, 25:1.362, 26:1.38, 27:1.49, 28:1.472, 29:1.363, 30:1.33346, 31:1.31766, 32:1.33283, 33:1.356, 101:1.0, 102:1.0002926, 103:1.000293, 104:1.000036, 105:1.000132, 106:1.00045, 201:1.33, 202:1.38, 203:1.41, 204:1.34, 205:2.04, 206:1.52, 207:1.569, 208:1.669, 209:1.805, 210:1.459, 211:1.474, 212:1.495, 213:1.53, 214:1.50, 215:1.460, 216:1.488, 217:1.516, 301:1.544, 302:1.746, 303:1.75, 304:1.539, 305:1.532, 306:1.52, 307:1.629, 308:1.632, 309:1.567, 310:1.674, 311:1.57, 312:1.570, 313:1.544, 314:1.61, 315:1.532, 316:1.625, 317:1.486, 318:2.000, 319:1.746, 320:1.627, 321:2.417, 322:1.560, 323:1.560, 324:1.434, 325:1.72, 326:1.88, 327:1.880, 328:1.790, 329:1.73, 330:1.740, 331:1.739, 332:1.74, 333:1.490, 334:1.522, 335:1.64, 336:1.600, 337:1.660, 338:1.660, 339:1.560, 340:1.50, 341:1.518, 342:1.585, 343:1.50, 344:1.440, 345:1.430, 346:1.440, 347:1.560, 348:1.760, 349:1.53, 350:1.635, 351:1.544, 352:1.757, 353:1.757, 354:1.760, 355:1.79, 356:1.712, 357:1.712, 358:1.708, 359:1.76, 360:1.690, 361:1.607, 362:1.605, 363:1.603, 364:1.61, 365:1.61, 366:1.61, 367:1.61, 368:1.61, 369:1.777, 370:2.173, 401:1.47, 402:1.76, 403:1.31, 404:1.388, 405:1.36, 406:1.36, 407:1.35, 408:1.4729, 409:1.49, 410:1.516, 411:1.5, 412:1.544, 413:1.584, 414:1.4893, 415:1.57, 416:1.575, 417:1.6, 418:1.485, 419:1.46, 420:1.661, 421:1.523, 422:2.15, 423:2.419, 424:2.65, 425:3.02, 426:3.5, 427:3.927}
  4447             r = gui.getRect(1.6, 1)
  4448             Draw.Button(iorpreset.get(), evtLuxGui, r[0], r[1], r[2], r[3], "select IOR preset", lambda e,v: setIor(Draw.PupTreeMenu(iortree), value, iorpreset, iortree, iordict))
  4449         link = luxFloat(name, value, min, max, "IOR", hint, None, 1.6)
  4450     else:
  4451         link = luxFloat(name, value, min, max, "IOR", hint, gui, 1.6, 1)
  4452 
  4453     tex = luxProp(mat, keyname+".textured", False)
  4454     if gui: Draw.Toggle("T", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, tex.get()=="true", "use texture", lambda e,v:tex.set(["false","true"][bool(v)]))
  4455     if tex.get()=="true":
  4456         if gui: gui.newline("", -2)
  4457         (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4458         if value.get() != 1.0:
  4459             str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4460             link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4461     return (str, link)
  4462 
  4463 def luxCauchyBFloatTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4464     # IOR preset data
  4465     cauchybnames = ["01 - Fused silica glass", "02 - Borosilicate glass BK7", "03 - Hard crown glass K5", "04 - Barium crown glass BaK4", "05 - Barium flint glass BaF10", "06 - Dense flint glass SF10" ]
  4466     cauchybvals = [ 0.00354, 0.00420, 0.00459, 0.00531, 0.00743, 0.01342 ]
  4467 
  4468     global icon_float
  4469     if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4470     str = ""
  4471     keyname = "%s:%s"%(key, name)
  4472     texname = "%s:%s"%(mat.getName(), keyname)
  4473     value = luxProp(mat, keyname, default)
  4474 
  4475     cauchybusepreset = luxProp(mat, keyname+".cauchybusepreset", "true")
  4476     luxBool("cauchybusepreset", cauchybusepreset, "Preset", "Select from a list of predefined presets", gui, 0.4)
  4477 
  4478     if(cauchybusepreset.get() == "true"):
  4479         cauchybpreset = luxProp(mat, keyname+".cauchybpreset", "01 - Fused silica glass")
  4480         luxOption("cauchybpreset", cauchybpreset, cauchybnames, "  PRESET", "select CauchyB preset", gui, 1.6)
  4481         idx = cauchybnames.index(cauchybpreset.get())
  4482         value.set(cauchybvals[idx])
  4483         link = luxFloat(name, value, min, max, "cauchyb", hint, None, 1.6)
  4484     else:
  4485         link = luxFloat(name, value, min, max, "cauchyb", hint, gui, 1.6, 1)
  4486 
  4487     tex = luxProp(mat, keyname+".textured", False)
  4488     if gui: Draw.Toggle("T", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, tex.get()=="true", "use texture", lambda e,v:tex.set(["false","true"][bool(v)]))
  4489     if tex.get()=="true":
  4490         if gui: gui.newline("", -2)
  4491         (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4492         if value.get() != 1.0:
  4493             str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4494             link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4495     return (str, link)
  4496 
  4497 def luxLight(name, kn, mat, gui, level):
  4498     if gui:
  4499         if name != "": gui.newline(name+":", 10, level)
  4500         else: gui.newline("color:", 0, level+1)
  4501     (str,link) = luxLightSpectrumTexture("L", kn+"light", "1.0 1.0 1.0", 1.0, "Spectrum", "", mat, gui, level+1)
  4502     if gui: gui.newline("")
  4503     link += luxFloat("power", luxProp(mat, kn+"light.power", 100.0), 0.0, 10000.0, "Power(W)", "AreaLight Power in Watts", gui)
  4504     link += luxFloat("efficacy", luxProp(mat, kn+"light.efficacy", 17.0), 0.0, 100.0, "Efficacy(lm/W)", "Efficacy Luminous flux/watt", gui)
  4505     if gui: gui.newline("")
  4506     link += luxFloat("gain", luxProp(mat, kn+"light.gain", 1.0), 0.0, 100.0, "gain", "Gain/scale multiplier", gui)
  4507     lightgroup = luxProp(mat, kn+"light.lightgroup", "default")
  4508     luxString("lightgroup", lightgroup, "group", "assign light to a named light-group", gui, 1.0)
  4509 
  4510     if gui: gui.newline("Photometric")
  4511     pm = luxProp(mat, kn+"light.usepm", "false")
  4512     luxCollapse("photometric", pm, "Photometric Diagram", "Enable Photometric Diagram options", gui, 2.0)
  4513 
  4514     if(pm.get()=="true"):
  4515         pmtype = luxProp(mat, kn+"light.pmtype", "IESna")
  4516         pmtypes = ["IESna", "imagemap"]
  4517         luxOption("type", pmtype, pmtypes, "type", "Choose Photometric data type to use", gui, 0.6)
  4518         if(pmtype.get() == "imagemap"):
  4519             map = luxProp(mat, kn+"light.pmmapname", "")
  4520             link += luxFile("mapname", map, "map-file", "filename of the photometric map", gui, 1.4)
  4521         if(pmtype.get() == "IESna"):
  4522             map = luxProp(mat, kn+"light.pmiesname", "")
  4523             link += luxFile("iesname", map, "ies-file", "filename of the IES photometric data file", gui, 1.4)
  4524 
  4525     has_bump_options = 0
  4526     has_object_options = 1
  4527     return (str, link)
  4528 
  4529 def luxLamp(name, kn, mat, gui, level):
  4530     if gui:
  4531         if name != "": gui.newline(name+":", 10, level)
  4532         else: gui.newline("color:", 0, level+1)
  4533 #    if gui: gui.newline("", 10, level)
  4534     (str,link) = luxLightSpectrumTexture("L", kn+"light", "1.0 1.0 1.0", 1.0, "Spectrum", "", mat, gui, level+1)
  4535     if gui: gui.newline("")
  4536     link += luxFloat("gain", luxProp(mat, kn+"light.gain", 1.0), 0.0, 100.0, "gain", "Gain/scale multiplier", gui)
  4537     lightgroup = luxProp(mat, kn+"light.lightgroup", "default")
  4538     luxString("lightgroup", lightgroup, "group", "assign light to a named light-group", gui, 1.0)
  4539 
  4540     if gui: gui.newline("Photometric")
  4541     pm = luxProp(mat, kn+"light.usepm", "false")
  4542     luxBool("photometric", pm, "Photometric Diagram", "Enable Photometric Diagram options", gui, 2.0)
  4543 
  4544     if(pm.get()=="true"):
  4545         pmtype = luxProp(mat, kn+"light.pmtype", "IESna")
  4546         pmtypes = ["IESna", "imagemap"]
  4547         luxOption("type", pmtype, pmtypes, "type", "Choose Photometric data type to use", gui, 0.6)
  4548         if(pmtype.get() == "imagemap"):
  4549             map = luxProp(mat, kn+"light.pmmapname", "")
  4550             link += luxFile("mapname", map, "map-file", "filename of the photometric map", gui, 1.4)
  4551         if(pmtype.get() == "IESna"):
  4552             map = luxProp(mat, kn+"light.pmiesname", "")
  4553             link += luxFile("iesname", map, "ies-file", "filename of the IES photometric data file", gui, 1.4)
  4554 
  4555         link += luxBool("flipz", luxProp(mat, kn+"light.flipZ", "true"), "Flip Z", "Flip Z direction in mapping", gui, 2.0)
  4556 
  4557     return (str, link)
  4558 
  4559 def luxSpot(name, kn, mat, gui, level):
  4560     if gui:
  4561         if name != "": gui.newline(name+":", 10, level)
  4562         else: gui.newline("color:", 0, level+1)
  4563 #    if gui: gui.newline("", 10, level)
  4564     (str,link) = luxLightSpectrumTexture("L", kn+"light", "1.0 1.0 1.0", 1.0, "Spectrum", "", mat, gui, level+1)
  4565     if gui: gui.newline("")
  4566     link += luxFloat("gain", luxProp(mat, kn+"light.gain", 1.0), 0.0, 100.0, "gain", "Gain/scale multiplier", gui)
  4567     lightgroup = luxProp(mat, kn+"light.lightgroup", "default")
  4568     luxString("lightgroup", lightgroup, "group", "assign light to a named light-group", gui, 1.0)
  4569 
  4570     if gui: gui.newline("Projection")
  4571     proj = luxProp(mat, kn+"light.usetexproj", "false")
  4572     luxBool("projection", proj, "Texture Projection", "Enable imagemap texture projection", gui, 2.0)
  4573 
  4574     if(proj.get() == "true"):
  4575         map = luxProp(mat, kn+"light.pmmapname", "")
  4576         link += luxFile("mapname", map, "map-file", "filename of the photometric map", gui, 2.0)
  4577 
  4578     return (str, link)
  4579 
  4580 
  4581 def Preview_Sphereset(mat, kn, state):
  4582     if state=="true":
  4583         luxProp(mat, kn+"prev_sphere", "true").set("true")
  4584         luxProp(mat, kn+"prev_plane", "false").set("false")
  4585         luxProp(mat, kn+"prev_torus", "false").set("false")
  4586 def Preview_Planeset(mat, kn, state):
  4587     if state=="true":
  4588         luxProp(mat, kn+"prev_sphere", "true").set("false")
  4589         luxProp(mat, kn+"prev_plane", "false").set("true")
  4590         luxProp(mat, kn+"prev_torus", "false").set("false")
  4591 def Preview_Torusset(mat, kn, state):
  4592     if state=="true":
  4593         luxProp(mat, kn+"prev_sphere", "true").set("false")
  4594         luxProp(mat, kn+"prev_plane", "false").set("false")
  4595         luxProp(mat, kn+"prev_torus", "false").set("true")
  4596 
  4597 
  4598     
  4599 
  4600 def Preview_Update(mat, kn, defLarge, defType, texName, name, level):
  4601     #print("%s %s %s %s %s %s %s" % (mat, kn, defLarge, defType, texName, name, level))
  4602 
  4603     global previewing
  4604     previewing = True
  4605     
  4606     Blender.Window.WaitCursor(True)
  4607     scn = Scene.GetCurrent()
  4608     
  4609     # set path mode to absolute for preview
  4610     pm_prop = luxProp(scn, "pathmode", "absolute")
  4611     pm = pm_prop.get()
  4612     pm_prop.set('absolute')
  4613     
  4614 
  4615     # Size of preview thumbnail
  4616     thumbres = 110 # default 110x110
  4617     if(defLarge):
  4618         large = luxProp(mat, kn+"prev_large", "true")
  4619     else:
  4620         large = luxProp(mat, kn+"prev_large", "false")
  4621     if(large.get() == "true"):
  4622         thumbres = 140 # small 140x140
  4623 
  4624     thumbbuf = thumbres*thumbres*3
  4625 
  4626 #        consolebin = luxProp(scn, "luxconsole", "").get()
  4627     
  4628     p = get_lux_pipe(scn, buf=thumbbuf, type="luxconsole")
  4629 
  4630     # Unremark to write debugging output to file
  4631     # p.stdin = open('c:\preview.lxs', 'w')
  4632 
  4633     if defType == 0:    
  4634         prev_sphere = luxProp(mat, kn+"prev_sphere", "true")
  4635         prev_plane = luxProp(mat, kn+"prev_plane", "false")
  4636         prev_torus = luxProp(mat, kn+"prev_torus", "false")
  4637     elif defType == 1:
  4638         prev_sphere = luxProp(mat, kn+"prev_sphere", "false")
  4639         prev_plane = luxProp(mat, kn+"prev_plane", "true")
  4640         prev_torus = luxProp(mat, kn+"prev_torus", "false")
  4641     else:
  4642         prev_sphere = luxProp(mat, kn+"prev_sphere", "false")
  4643         prev_plane = luxProp(mat, kn+"prev_plane", "false")
  4644         prev_torus = luxProp(mat, kn+"prev_torus", "true")
  4645 
  4646     # Zoom
  4647     if luxProp(mat, kn+"prev_zoom", "false").get() == "true":
  4648         p.stdin.write('LookAt 0.250000 -1.500000 0.750000 0.250000 -0.500000 0.750000 0.000000 0.000000 1.000000\nCamera "perspective" "float fov" [22.5]\n')
  4649     else:
  4650         p.stdin.write('LookAt 0.0 -3.0 0.5 0.0 -2.0 0.5 0.0 0.0 1.0\nCamera "perspective" "float fov" [22.5]\n')
  4651     # Fleximage
  4652     p.stdin.write('Film "fleximage" "integer xresolution" [%i] "integer yresolution" [%i] "integer displayinterval" [3] "integer ldr_writeinterval" [3600] "string tonemapkernel" ["linear"] "integer haltspp" [1] "integer reject_warmup" [64] "bool write_tonemapped_tga" ["false"] "bool write_untonemapped_exr" ["false"] "bool write_tonemapped_exr" ["false"] "bool write_untonemapped_igi" ["false"] "bool write_tonemapped_igi" ["false"] "bool write_png" ["false"] "string filename" ["luxblend-preview"] \n'%(thumbres, thumbres))
  4653     p.stdin.write('PixelFilter "sinc"\n')
  4654     # Quality
  4655     scn = Scene.GetCurrent()
  4656     defprevmat = luxProp(scn, "defprevmat", "high")
  4657     quality = luxProp(mat, kn+"prev_quality", defprevmat.get())
  4658     if quality.get()=="low":
  4659         p.stdin.write('Sampler "lowdiscrepancy" "string pixelsampler" ["hilbert"] "integer pixelsamples" [2]\n')
  4660     elif quality.get()=="medium":
  4661         p.stdin.write('Sampler "lowdiscrepancy" "string pixelsampler" ["hilbert"] "integer pixelsamples" [4]\n')
  4662     elif quality.get()=="high":
  4663         p.stdin.write('Sampler "lowdiscrepancy" "string pixelsampler" ["hilbert"] "integer pixelsamples" [8]\n')
  4664     else: 
  4665         p.stdin.write('Sampler "lowdiscrepancy" "string pixelsampler" ["hilbert"] "integer pixelsamples" [32]\n')
  4666     # SurfaceIntegrator
  4667     if(prev_plane.get()=="false"):
  4668         p.stdin.write('SurfaceIntegrator "distributedpath" "integer directsamples" [1] "integer diffusereflectdepth" [1] "integer diffusereflectsamples" [4] "integer diffuserefractdepth" [4] "integer diffuserefractsamples" [1] "integer glossyreflectdepth" [1] "integer glossyreflectsamples" [2] "integer glossyrefractdepth" [4] "integer glossyrefractsamples" [1] "integer specularreflectdepth" [2] "integer specularrefractdepth" [4]\n')
  4669     else:
  4670         p.stdin.write('SurfaceIntegrator "distributedpath" "integer directsamples" [1] "integer diffusereflectdepth" [0] "integer diffusereflectsamples" [0] "integer diffuserefractdepth" [0] "integer diffuserefractsamples" [0] "integer glossyreflectdepth" [0] "integer glossyreflectsamples" [0] "integer glossyrefractdepth" [0] "integer glossyrefractsamples" [0] "integer specularreflectdepth" [1] "integer specularrefractdepth" [1]\n')
  4671     # World
  4672     p.stdin.write('WorldBegin\n')
  4673     if(prev_sphere.get()=="true"):
  4674         p.stdin.write('AttributeBegin\nTransform [0.5 0.0 0.0 0.0  0.0 0.5 0.0 0.0  0.0 0.0 0.5 0.0  0.0 0.0 0.5 1.0]\n')
  4675     elif (prev_plane.get()=="true"):
  4676         p.stdin.write('AttributeBegin\nTransform [0.649999976158 0.0 0.0 0.0  0.0 4.90736340453e-008 0.649999976158 0.0  0.0 -0.649999976158 4.90736340453e-008 0.0  0.0 0.0 0.5 1.0]\n')
  4677     else:
  4678         p.stdin.write('AttributeBegin\nTransform [0.35 -0.35 0.0 0.0  0.25 0.25 0.35 0.0  -0.25 -0.25 0.35 0.0  0.0 0.0 0.5 1.0]\n')
  4679     obwidth = luxProp(mat, kn+"prev_obwidth", 1.0)
  4680     obw = obwidth.get()
  4681     p.stdin.write('TransformBegin\n')
  4682     p.stdin.write('Scale %f %f %f\n'%(obw,obw,obw))
  4683     if texName:
  4684         print("texture "+texName+"  "+name)
  4685         (str, link) = luxTexture(texName, name, "color", "1.0 1.0 1.0", None, None, "", "", mat, None, 0, level)
  4686         link = link.replace(" "+texName+"\"", " Kd\"") # swap texture name to "Kd"
  4687         p.stdin.write(str+"\n")
  4688         p.stdin.write("Material \"matte\" "+link+"\n") 
  4689     else:
  4690         # Material
  4691         p.stdin.write(luxMaterial(mat))
  4692         link = luxProp(mat,"link","").get()
  4693         if kn!="": link = link.rstrip("\"")+":"+kn.strip(".:")+"\""
  4694         p.stdin.write(link+'\n')
  4695     p.stdin.write('TransformEnd\n')
  4696     # Shape
  4697     if(prev_sphere.get()=="true"):
  4698         p.stdin.write('Shape "sphere" "float radius" [1.0]\n')
  4699     elif (prev_plane.get()=="true"):
  4700         p.stdin.write('    Shape "trianglemesh" "integer indices" [ 0 1 2 0 2 3 ] "point P" [ 1.0 1.0 0.0 -1.0 1.0 0.0 -1.0 -1.0 -0.0 1.0 -1.0 -0.0 ] "float uv" [ 1.0 1.0     0.0 1.0     0.0 0.0       1.0 0.0 ]\n')
  4701     elif (prev_torus.get()=="true"):
  4702         p.stdin.write('Shape "torus" "float radius" [1.0]\n')
  4703     p.stdin.write('AttributeEnd\n')
  4704     # Checkerboard floor
  4705     if(prev_plane.get()=="false"):
  4706         p.stdin.write('AttributeBegin\nTransform [5.0 0.0 0.0 0.0  0.0 5.0 0.0 0.0  0.0 0.0 5.0 0.0  0.0 0.0 0.0 1.0]\n')
  4707         p.stdin.write('Texture "checks" "color" "checkerboard"')
  4708         p.stdin.write('"integer dimension" [2] "string aamode" ["supersample"] "color tex1" [0.9 0.9 0.9] "color tex2" [0.0 0.0 0.0]')
  4709         p.stdin.write('"string mapping" ["uv"] "float uscale" [36.8] "float vscale" [36.0]\n')
  4710         p.stdin.write('Material "matte" "texture Kd" ["checks"]\n')
  4711         p.stdin.write('Shape "loopsubdiv" "integer nlevels" [3] "bool dmnormalsmooth" ["true"] "bool dmsharpboundary" ["false"] ')
  4712         p.stdin.write('"integer indices" [ 0 1 2 0 2 3 1 0 4 1 4 5 5 4 6 5 6 7 ]')
  4713         p.stdin.write('"point P" [ 1.000000 1.000000 0.000000 -1.000000 1.000000 0.000000 -1.000000 -1.000000 0.000000 1.000000 -1.000000 0.000000 1.000000 3.000000 0.000000 -1.000000 3.000000 0.000000 1.000000 3.000000 2.000000 -1.000000 3.000000 2.000000')
  4714         p.stdin.write('] "normal N" [ 0.000000 0.000000 1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 1.000000 0.000000 -0.707083 0.707083 0.000000 -0.707083 0.707083 0.000000 -1.000000 0.000000 0.000000 -1.000000 0.000000')
  4715         p.stdin.write('] "float uv" [ 0.333334 0.000000 0.333334 0.333334 0.000000 0.333334 0.000000 0.000000 0.666667 0.000000 0.666667 0.333333 1.000000 0.000000 1.000000 0.333333 ]\n')
  4716         p.stdin.write('AttributeEnd\n')
  4717     # Lightsource
  4718     if(prev_plane.get()=="false"):
  4719         p.stdin.write('AttributeBegin\nTransform [1.0 0.0 0.0 0.0  0.0 1.0 0.0 0.0  0.0 0.0 1.0 0.0  1.0 -1.0 4.0 1.0]\n')
  4720     else:
  4721         p.stdin.write('AttributeBegin\nTransform [1.0 0.0 0.0 0.0  0.0 1.0 0.0 0.0  0.0 0.0 1.0 0.0  1.0 -4.0 1.0 1.0]\n')
  4722     area = luxProp(mat, kn+"prev_arealight", "false")
  4723     if(area.get() == "false"):
  4724         p.stdin.write('Texture "pL" "color" "blackbody" "float temperature" [6500.0]\n')
  4725         p.stdin.write('LightSource "point" "texture L" ["pL"] "float gain" [0.002]')
  4726     else:
  4727         p.stdin.write('ReverseOrientation\n')
  4728         p.stdin.write('AreaLightSource "area" "color L" [1.0 1.0 1.0]\n')
  4729         if(prev_plane.get()=="false"):
  4730             p.stdin.write(' "float gain" [0.3]\n')
  4731         p.stdin.write('Shape "disk" "float radius" [1.0]\nAttributeEnd\n')
  4732     p.stdin.write('WorldEnd\n')
  4733     
  4734     previewing = False
  4735 
  4736     data = p.communicate()[0]
  4737     p.stdin.close()
  4738     
  4739     # restore path mode
  4740     pm_prop.set(pm)    
  4741     
  4742     datalen = len(data)
  4743     if(datalen < thumbbuf): 
  4744         print("error on preview: got %i bytes, expected %i" % (datalen, thumbbuf))
  4745         return
  4746     global previewCache
  4747     image = luxImage()
  4748     image.decodeLuxConsole(thumbres, thumbres, data)
  4749     previewCache[(mat.name+":"+kn).__hash__()] = image
  4750     Draw.Redraw()
  4751     Blender.Window.WaitCursor(False)
  4752 
  4753 def luxPreview(mat, name, defType=0, defEnabled=False, defLarge=False, texName=None, gui=None, level=0, color=None):
  4754     
  4755 
  4756     if gui:
  4757         kn = name
  4758         if texName: kn += ":"+texName
  4759         if kn != "": kn += "."
  4760         if(defEnabled == True):
  4761             showpreview = luxProp(mat, kn+"prev_show", "true")
  4762         else:
  4763             showpreview = luxProp(mat, kn+"prev_show", "false")
  4764         Draw.Toggle("P", evtLuxGui, gui.xmax, gui.y-gui.h, gui.h, gui.h, showpreview.get()=="true", "Preview", lambda e,v: showpreview.set(["false","true"][bool(v)]))
  4765         if showpreview.get()=="true": 
  4766             if(defLarge):
  4767                 large = luxProp(mat, kn+"prev_large", "true")
  4768             else:
  4769                 large = luxProp(mat, kn+"prev_large", "false")
  4770             voffset = -8
  4771             rr = 5.65 
  4772             if(large.get() == "true"):
  4773                 rr = 7
  4774                 voffset = 22
  4775             gui.newline()
  4776             r = gui.getRect(1.1, rr)
  4777             if(color != None):
  4778                 BGL.glColor3f(color[0],color[1],color[2]); BGL.glRectf(r[0]-110, r[1], 418, r[1]+128+voffset); BGL.glColor3f(0.9, 0.9, 0.9)
  4779             try: previewCache[(mat.name+":"+kn).__hash__()].draw(r[0]-82, r[1]+4)
  4780             except: pass
  4781 
  4782             prev_sphere = luxProp(mat, kn+"prev_sphere", "true")
  4783             prev_plane = luxProp(mat, kn+"prev_plane", "false")
  4784             prev_torus = luxProp(mat, kn+"prev_torus", "false")
  4785             if defType == 1:
  4786                 prev_sphere = luxProp(mat, kn+"prev_sphere", "false")
  4787                 prev_plane = luxProp(mat, kn+"prev_plane", "true")
  4788                 prev_torus = luxProp(mat, kn+"prev_torus", "false")
  4789             elif defType == 2:
  4790                 prev_sphere = luxProp(mat, kn+"prev_sphere", "false")
  4791                 prev_plane = luxProp(mat, kn+"prev_plane", "false")
  4792                 prev_torus = luxProp(mat, kn+"prev_torus", "true")
  4793 
  4794             # preview mode toggle buttons
  4795             Draw.Toggle("S", evtLuxGui, r[0]-108, r[1]+100+voffset, 22, 22, prev_sphere.get()=="true", "Draw Sphere", lambda e,v: Preview_Sphereset(mat, kn, ["false","true"][bool(v)]))
  4796             Draw.Toggle("P", evtLuxGui, r[0]-108, r[1]+74+voffset, 22, 22, prev_plane.get()=="true", "Draw 2D Plane", lambda e,v: Preview_Planeset(mat, kn, ["false","true"][bool(v)]))
  4797             Draw.Toggle("T", evtLuxGui, r[0]-108, r[1]+48+voffset, 22, 22, prev_torus.get()=="true", "Draw Torus", lambda e,v: Preview_Torusset(mat, kn, ["false","true"][bool(v)]))
  4798 
  4799             # Zoom toggle
  4800             zoom = luxProp(mat, kn+"prev_zoom", "false")
  4801             Draw.Toggle("Zoom", evtLuxGui, r[0]+66, r[1]+100+voffset, 50, 18, zoom.get()=="true", "Zoom", lambda e,v: zoom.set(["false","true"][bool(v)]))
  4802 
  4803             area = luxProp(mat, kn+"prev_arealight", "false")
  4804             Draw.Toggle("Area", evtLuxGui, r[0]+66, r[1]+5, 50, 18, area.get()=="true", "Area", lambda e,v: area.set(["false","true"][bool(v)]))
  4805 
  4806             # Object width
  4807             obwidth = luxProp(mat, kn+"prev_obwidth", 1.0)
  4808             Draw.Number("Width:", evtLuxGui, r[0]+66, r[1]+78+voffset, 129, 18, obwidth.get(), 0.001, 10, "The width of the preview object in blender/lux 1m units", lambda e,v: obwidth.set(v))
  4809 
  4810             # large/small size
  4811             Draw.Toggle("large", evtLuxGui, r[0]+200, r[1]+78+voffset, 88, 18, large.get()=="true", "Large", lambda e,v: large.set(["false","true"][bool(v)]))
  4812 
  4813             # Preview Quality
  4814             qs = ["low","medium","high","very high"]
  4815             scn = Scene.GetCurrent()
  4816             defprevmat = luxProp(scn, "defprevmat", "high")
  4817             quality = luxProp(mat, kn+"prev_quality", defprevmat.get())
  4818             luxOptionRect("quality", quality, qs, "  Quality", "select preview quality", gui, r[0]+200, r[1]+100+voffset, 88, 18)
  4819 
  4820             # Update preview
  4821             Draw.Button("Update Preview", evtLuxGui, r[0]+120, r[1]+5, 167, 18, "Update Material Preview", lambda e,v: Preview_Update(mat, kn, defLarge, defType, texName, name, level))
  4822 
  4823             # Reset depths after getRect()
  4824             gui.y -= 92+voffset
  4825             gui.y -= gui.h
  4826             gui.hmax = 18 + 4
  4827 
  4828 def luxMaterialBlock(name, luxname, key, mat, gui=None, level=0, str_opt=""):
  4829     global icon_mat, icon_matmix, icon_map3dparam
  4830     def c(t1, t2):
  4831         return (t1[0]+t2[0], t1[1]+t2[1])
  4832     str = ""
  4833     if key == "": keyname = kn = name
  4834     else: keyname = kn = "%s:%s"%(key, name)
  4835     if kn != "": kn += "."
  4836     if keyname == "": matname = mat.getName()
  4837     else: matname = "%s:%s"%(mat.getName(), keyname)
  4838 
  4839     if mat:
  4840         mattype = luxProp(mat, kn+"type", "matte")
  4841         # Set backwards compatibility of glossy material from plastic and substrate
  4842         if(mattype.get() == "substrate" or mattype.get() == "plastic"):
  4843             mattype.set("glossy")
  4844 
  4845         # this is reverse order than in shown in the dropdown list
  4846         materials = ["null","mix","mirror","shinymetal","metal","mattetranslucent","matte","glossy","roughglass","glass","carpaint"]
  4847         
  4848         if level == 0: materials = ["portal","light","boundvolume"]+materials
  4849         if gui:
  4850             icon = icon_mat
  4851             if mattype.get() == "mix": icon = icon_matmix
  4852             if level == 0: gui.newline("Material type:", 12, level, icon, [0.75,0.5,0.25])
  4853             else: gui.newline(name+":", 12, level, icon, scalelist([0.75,0.6,0.25],2.0/(level+2)))
  4854 
  4855 
  4856         link = luxOption("type", mattype, materials, "  TYPE", "select material type", gui)
  4857         showadvanced = luxProp(mat, kn+"showadvanced", "false")
  4858         luxBool("advanced", showadvanced, "Advanced", "Show advanced options", gui, 0.6)
  4859         showhelp = luxProp(mat, kn+"showhelp", "false")
  4860         luxHelp("help", showhelp, "Help", "Show Help Information", gui, 0.4)
  4861 
  4862         # show copy/paste menu button
  4863         if gui: Draw.PushButton(">", evtLuxGui, gui.xmax+gui.h, gui.y-gui.h, gui.h, gui.h, "Menu", lambda e,v: showMatTexMenu(mat,keyname,False))
  4864 
  4865         # Draw Material preview option
  4866         showmatprev = False
  4867         if level == 0:
  4868             showmatprev = True
  4869         if gui: luxPreview(mat, keyname, 0, showmatprev, True, None, gui, level, [0.746, 0.625, 0.5])
  4870 
  4871 
  4872         if gui: gui.newline()
  4873         has_object_options   = 0 # disable object options by default
  4874         has_bump_options     = 0 # disable bump mapping options by default
  4875         has_emission_options = 0 # disable emission options by default
  4876         has_compositing_options = 0 # disable compositing options by default
  4877 
  4878         if mattype.get() == "mix":
  4879             (str,link) = c((str,link), luxFloatTexture("amount", keyname, 0.5, 0.0, 1.0, "amount", "The degree of mix between the two materials", mat, gui, level+1))
  4880             (str,link) = c((str,link), luxMaterialBlock("mat1", "namedmaterial1", keyname, mat, gui, level+1))
  4881             (str,link) = c((str,link), luxMaterialBlock("mat2", "namedmaterial2", keyname, mat, gui, level+1))
  4882             has_bump_options = 0
  4883             has_object_options = 1
  4884             has_emission_options = 1
  4885             has_compositing_options = 0
  4886 
  4887         if mattype.get() == "light":
  4888             if luxProp(Scene.GetCurrent(), "nolg", "false").get()!="true":
  4889                 lightgroup = luxProp(mat, kn+"light.lightgroup", "default")
  4890                 link = "LightGroup \"%s\"\n"%lightgroup.get()
  4891             else:
  4892                 link = ''
  4893             link += "AreaLightSource \"area\""
  4894             (str,link) = c((str,link), luxLight("", kn, mat, gui, level))
  4895             has_bump_options = 0
  4896             has_object_options = 1
  4897             has_emission_options = 0
  4898             has_compositing_options = 1
  4899 
  4900         if mattype.get() == "boundvolume":
  4901             link = ""
  4902             voltype = luxProp(mat, kn+"vol.type", "homogeneous")
  4903             vols = ["homogeneous", "exponential", "cloud"]
  4904             vollink = luxOption("type", voltype, vols, "type", "", gui)
  4905             if voltype.get() == "homogeneous":
  4906                 link = "Volume \"homogeneous\""
  4907             if voltype.get() == "exponential":
  4908                 link = "Volume \"exponential\""
  4909             if voltype.get() == "cloud":
  4910                 link = "Volume \"cloud\""
  4911 
  4912             if gui: gui.newline("absorption:", 0, level+1)
  4913             link += luxRGB("sigma_a", luxProp(mat, kn+"vol.sig_a", "1.0 1.0 1.0"), 1.0, "sigma_a", "The absorption cross section", gui)
  4914             if gui: gui.newline("scattering:", 0, level+1)
  4915             link += luxRGB("sigma_s", luxProp(mat, kn+"vol.sig_b", "0.0 0.0 0.0"), 1.0, "sigma_b", "The scattering cross section", gui)
  4916             if gui: gui.newline("emission:", 0, level+1)
  4917             link += luxRGB("Le", luxProp(mat, kn+"vol.le", "0.0 0.0 0.0"), 1.0, "Le", "The volume's emission spectrum", gui)
  4918             if gui: gui.newline("assymetry:", 0, level+1)
  4919             link += luxFloat("g", luxProp(mat, kn+"vol.g", 0.0), 0.0, 100.0, "g", "The phase function asymmetry parameter", gui)
  4920 
  4921             if voltype.get() == "exponential":
  4922                 if gui: gui.newline("form:", 0, level+1)
  4923                 link += luxFloat("a", luxProp(mat, kn+"vol.a", 1.0), 0.0, 100.0, "a/scale", "exponential::a parameter in the ae^{-bh} formula", gui)
  4924                 link += luxFloat("b", luxProp(mat, kn+"vol.b", 2.0), 0.0, 100.0, "b/falloff", "exponential::b parameter in the ae^{-bh} formula", gui)
  4925                 if gui: gui.newline("updir:", 0, level+1)
  4926                 link += luxVector("updir", luxProp(mat, kn+"vol.updir", "0 0 1"), -1.0, 1.0, "updir", "Up direction vector", gui, 2.0)
  4927 
  4928             if voltype.get() == "cloud":
  4929                 if gui: gui.newline("cloud:", 0, level+1)
  4930                 link += luxFloat("radius", luxProp(mat, kn+"vol.radius", 0.5), 0.01, 2.0, "radius", "Radius of hemisphere used as basis for cloud shape", gui)
  4931                 link += luxFloat("noisescale", luxProp(mat, kn+"vol.noisescale", 0.3), 0.1, 2.0, "noisesize", "Size of cloud noise", gui)
  4932                 link += luxFloat("turbulence", luxProp(mat, kn+"vol.turbulence", 0.5), 0.0, 3.0, "turbulence", "Extent to which the noise effects the cloud shape", gui)
  4933                 link += luxFloat("noiseoffset", luxProp(mat, kn+"vol.noiseoffset", 0.0), 0.0, 1000.0, "noiseoffset", "Useful for creating unique clouds", gui )
  4934                 link += luxInt("octaves", luxProp(mat, kn+"vol.octaves", 3), 1, 8, "octaves", "Sets the amount of detail for the noise", gui )
  4935                 link += luxFloat("omega", luxProp(mat, kn+"vol.omega", 0.75), 0.1, 1.0, "omega", "Sets the scale difference of each successive octave", gui )
  4936                 link += luxFloat("sharpness", luxProp(mat, kn+"vol.sharpness", 6.0), 0.2, 10.0, "sharpness", "Sets the sharpness of the noise", gui)
  4937                 link += luxFloat("variability", luxProp(mat, kn+"vol.variability", 0.9), 0.0, 1.0, "mask amount", "Noise mask amount. 0 means noise everywhere, 1 means only some spots have noise.", gui)
  4938                 link += luxFloat("baseflatness", luxProp(mat, kn+"vol.baseflatness", 0.8), 0.0, 1.0, "baseflatness", "Flatness of the cloud's base. (0.0 makes a round cloud.)", gui)
  4939                 link += luxInt("spheres", luxProp(mat, kn+"vol.spheres", 2000), 0, 10000, "spheres", "Number of small spheres for cumulus shape. 0 is non-cumulus.", gui )
  4940                 link += luxFloat("spheresize", luxProp(mat, kn+"vol.spheresize", 0.15), 0.05, 0.55, "spheresize", "Size of cumulus spheres", gui)
  4941  
  4942             link += str_opt
  4943 
  4944             has_bump_options = 0
  4945             has_object_options = 0
  4946             has_emission_options = 0
  4947 
  4948             return (str, link)
  4949 
  4950         if mattype.get() == "carpaint":
  4951             if gui: gui.newline("Preset:", 0, level+1)
  4952             carname = luxProp(mat, kn+"carpaint.name", "Custom")
  4953             cars = ["Custom","ford f8","polaris silber","opel titan","bmw339","2k acrylack","white","blue","blue matte"]
  4954             carlink = luxOption("name", carname, cars, "name", "", gui)
  4955             if carname.get() == "Custom":
  4956                 (str,link) = c((str,link), luxSpectrumTexture("Kd", keyname, "1.0 1.0 1.0", 1.0, "diffuse", "", mat, gui, level+1))
  4957                 (str,link) = c((str,link), luxSpectrumTexture("Ks1", keyname, "1.0 1.0 1.0", 1.0, "specular1", "", mat, gui, level+1))
  4958                 (str,link) = c((str,link), luxSpectrumTexture("Ks2", keyname, "1.0 1.0 1.0", 1.0, "specular2", "", mat, gui, level+1))
  4959                 (str,link) = c((str,link), luxSpectrumTexture("Ks3", keyname, "1.0 1.0 1.0", 1.0, "specular3", "", mat, gui, level+1))
  4960                 (str,link) = c((str,link), luxFloatTexture("R1", keyname, 1.0, 0.0, 1.0, "R1", "", mat, gui, level+1))
  4961                 (str,link) = c((str,link), luxFloatTexture("R2", keyname, 1.0, 0.0, 1.0, "R2", "", mat, gui, level+1))
  4962                 (str,link) = c((str,link), luxFloatTexture("R3", keyname, 1.0, 0.0, 1.0, "R3", "", mat, gui, level+1))
  4963                 (str,link) = c((str,link), luxFloatTexture("M1", keyname, 1.0, 0.0, 1.0, "M1", "", mat, gui, level+1))
  4964                 (str,link) = c((str,link), luxFloatTexture("M2", keyname, 1.0, 0.0, 1.0, "M2", "", mat, gui, level+1))
  4965                 (str,link) = c((str,link), luxFloatTexture("M3", keyname, 1.0, 0.0, 1.0, "M3", "", mat, gui, level+1))
  4966             else: link += carlink
  4967             absorption = luxProp(mat, keyname+".useabsorption", "false")
  4968             luxCollapse("absorption", absorption, "Absorption", "Enable Coating Absorption", gui, 2.0)
  4969             if absorption.get() == "true":
  4970                 (str,link) = c((str,link), luxSpectrumTexture("Ka", keyname, "0.2 0.2 0.2", 1.0, "absorption", "", mat, gui, level+1))
  4971                 (str,link) = c((str,link), luxFloatTexture("d", keyname, 5.0, 0.0, 15.0, "depth", "", mat, gui, level+1))
  4972             has_bump_options = 1
  4973             has_object_options = 1
  4974             has_emission_options = 1
  4975             has_compositing_options = 1
  4976         
  4977         if mattype.get() == "glass":
  4978             (str,link) = c((str,link), luxSpectrumTexture("Kr", keyname, "1.0 1.0 1.0", 1.0, "reflection", "", mat, gui, level+1))
  4979             (str,link) = c((str,link), luxSpectrumTexture("Kt", keyname, "1.0 1.0 1.0", 1.0, "transmission", "", mat, gui, level+1))
  4980             (str,link) = c((str,link), luxIORFloatTexture("index", keyname, 1.5, 1.0, 6.0, "IOR", "", mat, gui, level+1))
  4981             architectural = luxProp(mat, keyname+".architectural", "false")
  4982             link += luxBool("architectural", architectural, "architectural", "Enable architectural glass", gui, 2.0)
  4983             if architectural.get() == "false":
  4984                 chromadisp = luxProp(mat, keyname+".chromadisp", "false")
  4985                 luxCollapse("chromadisp", chromadisp, "Dispersive Refraction", "Enable Chromatic Dispersion", gui, 2.0)
  4986                 if chromadisp.get() == "true":
  4987                     (str,link) = c((str,link), luxCauchyBFloatTexture("cauchyb", keyname, 0.0, 0.0, 1.0, "cauchyb", "", mat, gui, level+1))
  4988                 thinfilm = luxProp(mat, keyname+".thinfilm", "false")
  4989                 luxCollapse("thinfilm", thinfilm, "Thin Film Coating", "Enable Thin Film Coating", gui, 2.0)
  4990                 if thinfilm.get() == "true":
  4991                     (str,link) = c((str,link), luxFloatSliderTexture("film", keyname, 200.0, 1.0, 1500.0, "film", "thickness of film coating in nanometers", mat, gui, level+1))
  4992                     (str,link) = c((str,link), luxIORFloatTexture("filmindex", keyname, 1.5, 1.0, 6.0, "film IOR", "film coating index of refraction", mat, gui, level+1))
  4993             has_bump_options = 1
  4994             has_object_options = 1
  4995             has_emission_options = 1
  4996             has_compositing_options = 1
  4997             
  4998         if mattype.get() == "matte":
  4999             orennayar = luxProp(mat, keyname+".orennayar", "false")
  5000             (str,link) = c((str,link), luxSpectrumTexture("Kd", keyname, "1.0 1.0 1.0", 1.0, "diffuse", "", mat, gui, level+1))
  5001             luxCollapse("orennayar", orennayar, "Oren-Nayar", "Enable Oren-Nayar BRDF", gui, 2.0)
  5002             if orennayar.get() == "true":
  5003                 (str,link) = c((str,link), luxFloatTexture("sigma", keyname, 0.0, 0.0, 100.0, "sigma", "sigma value for Oren-Nayar BRDF", mat, gui, level+1))
  5004             has_bump_options = 1
  5005             has_object_options = 1
  5006             has_emission_options = 1
  5007             has_compositing_options = 1
  5008         
  5009         if mattype.get() == "mattetranslucent":
  5010             orennayar = luxProp(mat, keyname+".orennayar", "false")
  5011             (str,link) = c((str,link), luxSpectrumTexture("Kr", keyname, "1.0 1.0 1.0", 1.0, "reflection", "", mat, gui, level+1))
  5012             (str,link) = c((str,link), luxSpectrumTexture("Kt", keyname, "1.0 1.0 1.0", 1.0, "transmission", "", mat, gui, level+1))
  5013             luxCollapse("orennayar", orennayar, "Oren-Nayar", "Enable Oren-Nayar BRDF", gui, 2.0)
  5014             if orennayar.get() == "true":
  5015                 (str,link) = c((str,link), luxFloatTexture("sigma", keyname, 0.0, 0.0, 100.0, "sigma", "", mat, gui, level+1))
  5016             has_bump_options = 1
  5017             has_object_options = 1
  5018             has_emission_options = 1
  5019             has_compositing_options = 1
  5020         
  5021         if mattype.get() == "metal":
  5022             if gui: gui.newline("name:", 0, level+1)
  5023             metalname = luxProp(mat, kn+"metal.name", "")
  5024             metals = ["aluminium","amorphous carbon","silver","gold","copper"]
  5025 
  5026             if not(metalname.get() in metals):
  5027                 metals.append(metalname.get())
  5028             metallink = luxOption("name", metalname, metals, "name", "", gui, 1.88)
  5029             if gui: Draw.Button("...", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, "click to select a nk file",lambda e,v:Window.FileSelector(lambda s:metalname.set(s), "Select nk file"))
  5030             link += luxstr(metallink)
  5031             anisotropic = luxProp(mat, kn+"metal.anisotropic", "false")
  5032             if gui:
  5033                 gui.newline("")
  5034                 Draw.Toggle("A", evtLuxGui, gui.x-gui.h, gui.y-gui.h, gui.h, gui.h, anisotropic.get()=="true", "anisotropic roughness", lambda e,v:anisotropic.set(["false","true"][bool(v)]))
  5035             if anisotropic.get()=="true":
  5036                 (str,link) = c((str,link), luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "u-exponent", "", mat, gui, level+1))
  5037                 (str,link) = c((str,link), luxExponentTexture("vroughness", keyname, 0.002, 0.0, 1.0, "v-exponent", "", mat, gui, level+1))
  5038             else:
  5039                 (s, l) = luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "exponent", "", mat, gui, level+1)
  5040                 (str,link) = c((str,link), (s, l))
  5041                 link += l.replace("uroughness", "vroughness", 1)
  5042                 
  5043             has_bump_options = 1
  5044             has_object_options = 1
  5045             has_emission_options = 1
  5046             has_compositing_options = 1
  5047             
  5048         if mattype.get() == "mirror":
  5049             (str,link) = c((str,link), luxSpectrumTexture("Kr", keyname, "1.0 1.0 1.0", 1.0, "reflection", "", mat, gui, level+1))
  5050             thinfilm = luxProp(mat, keyname+".thinfilm", "false")
  5051             luxCollapse("thinfilm", thinfilm, "Thin Film Coating", "Enable Thin Film Coating", gui, 2.0)
  5052             if thinfilm.get() == "true":
  5053                 (str,link) = c((str,link), luxFloatSliderTexture("film", keyname, 200.0, 1.0, 1500.0, "film", "thickness of film coating in nanometers", mat, gui, level+1))
  5054                 (str,link) = c((str,link), luxIORFloatTexture("filmindex", keyname, 1.5, 1.0, 6.0, "film IOR", "film coating index of refraction", mat, gui, level+1))
  5055 
  5056             has_bump_options = 1
  5057             has_object_options = 1
  5058             has_emission_options = 1
  5059             has_compositing_options = 1
  5060             
  5061         if mattype.get() == "roughglass":
  5062             (str,link) = c((str,link), luxSpectrumTexture("Kr", keyname, "1.0 1.0 1.0", 1.0, "reflection", "", mat, gui, level+1))
  5063             (str,link) = c((str,link), luxSpectrumTexture("Kt", keyname, "1.0 1.0 1.0", 1.0, "transmission", "", mat, gui, level+1))
  5064             anisotropic = luxProp(mat, kn+"roughglass.anisotropic", "false")
  5065             if gui:
  5066                 gui.newline("")
  5067                 Draw.Toggle("A", evtLuxGui, gui.x-gui.h, gui.y-gui.h, gui.h, gui.h, anisotropic.get()=="true", "anisotropic roughness", lambda e,v:anisotropic.set(["false","true"][bool(v)]))
  5068             if anisotropic.get()=="true":
  5069                 (str,link) = c((str,link), luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "u-exponent", "", mat, gui, level+1))
  5070                 (str,link) = c((str,link), luxExponentTexture("vroughness", keyname, 0.002, 0.0, 1.0, "v-exponent", "", mat, gui, level+1))
  5071             else:
  5072                 (s, l) = luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "exponent", "", mat, gui, level+1)
  5073                 (str,link) = c((str,link), (s, l))
  5074                 link += l.replace("uroughness", "vroughness", 1)
  5075             (str,link) = c((str,link), luxIORFloatTexture("index", keyname, 1.5, 1.0, 6.0, "IOR", "", mat, gui, level+1))
  5076             chromadisp = luxProp(mat, keyname+".chromadisp", "false")
  5077             luxCollapse("chromadisp", chromadisp, "Dispersive Refraction", "Enable Chromatic Dispersion", gui, 2.0)
  5078             if chromadisp.get() == "true":
  5079                 (str,link) = c((str,link), luxCauchyBFloatTexture("cauchyb", keyname, 0.0, 0.0, 1.0, "cauchyb", "", mat, gui, level+1))
  5080             has_bump_options = 1
  5081             has_object_options = 1
  5082             has_emission_options = 1
  5083             has_compositing_options = 1
  5084             
  5085         if mattype.get() == "shinymetal":
  5086             (str,link) = c((str,link), luxSpectrumTexture("Kr", keyname, "1.0 1.0 1.0", 1.0, "reflection", "", mat, gui, level+1))
  5087             (str,link) = c((str,link), luxSpectrumTexture("Ks", keyname, "1.0 1.0 1.0", 1.0, "specular", "", mat, gui, level+1))
  5088             anisotropic = luxProp(mat, kn+"shinymetal.anisotropic", "false")
  5089             if gui:
  5090                 gui.newline("")
  5091                 Draw.Toggle("A", evtLuxGui, gui.x-gui.h, gui.y-gui.h, gui.h, gui.h, anisotropic.get()=="true", "anisotropic roughness", lambda e,v:anisotropic.set(["false","true"][bool(v)]))
  5092             if anisotropic.get()=="true":
  5093                 (str,link) = c((str,link), luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "u-exponent", "", mat, gui, level+1))
  5094                 (str,link) = c((str,link), luxExponentTexture("vroughness", keyname, 0.002, 0.0, 1.0, "v-exponent", "", mat, gui, level+1))
  5095             else:
  5096                 (s, l) = luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "exponent", "", mat, gui, level+1)
  5097                 (str,link) = c((str,link), (s, l))
  5098                 link += l.replace("uroughness", "vroughness", 1)
  5099 
  5100             thinfilm = luxProp(mat, keyname+".thinfilm", "false")
  5101             luxCollapse("thinfilm", thinfilm, "Thin Film Coating", "Enable Thin Film Coating", gui, 2.0)
  5102             if thinfilm.get() == "true":
  5103                 (str,link) = c((str,link), luxFloatSliderTexture("film", keyname, 200.0, 1.0, 1500.0, "film", "thickness of film coating in nanometers", mat, gui, level+1))
  5104                 (str,link) = c((str,link), luxIORFloatTexture("filmindex", keyname, 1.5, 1.0, 6.0, "film IOR", "film coating index of refraction", mat, gui, level+1))
  5105 
  5106             has_bump_options = 1
  5107             has_object_options = 1
  5108             has_emission_options = 1
  5109             has_compositing_options = 1
  5110             
  5111         if mattype.get() == "glossy":
  5112             (str,link) = c((str,link), luxSpectrumTexture("Kd", keyname, "1.0 1.0 1.0", 1.0, "diffuse", "", mat, gui, level+1))
  5113             useior = luxProp(mat, keyname+".useior", "false")
  5114             if gui:
  5115                 gui.newline("")
  5116                 Draw.Toggle("I", evtLuxGui, gui.x-gui.h, gui.y-gui.h, gui.h, gui.h, useior.get()=="true", "Use IOR/Reflective index input", lambda e,v:useior.set(["false","true"][bool(v)]))
  5117             if useior.get() == "true":
  5118                 (str,link) = c((str,link), luxIORFloatTexture("index", keyname, 1.5, 1.0, 50.0, "IOR", "", mat, gui, level+1))
  5119                 link += " \"color Ks\" [1.0 1.0 1.0]"    
  5120             else:
  5121                 (str,link) = c((str,link), luxSpectrumTexture("Ks", keyname, "1.0 1.0 1.0", 1.0, "specular", "", mat, gui, level+1))
  5122                 link += " \"float index\" [0.0]"    
  5123             anisotropic = luxProp(mat, kn+"glossy.anisotropic", "false")
  5124             if gui:
  5125                 gui.newline("")
  5126                 Draw.Toggle("A", evtLuxGui, gui.x-gui.h, gui.y-gui.h, gui.h, gui.h, anisotropic.get()=="true", "anisotropic roughness", lambda e,v:anisotropic.set(["false","true"][bool(v)]))
  5127             if anisotropic.get()=="true":
  5128                 (str,link) = c((str,link), luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "u-exponent", "", mat, gui, level+1))
  5129                 (str,link) = c((str,link), luxExponentTexture("vroughness", keyname, 0.002, 0.0, 1.0, "v-exponent", "", mat, gui, level+1))
  5130             else:
  5131                 (s, l) = luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "exponent", "", mat, gui, level+1)
  5132                 (str,link) = c((str,link), (s, l))
  5133                 link += l.replace("uroughness", "vroughness", 1)
  5134 
  5135             absorption = luxProp(mat, keyname+".useabsorption", "false")
  5136             luxCollapse("absorption", absorption, "Absorption", "Enable Coating Absorption", gui, 2.0)
  5137             if absorption.get() == "true":
  5138                 (str,link) = c((str,link), luxSpectrumTexture("Ka", keyname, "0.2 0.2 0.2", 1.0, "absorption", "", mat, gui, level+1))
  5139                 (str,link) = c((str,link), luxFloatTexture("d", keyname, 0.15, 0.0, 15.0, "depth", "", mat, gui, level+1))
  5140             has_bump_options = 1
  5141             has_object_options = 1
  5142             has_emission_options = 1
  5143             has_compositing_options = 1
  5144             
  5145         if mattype.get() == 'null':
  5146             has_emission_options = 1
  5147 
  5148         # Bump mapping options (common)
  5149         if (has_bump_options == 1):
  5150             usebump = luxProp(mat, keyname+".usebump", "false")
  5151             luxCollapse("usebump", usebump, "Bump Map", "Enable Bump Mapping options", gui, 2.0)
  5152             if usebump.get() == "true":
  5153                 (str,link) = c((str,link), luxFloatTexture("bumpmap", keyname, 0.0, -1.0, 1.0, "bumpmap", "bumpmap scale in meters - i.e. 0.01 = 1 cm", mat, gui, level+1))
  5154 
  5155         # emission options (common)
  5156         if (level == 0):
  5157             if (has_emission_options == 1):
  5158                 if gui: gui.newline("", 2, level, None, [0.6,0.6,0.4])
  5159                 useemission = luxProp(mat, "emission", "false")
  5160                 luxCollapse("useemission", useemission, "Emission", "Enable emission options", gui, 2.0)
  5161                 if useemission.get() == "true":
  5162                     # emission GUI is here but lux export will be done later 
  5163                     luxLight("", "", mat, gui, level)
  5164             else: luxProp(mat, "emission", "false").set("false") # prevent from exporting later
  5165 
  5166 
  5167         # Compositing options (common)
  5168         # Note - currently only display options when using distributedpath integrator
  5169         integratortype = luxProp(Scene.GetCurrent(), "sintegrator.type", "bidirectional")
  5170         if (integratortype.get() == "distributedpath" and level == 0):
  5171             if (has_compositing_options == 1):
  5172                 if gui: gui.newline("", 2, level, None, [0.4,0.4,0.6])
  5173                 usecompo = luxProp(mat, "compo", "false")
  5174                 luxCollapse("compo", usecompo, "Compositing", "Enable Compositing options", gui, 2.0)
  5175                 if usecompo.get() == "true":
  5176                     if gui: gui.newline("", 2, level, None, [0.35,0.35,0.55])
  5177                     usecompoviz = luxProp(mat, "compo_viz", "false")
  5178                     luxCollapse("compo_viz", usecompoviz, "Visibility", "Enable Visibility Compositing options", gui, 2.0)
  5179                     if usecompoviz.get() == "true":
  5180                         if gui: gui.newline("View", 2, level, None, [0.35,0.35,0.55])
  5181                         compovizmat = luxProp(mat, "compo_viz_mat", "true")
  5182                         link += luxBool("compo_visible_material", compovizmat, "Material", "Enable View Visibility of Material", gui, 1.0)
  5183                         compovizemi = luxProp(mat, "compo_viz_emi", "true")
  5184                         link += luxBool("compo_visible_emission", compovizemi, "Emission", "Enable View Visibility of Emission", gui, 1.0)
  5185                         
  5186                         if gui: gui.newline("Indirect", 2, level, None, [0.35,0.35,0.55])
  5187                         compovizmati = luxProp(mat, "compo_viz_mati", "true")
  5188                         link += luxBool("compo_visible_indirect_material", compovizmati, "Material", "Enable InDirect Visibility of Material", gui, 1.0)
  5189                         compovizemii = luxProp(mat, "compo_viz_emii", "true")
  5190                         link += luxBool("compo_visible_indirect_emission", compovizemii, "Emission", "Enable InDirect Visibility of Emission", gui, 1.0)
  5191                     
  5192                     if gui: gui.newline("", 2, level, None, [0.4,0.4,0.6])
  5193                     overridealpha = luxProp(mat, "compo_o_alpha", "false")
  5194                     link += luxCollapse("compo_override_alpha", overridealpha, "Override Alpha", "Enable Manual control of alpha value", gui, 2.0)
  5195                     if overridealpha.get() == "true":
  5196                         if gui: gui.newline("Alpha", 2, level, None, [0.4,0.4,0.6])
  5197                         link += luxFloat("compo_override_alpha_value", luxProp(mat, "compo_o_alpha_v", 0.0), 0.0, 1.0, "Alpha", "Alpha Value", gui, 2.0, 1)
  5198                     usecolorkey = luxProp(mat, "compo_usekey", "false")
  5199                     if gui: gui.newline("", 2, level, None, [0.35,0.35,0.55])
  5200                     link += luxCollapse("compo_use_key", usecolorkey, "Chroma Key", "Enable Chroma Object key", gui, 2.0)
  5201                     if usecolorkey.get() == "true":
  5202                         if gui: gui.newline("Key", 2, level, None, [0.35,0.35,0.55])
  5203                         link += luxRGB("compo_key_color", luxProp(mat, "compo_key_color", "0.0 0.0 1.0"), 1.0, "key", "", gui, 2.0)
  5204 
  5205         # transformation options (common)
  5206         if (level == 0) and mattype.get() not in ['portal', 'null']:
  5207             if gui: gui.newline("", 2, level, None, [0.6,0.6,0.4])
  5208             usetransformation = luxProp(mat, "transformation", "false")
  5209             luxCollapse("usetransformation", usetransformation, "Texture Transformation", "Enable transformation option", gui, 2.0)
  5210             if usetransformation.get() == "true":
  5211                 scale = luxProp(mat, "3dscale", 1.0)
  5212                 rotate = luxProp(mat, "3drotate", "0 0 0")
  5213                 translate = luxProp(mat, "3dtranslate", "0 0 0")
  5214                 if gui:
  5215                     gui.newline("scale:", -2, level, icon_map3dparam)
  5216                     luxVectorUniform("scale", scale, 0.001, 1000.0, "scale", "scale-vector", gui, 2.0)
  5217                     gui.newline("rot:", -2, level, icon_map3dparam)
  5218                     luxVector("rotate", rotate, -360.0, 360.0, "rotate", "rotate-vector", gui, 2.0)
  5219                     gui.newline("move:", -2, level, icon_map3dparam)
  5220                     luxVector("translate", translate, -1000.0, 1000.0, "move", "translate-vector", gui, 2.0)
  5221                 str = ("TransformBegin\n\tScale %f %f %f\n"%( 1.0/scale.getVector()[0],1.0/scale.getVector()[1],1.0/scale.getVector()[2] ))+("\tRotate %f 1 0 0\n\tRotate %f 0 1 0\n\tRotate %f 0 0 1\n"%rotate.getVector())+("\tTranslate %f %f %f\n"%translate.getVector()) + str + "TransformEnd\n"
  5222 
  5223         # Object options (common)
  5224         if (level == 0) and (has_object_options == 1):
  5225             if gui: gui.newline("Mesh:", 2, level, icon, [0.6,0.6,0.4])
  5226             usesubdiv = luxProp(mat, "subdiv", "false")
  5227             luxBool("usesubdiv", usesubdiv, "Subdivision", "Enable Loop Subdivision options", gui, 1.0)
  5228             usedisp = luxProp(mat, "dispmap", "false")
  5229             luxBool("usedisp", usedisp, "Displacement Map", "Enable Displacement mapping options", gui, 1.0)
  5230             if usesubdiv.get() == "true" or usedisp.get() == "true":
  5231                 luxInt("sublevels", luxProp(mat, "sublevels", 2), 0, 12, "sublevels", "The number of levels of object subdivision", gui, 2.0)
  5232                 sharpbound = luxProp(mat, "sharpbound", "false")
  5233                 luxBool("sharpbound", sharpbound, "Sharpen Bounds", "Sharpen boundaries during subdivision", gui, 1.0)
  5234                 nsmooth = luxProp(mat, "nsmooth", "true")
  5235                 luxBool("nsmooth", nsmooth, "Smooth", "Smooth faces during subdivision", gui, 1.0)
  5236             if usedisp.get() == "true":
  5237                 (str,ll) = c((str,link), luxDispFloatTexture("dispmap", keyname, 0.1, -10, 10.0, "dispmap", "Displacement Mapping amount", mat, gui, level+1))
  5238                 luxFloat("sdoffset",  luxProp(mat, "sdoffset", 0.0), 0.0, 1.0, "Offset", "Offset for displacement map", gui, 2.0)
  5239                 usesubdiv.set("true")
  5240 
  5241         if mattype.get() == "light":
  5242             return (str, link)
  5243 
  5244         str += "MakeNamedMaterial \"%s\"%s\n"%(matname, link)
  5245     return (str, " \"string %s\" [\"%s\"]"%(luxname, matname))
  5246 
  5247 
  5248 def luxMaterial(mat, gui=None):
  5249     str = ""
  5250     if mat:
  5251         if luxProp(mat, "type", "").get()=="": # lux material not defined yet
  5252             print("Blender material \"%s\" has no lux material definition, converting..."%(mat.getName()))
  5253             try:
  5254                 convertMaterial(mat) # try converting the blender material to a lux material
  5255             except: pass
  5256         (str, link) = luxMaterialBlock("", "", "", mat, gui, 0)
  5257         if luxProp(mat, "type", "matte").get() != "light":
  5258             link = "NamedMaterial \"%s\""%(mat.getName())
  5259         # export emission options (no gui)
  5260         useemission = luxProp(mat, "emission", "false")
  5261         if useemission.get() == "true":
  5262             lightgroup = luxProp(mat, "light.lightgroup", "default")
  5263             if luxProp(Scene.GetCurrent(), "nolg", "false").get()!="true":
  5264                 link += "\n\tLightGroup \"%s\"\n"%lightgroup.get()
  5265             
  5266             (estr, elink) = luxLight("", "", mat, None, 0)
  5267             str += estr
  5268             link += "\n\tAreaLightSource \"area\" "+elink 
  5269             
  5270         luxProp(mat, "link", "").set("".join(link))
  5271         
  5272     return str
  5273         
  5274 
  5275 def luxVolume(mat, gui=None):
  5276     str = ""
  5277     if mat:
  5278         (str, link) = luxMaterialBlock("", "", "", mat, gui, 0)
  5279         luxProp(mat, "link", "").set("".join(link))
  5280     return str
  5281 
  5282 runRenderAfterExport = None
  5283 def CBluxExport(default, run):
  5284     global runRenderAfterExport
  5285     runRenderAfterExport = run
  5286     if default:
  5287         datadir = luxProp(Scene.GetCurrent(), "datadir", "").get()
  5288         if datadir=="": datadir = Blender.Get("datadir")
  5289         import os.path
  5290         if not os.path.exists(datadir):
  5291             Draw.PupMenu("ERROR: output directory does not exist!")
  5292             if LuxIsGUI:
  5293                 Draw.Redraw()
  5294             return
  5295         filename = datadir + os.sep + "default.lxs"
  5296         save_still(filename)
  5297     else:
  5298         Window.FileSelector(save_still, "Export", sys.makename(Blender.Get("filename"), ".lxs"))
  5299 
  5300 
  5301 def CBluxAnimExport(default, run, fileselect=True):
  5302     if default:
  5303         datadir = luxProp(Scene.GetCurrent(), "datadir", "").get()
  5304         if datadir=="": datadir = Blender.Get("datadir")
  5305         import os.path
  5306         if not os.path.exists(datadir):
  5307             Draw.PupMenu("ERROR: output directory does not exist!")
  5308             if LuxIsGUI:
  5309                 Draw.Redraw()
  5310             return
  5311         filename = datadir + os.sep + "default.lxs"
  5312         save_anim(filename)
  5313     else:
  5314         if fileselect:
  5315             Window.FileSelector(save_anim, "Export", sys.makename(Blender.Get("filename"), ".lxs"))
  5316         else:
  5317             datadir = luxProp(Scene.GetCurrent(), "datadir", "").get()
  5318             if datadir=="": datadir = Blender.Get("datadir")
  5319             filename = sys.makename(Blender.Get("filename") , ".lxs")
  5320             save_anim(filename)
  5321 
  5322 
  5323 # convert a Blender material to lux material
  5324 def convertMaterial(mat):
  5325     def dot(str):
  5326         if str != "": return str+"."
  5327         return str
  5328     def ddot(str):
  5329         if str != "": return str+":"
  5330         return str
  5331     def mapConstDict(value, constant_dict, lux_dict, default=None):
  5332         for k,v in constant_dict.items():
  5333             if (v == value) and (lux_dict.has_key(k)):
  5334                 return lux_dict[k]
  5335         return default
  5336 
  5337     def convertMapping(name, tex):
  5338         if tex.texco == Texture.TexCo["UV"]:
  5339             luxProp(mat, dot(name)+"mapping","").set("uv")
  5340             luxProp(mat, dot(name)+"uscale", 1.0).set(tex.size[0])
  5341             luxProp(mat, dot(name)+"vscale", 1.0).set(-tex.size[1])
  5342             luxProp(mat, dot(name)+"udelta", 0.0).set(tex.ofs[0]+0.5*(1.0-tex.size[0]))
  5343             luxProp(mat, dot(name)+"vdelta", 0.0).set(-tex.ofs[1]-0.5*(1.0-tex.size[1]))
  5344             if tex.mapping != Texture.Mappings["FLAT"]:
  5345                 print("Material Conversion Warning: for UV-texture-input only FLAT mapping is supported\n") 
  5346         else:
  5347             if tex.mapping == Texture.Mappings["FLAT"]:
  5348                 luxProp(mat, dot(name)+"mapping","").set("planar") # make planar-mapping convert correctly from blender(WYSIWYG)- jens
  5349                 luxProp(mat, dot(name)+"v1", "1.0 1.0 1.0").setVector((0.5*tex.size[0], 0.0, 0.0))
  5350                 luxProp(mat, dot(name)+"v2", "0.0 0.0 0.0").setVector((0.0, -0.5*tex.size[1], -0.0))
  5351                 luxProp(mat, dot(name)+"udelta", 0.0).set(tex.ofs[0]+0.5)
  5352                 luxProp(mat, dot(name)+"vdelta", 0.0).set(-tex.ofs[1]-0.5)
  5353             elif tex.mapping == Texture.Mappings["TUBE"]:
  5354                 luxProp(mat, dot(name)+"mapping","").set("cylindrical")
  5355             elif tex.mapping == Texture.Mappings["SPHERE"]:
  5356                 luxProp(mat, dot(name)+"mapping","").set("spherical")
  5357             else: luxProp(mat, dot(name)+"mapping","").set("planar")
  5358 
  5359         luxProp(mat, dot(name)+"3dscale", "1.0 1.0 1.0").setVector((1.0/tex.size[0], 1.0/tex.size[1], 1.0/tex.size[2]))
  5360         luxProp(mat, dot(name)+"3dtranslate", "0.0 0.0 0.0").setVector((-tex.ofs[0], -tex.ofs[1], -tex.ofs[2]))
  5361 
  5362     def convertColorband(colorband):
  5363         # colorbands are not supported in lux - so lets extract a average low-side and high-side color
  5364         cb = [colorband[0]] + colorband[:] + [colorband[-1]]
  5365         cb[0][4], cb[-1][4] = 0.0, 1.0
  5366         low, high = [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]
  5367         for i in range(1, len(cb)):
  5368             for c in range(4):
  5369                 low[c] += (cb[i-1][c]*(1.0-cb[i-1][4]) + cb[i][c]*(1.0-cb[i][4])) * (cb[i][4]-cb[i-1][4])
  5370                 high[c] += (cb[i-1][c]*cb[i-1][4] + cb[i][c]*cb[i][4]) * (cb[i][4]-cb[i-1][4])
  5371         return low, high
  5372 
  5373     def createLuxTexture(name, tex):
  5374         texture = tex.tex
  5375         convertMapping(name, tex)
  5376         if (texture.type == Texture.Types["IMAGE"]) and (texture.image) and (texture.image.filename!=""):
  5377             luxProp(mat, dot(name)+"texture", "").set("imagemap")
  5378             luxProp(mat, dot(name)+"filename", "").set(texture.image.filename)
  5379             luxProp(mat, dot(name)+"wrap", "").set(mapConstDict(texture.extend, Texture.ExtendModes, {"REPEAT":"repeat", "EXTEND":"clamp", "CLIP":"black"}, ""))
  5380         else:
  5381             if tex.texco != Texture.TexCo["GLOB"]:
  5382                 print("Material Conversion Warning: procedural textures supports global mapping only\n")
  5383             noiseDict = {"BLENDER":"blender_original", "CELLNOISE":"cell_noise", "IMPROVEDPERLIN":"improved_perlin", "PERLIN":"original_perlin", "VORONOICRACKLE":"voronoi_crackle", "VORONOIF1":"voronoi_f1", "VORONOIF2":"voronoi_f2", "VORONOIF2F1":"voronoi_f2f1", "VORONOIF3":"voronoi_f3", "VORONOIF4":"voronoi_f4"}
  5384             luxProp(mat, dot(name)+"bright", 1.0).set(texture.brightness)
  5385             luxProp(mat, dot(name)+"contrast", 1.0).set(texture.contrast)
  5386             if texture.type == Texture.Types["CLOUDS"]:
  5387                 luxProp(mat, dot(name)+"texture", "").set("blender_clouds")
  5388                 luxProp(mat, dot(name)+"mtype", "").set(mapConstDict(texture.stype, Texture.STypes, {"CLD_DEFAULT":"default", "CLD_COLOR":"color"}, ""))
  5389                 luxProp(mat, dot(name)+"noisetype", "").set({"soft":"soft_noise", "hard":"hard_noise"}[texture.noiseType])
  5390                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5391                 luxProp(mat, dot(name)+"noisedepth", 2).set(texture.noiseDepth)
  5392                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5393             elif texture.type == Texture.Types["WOOD"]:
  5394                 luxProp(mat, dot(name)+"texture", "").set("blender_wood")
  5395                 luxProp(mat, dot(name)+"mtype", "").set(mapConstDict(texture.stype, Texture.STypes, {"WOD_BANDS":"bands", "WOD_RINGS":"rings", "WOD_BANDNOISE":"bandnoise", "WOD_RINGNOISE":"ringnoise"}, ""))
  5396                 luxProp(mat, dot(name)+"noisebasis2", "").set(mapConstDict(texture.noiseBasis2, Texture.Noise, {"SINE":"sin", "SAW":"saw", "TRI":"tri"}, ""))
  5397                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5398                 luxProp(mat, dot(name)+"noisetype", "").set({"soft":"soft_noise", "hard":"hard_noise"}[texture.noiseType])
  5399                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5400                 luxProp(mat, dot(name)+"turbulance", 0.25).set(texture.turbulence)
  5401             elif texture.type == Texture.Types["MUSGRAVE"]:
  5402                 luxProp(mat, dot(name)+"texture", "").set("blender_musgrave")
  5403                 luxProp(mat, dot(name)+"mtype", "").set(mapConstDict(texture.stype, Texture.STypes, {"MUS_MFRACTAL":"multifractal", "MUS_RIDGEDMF":"ridged_multifractal", "MUS_HYBRIDMF":"hybrid_multifractal", "MUS_HTERRAIN":"hetero_terrain", "MUS_FBM":"fbm"}, ""))
  5404                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5405                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5406                 # bug in blender python API: value of "hFracDim" is casted to Integer instead of Float (reported to Ideasman42 - will be fixed after Blender 2.47)
  5407                 if texture.hFracDim != 0.0: luxProp(mat, dot(name)+"h", 1.0).set(texture.hFracDim) # bug in blender API, "texture.hFracDim" returns a Int instead of a Float
  5408                 else: luxProp(mat, dot(name)+"h", 1.0).set(0.5) # use a default value
  5409                 # bug in blender python API: values "offset" and "gain" are missing in Python-API (reported to Ideasman42 - will be fixed after Blender 2.47)
  5410                 try:
  5411                     luxProp(mat, dot(name)+"offset", 1.0).set(texture.offset)
  5412                     luxProp(mat, dot(name)+"gain", 1.0).set(texture.gain)
  5413                 except AttributeError: pass
  5414                 luxProp(mat, dot(name)+"lacu", 2.0).set(texture.lacunarity)
  5415                 luxProp(mat, dot(name)+"octs", 2.0).set(texture.octs)
  5416                 luxProp(mat, dot(name)+"outscale", 1.0).set(texture.iScale)
  5417             elif texture.type == Texture.Types["MARBLE"]:
  5418                 luxProp(mat, dot(name)+"texture", "").set("blender_marble")
  5419                 luxProp(mat, dot(name)+"mtype", "").set(mapConstDict(texture.stype, Texture.STypes, {"MBL_SOFT":"soft", "MBL_SHARP":"sharp", "MBL_SHARPER":"sharper"}, ""))
  5420                 luxProp(mat, dot(name)+"noisetype", "").set({"soft":"soft_noise", "hard":"hard_noise"}[texture.noiseType])
  5421                 luxProp(mat, dot(name)+"turbulance", 0.25).set(texture.turbulence)
  5422                 luxProp(mat, dot(name)+"noisedepth", 2).set(texture.noiseDepth)
  5423                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5424                 luxProp(mat, dot(name)+"noisebasis2", "").set(mapConstDict(texture.noiseBasis2, Texture.Noise, {"SINE":"sin", "SAW":"saw", "TRI":"tri"}, ""))
  5425                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5426             elif texture.type == Texture.Types["VORONOI"]:
  5427                 luxProp(mat, dot(name)+"texture", "").set("blender_voronoi")
  5428                 luxProp(mat, dot(name)+"distmetric", "").set({0:"actual_distance", 1:"distance_squared", 2:"manhattan", 3:"chebychev", 4:"minkovsky_half", 5:"minkovsky_four", 6:"minkovsky"}[texture.distMetric])
  5429                 luxProp(mat, dot(name)+"outscale", 1.0).set(texture.iScale)
  5430                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5431                 luxProp(mat, dot(name)+"minkosky_exp", 2.5).set(texture.exp)
  5432                 luxProp(mat, dot(name)+"w1", 1.0).set(texture.weight1)
  5433                 luxProp(mat, dot(name)+"w2", 0.0).set(texture.weight2)
  5434                 luxProp(mat, dot(name)+"w3", 0.0).set(texture.weight3)
  5435                 luxProp(mat, dot(name)+"w4", 0.0).set(texture.weight4)
  5436             elif texture.type == Texture.Types["NOISE"]:
  5437                 luxProp(mat, dot(name)+"texture", "").set("blender_noise")
  5438             elif texture.type == Texture.Types["DISTNOISE"]:
  5439                 luxProp(mat, dot(name)+"texture", "").set("blender_distortednoise")
  5440                 luxProp(mat, dot(name)+"distamount", 1.0).set(texture.distAmnt)
  5441                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5442                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5443                 luxProp(mat, dot(name)+"noisebasis2", "").set(mapConstDict(texture.noiseBasis2, Texture.Noise, noiseDict, ""))
  5444             elif texture.type == Texture.Types["MAGIC"]:
  5445                 luxProp(mat, dot(name)+"texture", "").set("blender_magic")
  5446                 luxProp(mat, dot(name)+"turbulance", 0.25).set(texture.turbulence)
  5447                 luxProp(mat, dot(name)+"noisedepth", 2).set(texture.noiseDepth)
  5448             elif texture.type == Texture.Types["STUCCI"]:
  5449                 luxProp(mat, dot(name)+"texture", "").set("blender_stucci")
  5450                 luxProp(mat, dot(name)+"mtype", "").set(mapConstDict(texture.stype, Texture.STypes, {"STC_PLASTIC":"Plastic", "MSTC_WALLIN":"Wall In", "STC_WALLOUT":"Wall Out"}, ""))
  5451                 luxProp(mat, dot(name)+"noisetype", "").set({"soft":"soft_noise", "hard":"hard_noise"}[texture.noiseType])
  5452                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5453                 luxProp(mat, dot(name)+"turbulance", 0.25).set(texture.turbulence)
  5454                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5455             elif texture.type == Texture.Types["BLEND"]:
  5456                 luxProp(mat, dot(name)+"texture", "").set("blender_blend")
  5457                 luxProp(mat, dot(name)+"type", "").set(mapConstDict(texture.stype, Texture.STypes, {"BLN_LIN":"lin", "BLN_QUAD":"quad", "BLN_EASE":"ease", "BLN_DIAG":"diag", "BLN_SPHERE":"sphere", "BLN_HALO":"halo", "BLN_RADIAL":"radial"}, ""))
  5458                 luxProp(mat, dot(name)+"flipXY", "false").set({0:"false", 1:"true"}[texture.rot90])
  5459             else:
  5460                 print("Material Conversion Warning: SORRY, this procedural texture isn\'t implemented in conversion\n")
  5461 
  5462     def convertTextures(basename, texs, type="float", channel="col", val=1.0):
  5463         tex = texs.pop()
  5464         texture = tex.tex
  5465         isImagemap = (texture.type == Texture.Types["IMAGE"]) and (texture.image) and (texture.image.filename!="")
  5466         if channel == "col":
  5467             if texture.flags & Texture.Flags["COLORBAND"] > 0:
  5468                 cbLow, cbHigh = convertColorband(texture.colorband)
  5469                 val1, alpha1, val2, alpha2 = (cbLow[0],cbLow[1],cbLow[2]), cbLow[3]*tex.colfac, (cbHigh[0], cbHigh[1], cbHigh[2]), cbHigh[3]*tex.colfac
  5470                 if tex.noRGB:
  5471                     lum1, lum2 = (val1[0]+val1[1]+val1[2])/3.0, (val2[0]+val2[1]+val2[2])/3.0
  5472                     val1, val2 = (tex.col[0]*lum1,tex.col[1]*lum1,tex.col[2]*lum1), (tex.col[0]*lum2,tex.col[1]*lum2,tex.col[2]*lum2)
  5473             elif isImagemap and not(tex.noRGB): val1, alpha1, val2, alpha2 = (0.0,0.0,0.0), tex.colfac, (1.0,1.0,1.0), tex.colfac
  5474             else: val1, alpha1, val2, alpha2 = tex.col, 0.0, tex.col, tex.colfac
  5475         elif channel == "nor": val1, alpha1, val2, alpha2 = tex.norfac * 0.01, 0.0, tex.norfac * 0.01, 1.0
  5476         else: val1, alpha1, val2, alpha2 = 1.0, 0.0, 1.0, tex.varfac
  5477         if (tex.neg)^((channel=="nor") and (tex.mtNor<0)): val1, alpha1, val2, alpha2 = val2, alpha2, val1, alpha1
  5478         luxProp(mat, dot(basename)+"textured", "").set("true")
  5479 
  5480         name = basename
  5481         if (alpha1 < 1.0) or (alpha2 < 1.0): # texture with transparency
  5482             luxProp(mat, dot(basename)+"texture", "").set("mix")
  5483             if alpha1 == alpha2: # constant alpha
  5484                 luxProp(mat, ddot(basename)+"amount.value", 1.0).set(alpha1)
  5485             else:
  5486                 createLuxTexture(ddot(basename)+"amount", tex)
  5487                 luxProp(mat, ddot(basename)+"amount:tex1.value", 1.0).set(alpha1)
  5488                 luxProp(mat, ddot(basename)+"amount:tex2.value", 1.0).set(alpha2)
  5489             # transparent to next texture
  5490             name = ddot(basename)+"tex1"
  5491             if len(texs) > 0:
  5492                 convertTextures(ddot(basename)+"tex1", texs, type, channel, val)
  5493             else:
  5494                 if type=="float": luxProp(mat, ddot(basename)+"tex1.value", 1.0).set(val)
  5495                 else: luxProp(mat, ddot(basename)+"tex1.value", "1.0 1.0 1.0").setRGB((val[0], val[1], val[2]))
  5496             name = ddot(basename)+"tex2"
  5497         if val1 == val2: # texture with different colors / value
  5498             if type == "col": luxProp(mat, dot(name)+"value", "1.0 1.0 1.0").setRGB(val1)
  5499             else: luxProp(mat, dot(name)+"value", 1.0).set(val1)
  5500         else:
  5501             createLuxTexture(name, tex)
  5502             if type == "col": luxProp(mat, ddot(name)+"tex1.value", "1.0 1.0 1.0").setRGB(val1)
  5503             else: luxProp(mat, ddot(name)+"tex1.value", 1.0).set(val1)
  5504             if type == "col": luxProp(mat, ddot(name)+"tex2.value", "1.0 1.0 1.0").setRGB(val2)
  5505             else: luxProp(mat, ddot(name)+"tex2.value", 1.0).set(val2)
  5506 
  5507 
  5508     def convertDiffuseTexture(name):
  5509         texs = []
  5510         for tex in mat.getTextures():
  5511             if tex and (tex.mapto & Texture.MapTo["COL"] > 0) and (tex.tex) and (tex.tex.type != Texture.Types["NONE"]): texs.append(tex)
  5512         if len(texs) > 0:
  5513             luxProp(mat, name, "").setRGB((mat.ref, mat.ref, mat.ref))
  5514             convertTextures(name, texs, "col", "col", (mat.R, mat.G, mat.B))
  5515     def convertSpecularTexture(name):
  5516         texs = []
  5517         for tex in mat.getTextures():
  5518             if tex and (tex.mapto & Texture.MapTo["CSP"] > 0) and (tex.tex) and (tex.tex.type != Texture.Types["NONE"]): texs.append(tex)
  5519         if len(texs) > 0:
  5520             luxProp(mat, name, "").setRGB((mat.ref*mat.spec, mat.ref*mat.spec, mat.ref*mat.spec))
  5521             convertTextures(name, texs, "col", "col", (mat.specR, mat.specG, mat.specB))
  5522     def convertMirrorTexture(name):
  5523         texs = []
  5524         for tex in mat.getTextures():
  5525             if tex and (tex.mapto & Texture.MapTo["CMIR"] > 0) and (tex.tex) and (tex.tex.type != Texture.Types["NONE"]): texs.append(tex)
  5526         if len(texs) > 0:
  5527             luxProp(mat, name, "").setRGB((mat.ref, mat.ref, mat.ref))
  5528             convertTextures(name, texs, "col", "col", (mat.mirR, mat.mirG, mat.mirB))
  5529     def convertBumpTexture(basename):
  5530         texs = []
  5531         for tex in mat.getTextures():
  5532             if tex and (tex.mapto & Texture.MapTo["NOR"] > 0) and (tex.tex) and (tex.tex.type != Texture.Types["NONE"]): texs.append(tex)
  5533         if len(texs) > 0:
  5534             name = basename+":bumpmap"
  5535             luxProp(mat, basename+".usebump", "").set("true")
  5536             luxProp(mat, dot(name)+"textured", "").set("true")
  5537             luxProp(mat, name, "").set(1.0)
  5538             convertTextures(name, texs, "float", "nor", 0.0)
  5539 
  5540     def makeMatte(name):
  5541         luxProp(mat, dot(name)+"type", "").set("matte")
  5542         luxProp(mat, name+":Kd", "").setRGB((mat.R*mat.ref, mat.G*mat.ref, mat.B*mat.ref))
  5543         convertDiffuseTexture(name+":Kd")
  5544         convertBumpTexture(name)
  5545     def makeGlossy(name, roughness):
  5546         luxProp(mat, dot(name)+"type", "").set("glossy")
  5547         luxProp(mat, name+":Kd", "").setRGB((mat.R*mat.ref, mat.G*mat.ref, mat.B*mat.ref))
  5548         luxProp(mat, name+":Ks", "").setRGB((mat.specR*mat.spec*0.5, mat.specG*mat.spec*0.5, mat.specB*mat.spec*0.5))
  5549         luxProp(mat, name+":uroughness", 0.0).set(roughness)
  5550         luxProp(mat, name+":vroughness", 0.0).set(roughness)
  5551         convertDiffuseTexture(name+":Kd")
  5552         convertSpecularTexture(name+":Ks")
  5553         convertBumpTexture(name)
  5554     def makeMirror(name):
  5555         luxProp(mat, dot(name)+"type", "").set("mirror")
  5556         luxProp(mat, name+":Kr", "").setRGB((mat.mirR, mat.mirG, mat.mirB))
  5557         convertMirrorTexture(name+":Kr")
  5558         convertBumpTexture(name)
  5559     def makeGlass(name):
  5560         luxProp(mat, dot(name)+"type", "").set("glass")
  5561         luxProp(mat, name+":Kr", "").setRGB((0.0, 0.0, 0.0))
  5562         luxProp(mat, name+":Kt", "").setRGB((mat.R, mat.G, mat.B))
  5563         luxProp(mat, name+":index.iorusepreset", "").set("false")
  5564         luxProp(mat, name+":index", 0.0).set(mat.getIOR())
  5565         convertMirrorTexture(name+":Kr")
  5566         convertDiffuseTexture(name+":Kt")
  5567         convertBumpTexture(name)
  5568     def makeRoughglass(name, roughness):
  5569         luxProp(mat, dot(name)+"type", "").set("roughglass")
  5570         luxProp(mat, name+":Kr", "").setRGB((0.0, 0.0, 0.0))
  5571         luxProp(mat, name+":Kt", "").setRGB((mat.R, mat.G, mat.B))
  5572         luxProp(mat, name+":index.iorusepreset", "").set("false")
  5573         luxProp(mat, name+":index", 0.0).set(mat.getIOR())
  5574         luxProp(mat, name+":uroughness", 0.0).set(roughness)
  5575         luxProp(mat, name+":vroughness", 0.0).set(roughness)
  5576         convertMirrorTexture(name+":Kr")
  5577         convertDiffuseTexture(name+":Kt")
  5578         convertBumpTexture(name)
  5579     print("convert Blender material \"%s\" to lux material"%(mat.name))
  5580     mat.properties['luxblend'] = {}
  5581     if mat.emit > 0.0001:
  5582         luxProp(mat, "type", "").set("light")
  5583         luxProp(mat, "light.l", "").setRGB((mat.R, mat.G, mat.B))
  5584         luxProp(mat, "light.gain", 1.0).set(mat.emit)
  5585         return
  5586     alpha = mat.alpha
  5587     if not(mat.mode & Material.Modes.RAYTRANSP): alpha = 1.0
  5588     alpha0name, alpha1name = "", ""
  5589     if (alpha > 0.0) and (alpha < 1.0):
  5590         luxProp(mat, "type", "").set("mix")
  5591         luxProp(mat, ":amount", 0.0).set(alpha)
  5592         alpha0name, alpha1name = "mat2", "mat1"
  5593     if alpha > 0.0:
  5594         mirror = mat.rayMirr
  5595         if not(mat.mode & Material.Modes.RAYMIRROR): mirror = 0.0
  5596         mirror0name, mirror1name = alpha1name, alpha1name
  5597         if (mirror > 0.0) and (mirror < 1.0):
  5598             luxProp(mat, dot(alpha1name)+"type", "").set("mix")
  5599             luxProp(mat, alpha1name+":amount", 0.0).set(1.0 - mirror)
  5600             mirror0name, mirror1name = ddot(alpha1name)+"mat1", ddot(alpha1name)+"mat2"
  5601         if mirror > 0.0:
  5602             if mat.glossMir < 1.0: makeGlossy(mirror1name, 1.0-mat.glossMir**2)
  5603             else: makeMirror(mirror1name)
  5604         if mirror < 1.0:
  5605             if mat.spec > 0.0: makeGlossy(mirror0name, 1.0/mat.hard)
  5606             else: makeMatte(mirror0name)
  5607     if alpha < 1.0:
  5608         if mat.glossTra < 1.0: makeRoughnessGlass(alpha0name, 1.0-mat.glossTra**2)
  5609         else: makeGlass(alpha0name)
  5610 
  5611 def convertAllMaterials():
  5612     for mat in Material.Get(): convertMaterial(mat)
  5613 
  5614 
  5615 
  5616 
  5617 ### Connect LRMDB ###
  5618 ConnectLrmdb = False
  5619 try:
  5620     import socket  # try import of socket library
  5621     ConnectLrmdb = True
  5622     def downloadLRMDB(mat, id):
  5623         if id.isalnum():
  5624             DrawProgressBar(0.0,'Getting Material #'+id)
  5625             try:
  5626                 HOST = 'www.luxrender.net'
  5627                 GET = '/lrmdb/en/material/download/'+id
  5628                 PORT = 80
  5629                 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  5630                 sock.connect((HOST, PORT))
  5631                 sock.send("GET %s HTTP/1.0\r\nHost: %s\r\n\r\n" % (GET, HOST))
  5632                 data = sock.recv(1024)
  5633                 str = ""
  5634                 while len(data):
  5635                     str += data
  5636                     data = sock.recv(1024)
  5637                 sock.close()
  5638                 if str.split("\n", 1)[0].find("200") < 0:
  5639                     print("ERROR: server error: %s"%(str.split("\n",1)[0]))
  5640                     return None
  5641                 str = (str.split("\r\n\r\n")[1]).strip()
  5642                 if (str[0]=="{") and (str[-1]=="}"):
  5643                     return str2MatTex(str)
  5644                 print("ERROR: downloaded data is not a material or texture")
  5645             except:
  5646                 print("ERROR: download failed")
  5647                 
  5648             DrawProgressBar(1.0,'')
  5649         else:
  5650             print("ERROR: material id is not valid")
  5651         return None
  5652     
  5653         
  5654     #===========================================================================
  5655     # COOKIETRANSPORT
  5656     #===========================================================================
  5657     
  5658     #--------------------------------------------------------------------------- 
  5659     # IMPORTS
  5660     import cookielib, urllib2, xmlrpclib
  5661     
  5662     #---------------------------------------------------------------------------
  5663     # pilfered from
  5664     # https://fedorahosted.org/python-bugzilla/browser/bugzilla.py?rev=e6f699f06e92b1e49b1b8d2c8fbe89d9425a4a9a
  5665     class CookieTransport(xmlrpclib.Transport):
  5666         '''
  5667         A subclass of xmlrpclib.Transport that supports cookies.
  5668         '''
  5669         
  5670         cookiejar = None
  5671         scheme = 'http'
  5672         verbose = None
  5673     
  5674         # Cribbed from xmlrpclib.Transport.send_user_agent 
  5675         def send_cookies(self, connection, cookie_request):
  5676             '''
  5677             Send all the cookie data that we have received
  5678             '''
  5679             
  5680             if self.cookiejar is None:
  5681                 self.cookiejar = cookielib.CookieJar()
  5682             elif self.cookiejar:
  5683                 # Let the cookiejar figure out what cookies are appropriate
  5684                 self.cookiejar.add_cookie_header(cookie_request)
  5685                 # Pull the cookie headers out of the request object...
  5686                 cookielist = list()
  5687                 for header, value in cookie_request.header_items():
  5688                     if header.startswith('Cookie'):
  5689                         cookielist.append([header, value])
  5690                 # ...and put them over the connection
  5691                 for header, value in cookielist:
  5692                     connection.putheader(header, value)
  5693     
  5694         # This is the same request() method from xmlrpclib.Transport,
  5695         # with a couple additions noted below
  5696         def request(self, host, handler, request_body, verbose=0):
  5697             '''
  5698             Handle the request
  5699             '''
  5700             
  5701             host_connection = self.make_connection(host)
  5702             if verbose:
  5703                 host_connection.set_debuglevel(1)
  5704     
  5705             # ADDED: construct the URL and Request object for proper cookie handling
  5706             request_url = "%s://%s/" % (self.scheme, host)
  5707             cookie_request  = urllib2.Request(request_url) 
  5708     
  5709             self.send_request(host_connection, handler, request_body)
  5710             self.send_host(host_connection, host) 
  5711             
  5712             # ADDED. creates cookiejar if None.
  5713             self.send_cookies(host_connection, cookie_request)
  5714             self.send_user_agent(host_connection)
  5715             self.send_content(host_connection, request_body)
  5716     
  5717             errcode, errmsg, headers = host_connection.getreply()
  5718     
  5719             # ADDED: parse headers and get cookies here
  5720             class CookieResponse:
  5721                 '''
  5722                 fake a response object that we can fill with the headers above
  5723                 '''
  5724                 
  5725                 def __init__(self, headers):
  5726                     self.headers = headers
  5727                     
  5728                 def info(self):
  5729                     return self.headers
  5730                 
  5731             cookie_response = CookieResponse(headers)
  5732             
  5733             # Okay, extract the cookies from the headers
  5734             self.cookiejar.extract_cookies(cookie_response, cookie_request)
  5735             
  5736             # And write back any changes
  5737             # DH THIS DOESN'T WORK
  5738             # self.cookiejar.save(self.cookiejar.filename)
  5739     
  5740             if errcode != 200:
  5741                 raise xmlrpclib.ProtocolError(
  5742                     host + handler,
  5743                     errcode, errmsg,
  5744                     headers
  5745                 )
  5746     
  5747             self.verbose = verbose
  5748     
  5749             try:
  5750                 sock = host_connection._conn.sock
  5751             except AttributeError:
  5752                 sock = None
  5753     
  5754             return self._parse_response(host_connection.getfile(), sock)
  5755     
  5756 
  5757     #===========================================================================
  5758     # LRMDB Integration
  5759     #===========================================================================
  5760     class lrmdb:
  5761         host              = 'http://www.luxrender.net/lrmdb/ixr'
  5762         
  5763         username          = ""
  5764         password          = ""
  5765         logged_in         = False
  5766         
  5767         SERVER            = None
  5768         
  5769         last_error_str    = None
  5770         
  5771         def last_error(self):
  5772             return self.last_error_str #'LRMDB Connector: %s' %
  5773         
  5774         def login(self):
  5775             try:
  5776                 result = self.SERVER.user.login(
  5777                     self.username,
  5778                     self.password
  5779                 )
  5780                 if not result:
  5781                     raise
  5782                 else:
  5783                     self.logged_in = True
  5784                     return True
  5785             except:
  5786                 self.last_error_str = 'Login Failed'
  5787                 self.logged_in = False
  5788                 return False
  5789             
  5790         def submit_object(self, mat, basekey, tex):
  5791             if not self.check_creds(): return False
  5792             
  5793             try:
  5794                 result = 'Unknown Error'
  5795                 
  5796                 if tex:
  5797                     name = Draw.PupStrInput('Name: ', '', 32)
  5798                 else:
  5799                     name = mat.name
  5800                 
  5801                 result = self.SERVER.object.submit(
  5802                     name,
  5803                     MatTex2dict( getMatTex(mat, basekey, tex), tex )
  5804                 )
  5805                 if result is not True:
  5806                     raise
  5807                 else:
  5808                     return True
  5809             except:
  5810                 self.last_error_str = 'Submit failed: %s' % result
  5811                 return False
  5812         
  5813         def check_creds(self):
  5814             if self.SERVER is None:
  5815                 try:
  5816                     self.SERVER = xmlrpclib.ServerProxy(self.host, transport=CookieTransport())
  5817                 except:
  5818                     self.last_error_str = 'ServerProxy init failed'
  5819                     return False
  5820             
  5821             
  5822             if not self.logged_in:
  5823                 #if self.username is "":
  5824                 self.request_username()
  5825                 
  5826                 #if self.password is "":
  5827                 self.request_password()
  5828                     
  5829                 return self.login()
  5830             else:
  5831                 return True
  5832                 
  5833         def request_username(self):
  5834             self.username = Draw.PupStrInput("Username:", self.username, 32)
  5835             
  5836         def request_password(self):
  5837             self.password = Draw.PupStrInput("Password:", self.password, 32)
  5838 
  5839     lrmdb_connector = lrmdb()
  5840         
  5841     
  5842 except: print("WARNING: LRMDB support not available")
  5843 
  5844 
  5845 
  5846 ### MatTex functions ###
  5847 ### MatTex : is a dictionary of material or texture properties
  5848 
  5849 def getMatTex(mat, basekey='', tex=False):
  5850     global usedproperties, usedpropertiesfilterobj
  5851     usedproperties = {}
  5852     usedpropertiesfilterobj = mat
  5853     luxMaterial(mat)
  5854     dict = {}
  5855     for k,v in usedproperties.items():
  5856         if k[:len(basekey)]==basekey:
  5857             if k[-9:] != '.textured':
  5858                 name = k[len(basekey):]
  5859                 if name == ".type": name = "type"
  5860                 dict[name] = v
  5861     dict["__type__"] = ["material","texture"][bool(tex)]
  5862     return dict
  5863 
  5864 def putMatTex(mat, dict, basekey='', tex=None):
  5865     if dict and (tex!=None) and (tex ^ (dict.has_key("__type__") and (dict["__type__"]=="texture"))):
  5866         print("ERROR: Can't apply %s as %s"%(["texture","material"][bool(tex)],["material","texture"][bool(tex)]))
  5867         return
  5868     if dict:
  5869         # remove all current properties in mat that starts with basekey
  5870         try:
  5871             d = mat.properties['luxblend']
  5872             for k,v in d.convert_to_pyobject().items():
  5873                 kn = k
  5874                 if k[:7]=="__hash:":    # decode if entry is hashed (cause of 32chars limit)
  5875                     l = v.split(" = ")
  5876                     kn = l[0]
  5877                 if kn[:len(basekey)]==basekey:
  5878                     del mat.properties['luxblend'][k]
  5879         except: print("error") # pass
  5880         # assign loaded properties
  5881         for k,v in dict.items():
  5882             try:
  5883                 if (basekey!="") and (k=="type"): k = ".type"
  5884                 # zuegs: following two lines should fix issue http://www.luxrender.net/forum/viewtopic.php?f=16&t=1618&p=14512#p14512
  5885                 if (basekey!="") and ((k[0]!=".") and (k[0]!=":")): k = ":"+k
  5886                 if (basekey=="") and (k[0:4]==":mat"): k = k[1:]
  5887                 luxProp(mat, basekey+k, None).set(v)
  5888                 if k[-8:] == '.texture':
  5889                     luxProp(mat, basekey+k[:-8]+'.textured', 'false').set('true')
  5890             except: pass
  5891 
  5892 
  5893 LBX_VERSION = '0.7'
  5894 
  5895 def MatTex2dict(d, tex = None):
  5896     global LBX_VERSION
  5897     
  5898     if LBX_VERSION == '0.6':
  5899     
  5900         if tex is not None and tex == True:
  5901             d['LUX_DATA'] = 'TEXTURE'
  5902         else:
  5903             d['LUX_DATA'] = 'MATERIAL'
  5904         
  5905         d['LUX_VERSION'] = '0.6'
  5906         
  5907         return d
  5908     
  5909     elif LBX_VERSION == '0.7':
  5910         definition = []
  5911         for k in d.keys():
  5912             if type(d[k]) == types.IntType:
  5913                 t = 'integer'
  5914             if type(d[k]) == types.FloatType:
  5915                 t = 'float'
  5916             if type(d[k]) == types.BooleanType:
  5917                 t = 'bool'
  5918             if type(d[k]) == types.StringType:
  5919                 l=None
  5920                 try:
  5921                     l = d[k].split(" ")
  5922                 except: pass
  5923                 if l==None or len(l)!=3:
  5924                     t = 'string'
  5925                 else:
  5926                     t = 'vector'
  5927                 
  5928             definition.append([ t, k, d[k] ])
  5929         
  5930         
  5931         lbx = {
  5932             'type': d['__type__'],
  5933             'version': '0.7',
  5934             'definition': definition,
  5935             'metadata': [
  5936                 ['string', 'generator', 'luxblend'],
  5937             ]
  5938         }
  5939         
  5940         return lbx
  5941 
  5942 def format_dictStr(dictStr):
  5943     result = ''
  5944     pos = 0
  5945     indentStr = '  '
  5946     newLine = '\n'
  5947     
  5948     for char in dictStr:
  5949         if char in ['}', ']']:
  5950             result += newLine
  5951             pos -= 1
  5952             for j in range(0,pos):
  5953                 result += indentStr
  5954                 
  5955         result += char
  5956         
  5957         if char in [',', '{', '[']:
  5958             result += newLine
  5959             if char in ['{', '[']:
  5960                 pos += 1
  5961             for j in range(0,pos):
  5962                 result += indentStr
  5963             
  5964     return result
  5965 
  5966 
  5967 def MatTex2str(d, tex = None):
  5968     global LBX_VERSION
  5969     
  5970     if LBX_VERSION == '0.6':
  5971         return format_dictStr(str( MatTex2dict(d, tex) )) #.replace(", \'", ",\n\'")
  5972     
  5973     elif LBX_VERSION == '0.7':
  5974         return format_dictStr(str( MatTex2dict(d, tex) )) #.replace("], \'", "],\r\n\'").replace("[","\r\n\t[")
  5975         
  5976 
  5977 def str2MatTex(s, tex = None):    # todo: this is not absolutely save from attacks!!!
  5978     global LBX_VERSION
  5979     
  5980     s = s.strip()
  5981     if (s[0]=='{') and (s[-1]=='}'):
  5982         d = eval(s, dict(__builtins__=None))
  5983         if type(d)==types.DictType:
  5984             
  5985             
  5986             if LBX_VERSION == '0.6':
  5987             
  5988                 if tex is not None and tex == True:
  5989                     test_str = 'TEXTURE'
  5990                 else:
  5991                     test_str = 'MATERIAL'
  5992                     
  5993                 if   ('LUX_DATA' in d.keys() and d['LUX_DATA'] == test_str) \
  5994                 and  ('LUX_VERSION' in d.keys() and (d['LUX_VERSION'] == '0.6' or d['LUX_VERSION'] == 0.6)):
  5995                     return d
  5996                 else:
  5997                     reason = 'Missing/incorrect metadata'
  5998                     
  5999             elif LBX_VERSION == '0.7':
  6000                 
  6001                 def lb_list_to_dict(list):
  6002                     d = {}
  6003                     for t, k, v in list:
  6004                         if t == 'float':
  6005                             v = float(v)
  6006                             
  6007                         d[k] = v
  6008                     return d
  6009                 
  6010                 if   ('version' in d.keys() and d['version'] in ['0.6', '0.7']) \
  6011                 and  ('type' in d.keys() and d['type'] in ['material', 'texture']) \
  6012                 and  ('definition' in d.keys()):
  6013                     
  6014                     
  6015                     try:
  6016                         definition = lb_list_to_dict(d['definition'])
  6017                         
  6018                         if 'metadata' in d.keys():
  6019                             definition.update( lb_list_to_dict(d['metadata']) )
  6020                         
  6021                         return definition
  6022                     except:
  6023                         reason = 'Incorrect LBX definition data'
  6024                 else: 
  6025                     reason = 'Missing/incorrect metadata'
  6026             else:
  6027                 reason = 'Unknown LBX version'
  6028         else:
  6029             reason = 'Not a parsed dict'
  6030     else:
  6031         reason = 'Not a stored dict'
  6032             
  6033             
  6034     print("ERROR: string to material/texture conversion failed: %s" % reason)
  6035     return None
  6036 
  6037 
  6038 luxclipboard = None # global variable for copy/paste content
  6039 def showMatTexMenu(mat, basekey='', tex=False):
  6040     global luxclipboard, ConnectLrmdb
  6041     if tex: menu="Texture menu:%t"
  6042     else: menu="Material menu:%t"
  6043     menu += "|Copy%x1"
  6044     try:
  6045         if luxclipboard and (not(tex) ^ (luxclipboard["__type__"]=="texture")): menu +="|Paste%x2"
  6046     except: pass
  6047     if (tex):
  6048         menu += "|Load LBT%x3|Save LBT%x4"
  6049     else:
  6050         menu += "|Load LBM%x3|Save LBM%x4"
  6051     if  ConnectLrmdb:
  6052         menu += "|Download from DB%x5" #not(tex) and
  6053         menu += "|Upload to DB%x6"
  6054 
  6055 #    menu += "|%l|dump material%x99|dump clipboard%x98"
  6056     r = Draw.PupMenu(menu)
  6057     if r==1:
  6058         luxclipboard = getMatTex(mat, basekey, tex)
  6059     elif r==2: putMatTex(mat, luxclipboard, basekey, tex)
  6060     elif r==3: 
  6061         scn = Scene.GetCurrent()
  6062         if (tex):
  6063             Window.FileSelector(lambda fn:loadMatTex(mat, fn, basekey, tex), "load texture", luxProp(scn, "lux", "").get()+os.sep+".lbt")
  6064         else:
  6065             Window.FileSelector(lambda fn:loadMatTex(mat, fn, basekey, tex), "load material", luxProp(scn, "lux", "").get()+os.sep+".lbm")
  6066     elif r==4:
  6067         scn = Scene.GetCurrent()
  6068         if (tex):
  6069             Window.FileSelector(lambda fn:saveMatTex(mat, fn, basekey, tex), "save texture", luxProp(scn, "lux", "").get()+os.sep+".lbt")
  6070         else:
  6071             Window.FileSelector(lambda fn:saveMatTex(mat, fn, basekey, tex), "save material", luxProp(scn, "lux", "").get()+os.sep+".lbm")
  6072     elif r==5:
  6073         if not tex:
  6074             id = Draw.PupStrInput("Material ID:", "", 32)
  6075         else:
  6076             id = Draw.PupStrInput("Texture ID:", "", 32)
  6077         if id: putMatTex(mat, downloadLRMDB(mat, id), basekey, tex)
  6078     elif r==6:
  6079         global lrmdb_connector
  6080         if not lrmdb_connector.submit_object(mat, basekey, tex):
  6081             msg = lrmdb_connector.last_error()
  6082         else:
  6083             msg = 'OK'
  6084             
  6085         Draw.PupMenu("Upload: "+msg+".%t|OK")
  6086 #    elif r==99:
  6087 #        for k,v in mat.properties['luxblend'].convert_to_pyobject().items(): print(k+"="+repr(v))
  6088 #    elif r==98:
  6089 #        for k,v in luxclipboard.items(): print(k+"="+repr(v))
  6090 #    prin()
  6091     Draw.Redraw()
  6092 
  6093 
  6094 def saveMatTex(mat, fn, basekey='', tex=False):
  6095     global LuxIsGUI
  6096     d = getMatTex(mat, basekey, tex)
  6097     file = open(fn, 'w')
  6098     file.write(MatTex2str(d, tex))
  6099     file.close()
  6100     if LuxIsGUI: Draw.Redraw()
  6101 
  6102 
  6103 def loadMatTex(mat, fn, basekey='', tex=None):
  6104     global LuxIsGUI
  6105     file = open(fn, 'r')
  6106     data = file.read()
  6107     file.close()
  6108     data = str2MatTex(data, tex)
  6109     putMatTex(mat, data, basekey, tex) 
  6110     if LuxIsGUI: Draw.Redraw()
  6111 
  6112 
  6113 activemat = None
  6114 def setactivemat(mat):
  6115     global activemat
  6116     activemat = mat
  6117 
  6118 
  6119 # scrollbar
  6120 class scrollbar:
  6121     def __init__(self):
  6122         self.position = 0 # current position at top (inside 0..height-viewHeight)
  6123         self.height = 0 # total height of the content
  6124         self.viewHeight = 0 # height of window
  6125         self.x = 0 # horizontal position of the scrollbar
  6126         self.scrolling = self.over = False # start without scrolling ;)
  6127     def calcRects(self):
  6128         # Blender doesn't give us direct access to the window size yet, but it does set the
  6129         # GL scissor box for it, so we can get the size from that. (thx to Daniel Dunbar)
  6130         size = BGL.Buffer(BGL.GL_FLOAT, 4)
  6131         BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, size)
  6132         size = size.list # [winx, winy, width, height]
  6133         self.winrect = size[:]
  6134         self.viewHeight = size[3]
  6135         size[0], size[1] = size[2]-20, 0 # [scrollx1, scrolly1, scrollx2, scrolly2]
  6136         self.rect = size[:]
  6137         if self.position < 0: self.position = 0
  6138         if self.height < self.viewHeight: self.height = self.viewHeight
  6139         if self.position > self.height-self.viewHeight: self.position = self.height-self.viewHeight
  6140         self.factor = (size[3]-size[1]-4)/self.height
  6141         self.sliderRect = [size[0]+2, size[3]-2-(self.position+self.viewHeight)*self.factor, size[2]-2, size[3]-2-self.position*self.factor]
  6142     def draw(self):
  6143         self.calcRects()
  6144         BGL.glColor3f(0.5,0.5,0.5); BGL.glRectf(self.rect[0],self.rect[1],self.rect[2],self.rect[3])
  6145         if self.over or self.scrolling: BGL.glColor3f(1.0,1.0,0.7)
  6146         else: BGL.glColor3f(0.7,0.7,0.7)
  6147         BGL.glRectf(self.sliderRect[0],self.sliderRect[1],self.sliderRect[2],self.sliderRect[3])
  6148     def getTop(self):
  6149         return self.viewHeight+self.position
  6150     def scroll(self, delta):
  6151         self.position = self.position + delta
  6152         self.calcRects()
  6153         Draw.Redraw()
  6154     def Mouse(self):
  6155         self.calcRects()
  6156         coord, buttons = Window.GetMouseCoords(), Window.GetMouseButtons()
  6157         over = (coord[0]>=self.winrect[0]+self.rect[0]) and (coord[0]<=self.winrect[0]+self.rect[2]) and \
  6158                (coord[1]>=self.winrect[1]+self.rect[1]) and (coord[1]<=self.winrect[1]+self.rect[3])
  6159         if Window.MButs.L and buttons > 0:
  6160             if self.scrolling:
  6161                 if self.factor > 0: self.scroll((self.lastcoord[1]-coord[1])/self.factor)
  6162                 Draw.Redraw()
  6163             elif self.over:
  6164                 self.scrolling = True
  6165             self.lastcoord = coord
  6166         elif self.scrolling:
  6167             self.scrolling = False
  6168             Draw.Redraw()
  6169         if self.over != over: Draw.Redraw()
  6170         self.over = over
  6171 
  6172 scrollbar = scrollbar()
  6173 
  6174 
  6175 # gui main draw
  6176 def luxDraw():
  6177     global icon_luxblend
  6178 
  6179     BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
  6180 
  6181     y = int(scrollbar.getTop()) # 420
  6182     BGL.glColor3f(0.1,0.1,0.1); BGL.glRectf(0,0,440,y)
  6183     BGL.glColor3f(1.0,0.5,0.0); BGL.glRasterPos2i(130,y-21); Draw.Text("v0.6")
  6184     BGL.glColor3f(0.9,0.9,0.9)
  6185 
  6186     drawLogo(icon_luxblend, 6, y-25)
  6187 
  6188     scn = Scene.GetCurrent()
  6189     if scn:
  6190         luxpage = luxProp(scn, "page", 0)
  6191         gui = luxGui(y-70)
  6192 
  6193         # render presets
  6194         BGL.glRasterPos2i(10,y-45); Draw.Text("Render presets:")
  6195         luxpreset = luxProp(scn, "preset", "1C - Final - medium MLT/Path Tracing (indoor) (recommended)")
  6196         presets = getScenePresets()
  6197         presetskeys = presets.keys()
  6198         presetskeys.sort()
  6199         presetskeys.insert(0, "")
  6200         presetsstr = "presets: %t"
  6201         for i, v in enumerate(presetskeys): presetsstr = "%s %%x%d|%s"%(v, i, presetsstr)
  6202         try: i = presetskeys.index(luxpreset.get())
  6203         except ValueError: i = 0
  6204         Draw.Menu(presetsstr, evtLuxGui, 110, y-50, 220, 18, i, "", lambda e,v: luxpreset.set(presetskeys[v]))
  6205         Draw.Button("save", evtSavePreset, 330, y-50, 40, 18, "create a render-settings preset")
  6206         Draw.Button("del", evtDeletePreset, 370, y-50, 40, 18, "delete a render-settings preset")
  6207 
  6208         # if preset is selected load values
  6209         if luxpreset.get() != "":
  6210             try:
  6211                 d = presets[luxpreset.get()]
  6212                 for k,v in d.items(): scn.properties['luxblend'][k] = v
  6213             except: pass
  6214 
  6215         Draw.Button("Material", evtLuxGui, 10, y-70, 80, 16, "", lambda e,v:luxpage.set(0))
  6216         Draw.Button("Cam/Env", evtLuxGui, 90, y-70, 80, 16, "", lambda e,v:luxpage.set(1))
  6217         Draw.Button("Render", evtLuxGui, 170, y-70, 80, 16, "", lambda e,v:luxpage.set(2))
  6218         Draw.Button("Output", evtLuxGui, 250, y-70, 80, 16, "", lambda e,v:luxpage.set(3))
  6219         Draw.Button("System", evtLuxGui, 330, y-70, 80, 16, "", lambda e,v:luxpage.set(4))
  6220         if luxpage.get() == 0:
  6221             BGL.glColor3f(1.0,0.5,0.0);BGL.glRectf(10,y-74,90,y-70);BGL.glColor3f(0.9,0.9,0.9)
  6222             obj = scn.objects.active
  6223             if obj:
  6224                 if (obj.getType() == "Lamp"):
  6225                     ltype = obj.getData(mesh=1).getType() # data
  6226                     if (ltype == Lamp.Types["Area"]): luxLight("Area LIGHT", "", obj, gui, 0)
  6227                     elif (ltype == Lamp.Types["Spot"]): luxSpot("Spot LIGHT", "", obj, gui, 0)
  6228                     elif (ltype == Lamp.Types["Lamp"]): luxLamp("Point LIGHT", "", obj, gui, 0)
  6229                 else:
  6230                     matfilter = luxProp(scn, "matlistfilter", "false")
  6231                     mats = getMaterials(obj, True)
  6232                     if (activemat == None) and (len(mats) > 0):
  6233                         setactivemat(mats[0])
  6234                     if matfilter.get() == "false":
  6235                         mats = Material.Get()
  6236                     matindex = 0
  6237                     for i, v in enumerate(mats):
  6238                         if v==activemat: matindex = i
  6239                     matnames = [m.getName() for m in mats]
  6240                     menustr = "Material: %t"
  6241                     for i, v in enumerate(matnames): menustr = "%s %%x%d|%s"%(v, i, menustr)
  6242                     gui.newline("MATERIAL:", 8) 
  6243                     r = gui.getRect(1.1, 1)
  6244                     Draw.Button("C", evtConvertMaterial, r[0]-gui.h, gui.y-gui.h, gui.h, gui.h, "convert blender material to lux material")
  6245                     Draw.Menu(menustr, evtLuxGui, r[0], r[1], r[2], r[3], matindex, "", lambda e,v: setactivemat(mats[v]))
  6246                     luxBool("", matfilter, "filter", "only show active object materials", gui, 0.5)
  6247 
  6248                     Draw.Button("L", evtLoadMaterial, gui.x, gui.y-gui.h, gui.h, gui.h, "load a material preset")
  6249                     Draw.Button("S", evtSaveMaterial, gui.x+gui.h, gui.y-gui.h, gui.h, gui.h, "save a material preset")
  6250                     Draw.Button("D", evtDeleteMaterial, gui.x+gui.h*2, gui.y-gui.h, gui.h, gui.h, "delete a material preset")
  6251                     if len(mats) > 0:
  6252                         setactivemat(mats[matindex])
  6253                         luxMaterial(activemat, gui)
  6254         if luxpage.get() == 1:
  6255             BGL.glColor3f(1.0,0.5,0.0);BGL.glRectf(90,y-74,170,y-70);BGL.glColor3f(0.9,0.9,0.9)
  6256             cam = scn.getCurrentCamera()
  6257             if cam:
  6258                 r = gui.getRect(1.1, 1)
  6259                 luxCamera(cam.data, scn.getRenderingContext(), gui)
  6260             gui.newline("", 10)
  6261             luxEnvironment(scn, gui)
  6262         if luxpage.get() == 2:
  6263             BGL.glColor3f(1.0,0.5,0.0);BGL.glRectf(170,y-74,250,y-70);BGL.glColor3f(0.9,0.9,0.9)
  6264             r = gui.getRect(1.1, 1)
  6265             luxSampler(scn, gui)
  6266             gui.newline("", 10)
  6267             luxSurfaceIntegrator(scn, gui)
  6268             gui.newline("", 10)
  6269             luxVolumeIntegrator(scn, gui)
  6270             gui.newline("", 10)
  6271             luxPixelFilter(scn, gui)
  6272         if luxpage.get() == 3:
  6273             BGL.glColor3f(1.0,0.5,0.0);BGL.glRectf(250,y-74,330,y-70);BGL.glColor3f(0.9,0.9,0.9)
  6274             r = gui.getRect(1.1, 1)
  6275             luxFilm(scn, gui)
  6276         if luxpage.get() == 4:
  6277             BGL.glColor3f(1.0,0.5,0.0);BGL.glRectf(330,y-74,410,y-70);BGL.glColor3f(0.9,0.9,0.9)
  6278             luxSystem(scn, gui)
  6279             gui.newline("", 10)
  6280             luxAccelerator(scn, gui)
  6281             gui.newline("MATERIALS:", 10)
  6282             r = gui.getRect(2,1)
  6283             Draw.Button("convert all blender materials", 0, r[0], r[1], r[2], r[3], "convert all blender-materials to lux-materials", lambda e,v:convertAllMaterials())
  6284             gui.newline("SETTINGS:", 10)
  6285             r = gui.getRect(2,1)
  6286             Draw.Button("save defaults", 0, r[0], r[1], r[2], r[3], "save current settings as defaults", lambda e,v:saveluxdefaults())
  6287         y = gui.y - 80
  6288         if y > 0: y = 0 # bottom align of render button
  6289         run = luxProp(scn, "run", "true")
  6290         dlt = luxProp(scn, "default", "true")
  6291         pipe = luxProp(scn, "pipe", "false")
  6292         clay = luxProp(scn, "clay", "false")
  6293         nolg = luxProp(scn, "nolg", "false")
  6294         lxs = luxProp(scn, "lxs", "true")
  6295         lxo = luxProp(scn, "lxo", "true")
  6296         lxm = luxProp(scn, "lxm", "true")
  6297         lxv = luxProp(scn, "lxv", "true")
  6298         net = luxProp(scn, "netrenderctl", "false")
  6299         donet = luxProp(scn, "donetrender", "true")
  6300         
  6301         global render_status_text
  6302         global render_status
  6303         
  6304         if render_status == True:
  6305             BGL.glRasterPos2i(10,y+20)
  6306             Draw.Text(render_status_text)
  6307         else:
  6308             BGL.glRasterPos2i(10,y+5)
  6309             Draw.Text(render_status_text, "tiny")
  6310             
  6311             def check_pipe_def_exclusion(m, v):
  6312             	if m == 'd':
  6313             		dlt.set(["false","true"][bool(v)])
  6314             		
  6315             		if dlt.get() == 'true':
  6316             			pipe.set('false')
  6317             	elif m == 'p':
  6318             		pipe.set(["false","true"][bool(v)])
  6319             		
  6320             		if pipe.get() == 'true':
  6321             			dlt.set('false')
  6322             
  6323             if (run.get()=="true"):
  6324                 Draw.Button("Render", 0, 10, y+20, 100, 36, "Render with Lux", lambda e,v:CBluxExport(dlt.get()=="true" or pipe.get()=="true", True))
  6325                 Draw.Button("Render Anim", 0, 110, y+20, 100, 36, "Render animation with Lux", lambda e,v:CBluxAnimExport(dlt.get()=="true" or pipe.get()=="true", True))
  6326             else:
  6327                 Draw.Button("Export", 0, 10, y+20, 100, 36, "Export", lambda e,v:CBluxExport(dlt.get()=="true" or pipe.get()=="true", False))
  6328                 Draw.Button("Export Anim", 0, 110, y+20, 100, 36, "Export animation", lambda e,v:CBluxAnimExport(dlt.get()=="true" or pipe.get()=="true", False))
  6329             
  6330             Draw.Toggle("run", evtLuxGui, 265, y+40, 30, 16, run.get()=="true", "start Lux after export", lambda e,v: run.set(["false","true"][bool(v)]))
  6331             
  6332             if (pipe.get() == 'false' and dlt.get() == 'true') or run.get()=='false':
  6333                 Draw.Toggle("def", evtLuxGui, 295, y+40, 55, 16, dlt.get()=="true", "write to default lxs file", lambda e,v: check_pipe_def_exclusion('d',v))
  6334             elif pipe.get() == 'true' and dlt.get() == 'false':
  6335                 Draw.Toggle("pipe", evtLuxGui, 295, y+40, 55, 16, pipe.get()=="true", "do not write any lxs file", lambda e,v: check_pipe_def_exclusion('p',v))
  6336             else:
  6337                 Draw.Toggle("def", evtLuxGui, 295, y+40, 25, 16, dlt.get()=="true", "write to default lxs file", lambda e,v: check_pipe_def_exclusion('d',v))
  6338                 Draw.Toggle("pipe", evtLuxGui, 320, y+40, 30, 16, pipe.get()=="true", "do not write any lxs file", lambda e,v: check_pipe_def_exclusion('p',v))
  6339             
  6340             Draw.Toggle("clay", evtLuxGui, 350, y+40, 30, 16, clay.get()=="true", "all materials are rendered as white-matte", lambda e,v: clay.set(["false","true"][bool(v)]))
  6341             Draw.Toggle("noLG", evtLuxGui, 380, y+40, 35, 16, nolg.get()=="true", "disables all light groups", lambda e,v: nolg.set(["false","true"][bool(v)]))
  6342             
  6343             if pipe.get() == "false":
  6344                 Draw.Toggle(".lxs", 0, 265, y+20, 37, 16, lxs.get()=="true", "export .lxs scene file", lambda e,v: lxs.set(["false","true"][bool(v)]))
  6345                 Draw.Toggle(".lxo", 0, 302, y+20, 38, 16, lxo.get()=="true", "export .lxo geometry file", lambda e,v: lxo.set(["false","true"][bool(v)]))
  6346                 Draw.Toggle(".lxm", 0, 340, y+20, 37, 16, lxm.get()=="true", "export .lxm material file", lambda e,v: lxm.set(["false","true"][bool(v)]))
  6347                 Draw.Toggle(".lxv", 0, 377, y+20, 38, 16, lxv.get()=="true", "export .lxv volume file", lambda e,v: lxv.set(["false","true"][bool(v)]))
  6348     
  6349     BGL.glColor3f(0.9, 0.9, 0.9)
  6350     
  6351     BGL.glRasterPos2i(330,y+5) ; Draw.Text("Press Q or ESC to quit.", "tiny")
  6352     scrollbar.height = scrollbar.getTop() - y
  6353     scrollbar.draw()
  6354 
  6355 render_status_text = ''
  6356 render_status = False
  6357 
  6358 mouse_xr=1 
  6359 mouse_yr=1 
  6360 
  6361 activeObject = None
  6362 activeEvent = None
  6363 lastEventTime = 0
  6364 key_tabs = {
  6365     Draw.ONEKEY:     0,
  6366     Draw.TWOKEY:     1,
  6367     Draw.THREEKEY:   2,
  6368     Draw.FOURKEY:    3,
  6369     Draw.FIVEKEY:    4,
  6370 }
  6371 def luxEvent(evt, val):  # function that handles keyboard and mouse events
  6372     global activeObject, activemat, activeEvent, lastEventTime, key_tabs
  6373     if evt == Draw.ESCKEY or evt == Draw.QKEY:
  6374         stop = Draw.PupMenu("OK?%t|Cancel export %x1")
  6375         if stop == 1:
  6376             Draw.Exit()
  6377             return
  6378     scn = Scene.GetCurrent()
  6379     if scn:
  6380         if scn.objects.active != activeObject:
  6381             activeObject = scn.objects.active
  6382             activemat = None
  6383             Window.QRedrawAll()
  6384     if (evt == Draw.MOUSEX) or (evt == Draw.MOUSEY): scrollbar.Mouse()
  6385     if evt == Draw.WHEELUPMOUSE: scrollbar.scroll(-16)
  6386     if evt == Draw.WHEELDOWNMOUSE: scrollbar.scroll(16)
  6387     if evt == Draw.PAGEUPKEY: scrollbar.scroll(-50)
  6388     if evt == Draw.PAGEDOWNKEY: scrollbar.scroll(50)
  6389 
  6390     # scroll to [T]op and [B]ottom
  6391     if evt == Draw.TKEY:
  6392         scrollbar.scroll(-scrollbar.position)
  6393     if evt == Draw.BKEY:
  6394         scrollbar.scroll(100000)   # Some large number should be enough ?!
  6395 
  6396     # R key shortcut to launch render
  6397     # E key shortcut to export current scene (not render)
  6398     # P key shortcut to preview current material
  6399     # These keys need time and process-complete locks
  6400     if evt in [Draw.RKEY, Draw.EKEY, Draw.PKEY]:
  6401         if activeEvent == None and (sys.time() - lastEventTime) > 5:
  6402             lastEventTime = sys.time()
  6403             if evt == Draw.RKEY:
  6404                 activeEvent = 'RKEY'
  6405                 CBluxExport(luxProp(scn, "default", "true").get() == "true" or luxProp(scn, "pipe", "false").get() == "true", True)
  6406                 activeEvent = None
  6407             if evt == Draw.EKEY:
  6408                 activeEvent = 'EKEY'
  6409                 CBluxExport(luxProp(scn, "default", "true").get() == "true" or luxProp(scn, "pipe", "false").get() == "true", False)
  6410                 activeEvent = None
  6411             if evt == Draw.PKEY:
  6412                 activeEvent = 'PKEY'
  6413                 if activemat != None:
  6414                     Preview_Update(activemat, '', True, 0, None, None, None)
  6415                 activeEvent = None
  6416         
  6417     # Switch GUI tabs with number keys
  6418     if evt in key_tabs.keys():
  6419         luxProp(scn, "page", 0).set(key_tabs[evt])        
  6420         luxDraw()
  6421         Window.QRedrawAll()
  6422           
  6423 
  6424     # Handle icon button events - note - radiance - this is a work in progress! :)
  6425 #    if evt == Draw.LEFTMOUSE and not val: 
  6426 #           size=BGL.Buffer(BGL.GL_FLOAT, 4) 
  6427 #           BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, size) 
  6428 #            size= [int(s) for s in size] 
  6429 #        mx, my = Window.GetMouseCoords()
  6430 #        mousex = mx - size[0]
  6431 #        print("mousex = %i"%mousex)
  6432 #        #if((mousex > 2) and (mousex < 25)):
  6433 #            # Mouse clicked in left button bar
  6434 #        if((mousex > 399) and (mousex < 418)):
  6435 #            # Mouse clicked in right button bar
  6436 #            mousey = my - size[1] - scrollbar.position
  6437 #            print("mousey = %i"%mousey)
  6438             
  6439     
  6440 def luxButtonEvt(evt):  # function that handles button events
  6441     global usedproperties, usedpropertiesfilterobj
  6442     if evt == evtLuxGui:
  6443         Draw.Redraw()
  6444     if evt == evtSavePreset:
  6445         scn = Scene.GetCurrent()
  6446         if scn:
  6447             name = Draw.PupStrInput("preset name: ", "")
  6448             if name != "":
  6449                 usedproperties = {}
  6450                 usedpropertiesfilterobj = None
  6451                 luxSurfaceIntegrator(scn)
  6452                 luxSampler(scn)
  6453                 luxPixelFilter(scn)
  6454                 # luxFilm(scn)
  6455                 luxAccelerator(scn)
  6456                 # luxEnvironment(scn)
  6457                 saveScenePreset(name, usedproperties.copy())
  6458                 luxProp(scn, "preset", "").set(name)
  6459                 Draw.Redraw()
  6460     if evt == evtDeletePreset:
  6461         presets = getScenePresets().keys()
  6462         presets.sort()
  6463         presetsstr = "delete preset: %t"
  6464         for i, v in enumerate(presets): presetsstr += "|%s %%x%d"%(v, i)
  6465         r = Draw.PupMenu(presetsstr, 20)
  6466         if r >= 0:
  6467             saveScenePreset(presets[r], None)
  6468             Draw.Redraw()
  6469 
  6470     if evt == evtLoadMaterial:
  6471         if activemat:
  6472             mats = getMaterialPresets()
  6473             matskeys = mats.keys()
  6474             matskeys.sort()
  6475             matsstr = "load preset: %t"
  6476             for i, v in enumerate(matskeys): matsstr += "|%s %%x%d"%(v, i)
  6477             r = Draw.PupMenu(matsstr, 20)
  6478             if r >= 0:
  6479                 name = matskeys[r]
  6480                 try:
  6481 #                    for k,v in mats[name].items(): activemat.properties['luxblend'][k] = v
  6482                     for k,v in mats[name].items(): luxProp(activemat, k, None).set(v)
  6483                 except: pass
  6484                 Draw.Redraw()
  6485     if evt == evtSaveMaterial:
  6486         if activemat:
  6487             name = Draw.PupStrInput("preset name: ", "")
  6488             if name != "":
  6489                 usedproperties = {}
  6490                 usedpropertiesfilterobj = activemat
  6491                 luxMaterial(activemat)
  6492                 saveMaterialPreset(name, usedproperties.copy())
  6493                 Draw.Redraw()
  6494     if evt == evtDeleteMaterial:
  6495         matskeys = getMaterialPresets().keys()
  6496         matskeys.sort()
  6497         matsstr = "delete preset: %t"
  6498         for i, v in enumerate(matskeys): matsstr += "|%s %%x%d"%(v, i)
  6499         r = Draw.PupMenu(matsstr, 20)
  6500         if r >= 0:
  6501             saveMaterialPreset(matskeys[r], None)
  6502             Draw.Redraw()
  6503     if evt == evtConvertMaterial:
  6504         if activemat: convertMaterial(activemat)
  6505         Draw.Redraw()
  6506     if evt == evtLoadMaterial2:
  6507         if activemat:
  6508             scn = Scene.GetCurrent()
  6509             Window.FileSelector(lambda fn:loadMatTex(activemat, fn), "load material", luxProp(scn, "lux", "").get()+os.sep+".lbm")
  6510     if evt == evtSaveMaterial2:
  6511         if activemat:
  6512             scn = Scene.GetCurrent()
  6513             Window.FileSelector(lambda fn:saveMaterial(activemat, fn), "save material", luxProp(scn, "lux", "").get()+os.sep+".lbm")
  6514     
  6515 
  6516 def setFocus(target):
  6517     currentscene = Scene.GetCurrent()
  6518     camObj = currentscene.objects.camera # currentscene.getCurrentCamera()
  6519     if target == "S":
  6520         try:
  6521             refLoc = (Object.GetSelected()[0]).getLocation()
  6522         except:
  6523             print("select an object to focus\n")
  6524     elif target == "C":
  6525         refLoc = Window.GetCursorPos()
  6526     else:
  6527         refLoc = (Object.Get(target)).getLocation()
  6528     dist = Mathutils.Vector(refLoc) - Mathutils.Vector(camObj.getLocation())
  6529     camDir = camObj.getMatrix()[2]*(-1.0)
  6530     camObj.getData(mesh=1).dofDist = (camDir[0]*dist[0]+camDir[1]*dist[1]+camDir[2]*dist[2])/camDir.length # data
  6531 
  6532 
  6533 # Parse command line arguments for batch mode rendering if supplied
  6534 
  6535 try:
  6536     batchindex = osys.argv.index('--batch')
  6537     pyargs = osys.argv[osys.argv.index('--batch')+1:]
  6538 except: pyargs = []
  6539 
  6540 if (pyargs != []) and (batchindex != 0):
  6541     print("\n\nLuxBlend v0.6 - BATCH mode\n")
  6542     LuxIsGUI = False
  6543 
  6544     scene = Scene.GetCurrent()
  6545     context = scene.getRenderingContext()
  6546 
  6547     luxpath = ""
  6548     import getopt
  6549     o, a = getopt.getopt(pyargs, 's:e:o:t:l:',["scale=","haltspp=","run=", "lbm=", "lbt="])
  6550 
  6551     opts = {}
  6552     for k,v in o:
  6553         opts[k] = v
  6554 
  6555     if (opts.has_key('--run')) and (opts['--run'] == 'false'):
  6556         print("Run: false")
  6557         luxProp(scene, "run", "true").set("false")
  6558     else:
  6559         luxProp(scene, "run", "true").set("true")
  6560 
  6561     if opts.has_key('--scale'):
  6562         print("Zoom: %s" %opts['--scale'])
  6563         luxProp(scene, "film.scale", "100 %").set(opts['--scale'])
  6564 
  6565     if opts.has_key('--haltspp'):
  6566         print("haltspp: %s" %opts['--haltspp'])
  6567         luxProp(scene, "haltspp", 0).set(int(opts['--haltspp']))
  6568 
  6569     if opts.has_key('-s'):
  6570         print("Start frame: %s" %opts['-s'])
  6571         context.startFrame(int(opts['-s']))
  6572     else:
  6573         print("Error: Start frame not supplied (-s)"); osys.exit(1)
  6574     if opts.has_key('-e'):
  6575         print("End frame: %s" %opts['-e'])
  6576         context.endFrame(int(opts['-e']))
  6577     else:
  6578         print("Error: End frame not supplied (-e)"); osys.exit(1)
  6579     if opts.has_key('-l'):
  6580         print("Path to lux binary: %s" %opts['-l'])
  6581         luxbatchconsolemode = luxProp(scene, "luxbatchc", "false")
  6582         luxbatchconsolemode.set("true")
  6583         luxpathprop = luxProp(scene, "lux", "")
  6584         luxpathprop.set(opts['-l'])
  6585     else:
  6586         print("Error: path to lux binary not supplied (-l)"); osys.exit(1)
  6587     if opts.has_key('-o'):
  6588         print("Image output path: %s" %opts['-o'])
  6589         luxProp(scene, "overrideoutputpath", "").set(opts['-o'])
  6590     else:
  6591         print("Error: image output path not supplied (-o)"); osys.exit(1)
  6592     if opts.has_key('-t'):
  6593         print("Temporary export path: %s" %opts['-t'])
  6594         luxProp(scene, "datadir", "").set(opts['-t'])
  6595     else:
  6596         print("Error: Temporary export path not supplied (-t)"); osys.exit(1)
  6597     
  6598     if opts.has_key('--lbm'):
  6599         print("Load material: %s" %opts['--lbm'])
  6600         mat = Material.Get("Material")
  6601         if mat: loadMatTex(mat, opts['--lbm'])
  6602         else:
  6603             print("Error: No material with name \"Material\" found (--lbm)"); osys.exit(1)
  6604             
  6605     if opts.has_key('--lbt'):
  6606         print("Load material: %s" %opts['--lbt'])
  6607         mat = Material.Get("Material")
  6608         if mat: loadMatTex(mat, opts['--lbt'], ':Kd')
  6609         else:
  6610             print("Error: No material with name \"Material\" found (--lbt)"); osys.exit(1)
  6611 
  6612 #    CBluxAnimExport(True, True)
  6613     CBluxAnimExport(True, True, False) # as by zukazuka (http://www.luxrender.net/forum/viewtopic.php?f=11&t=1288)
  6614     osys.exit(0)
  6615 
  6616 else:
  6617     print("\n\nLuxBlend v0.6 - UI mode\n")
  6618     from Blender.Window import DrawProgressBar
  6619     LuxIsGUI = True
  6620     
  6621     Draw.Register(luxDraw, luxEvent, luxButtonEvt) # init GUI
  6622 
  6623     luxpathprop = luxProp(Scene.GetCurrent(), "lux", "")
  6624     luxpath = luxpathprop.get()
  6625     luxrun = luxProp(Scene.GetCurrent(), "run", True).get()
  6626     checkluxpath = luxProp(Scene.GetCurrent(), "checkluxpath", True).get()
  6627 
  6628     if checkluxpath and luxrun:
  6629         if (luxpath is None) or (sys.exists(luxpath)<=0):
  6630             # luxpath not valid, so delete entry from .blend scene file
  6631             luxpathprop.delete()
  6632             # and re-get luxpath, so we get the path from default-settings
  6633             luxpath = luxpathprop.get()
  6634             #
  6635             LUXRENDER_ROOT = os.getenv('LUXRENDER_ROOT')
  6636             if LUXRENDER_ROOT is not None:
  6637                 LUXRENDER_ROOT = LUXRENDER_ROOT + os.sep
  6638                 luxpathprop.set(LUXRENDER_ROOT)
  6639                 luxpath = LUXRENDER_ROOT
  6640                 if sys.exists(luxpath)>0:
  6641                     print('LuxRender path set from LUXRENDER_ROOT environment variable')
  6642                     saveluxdefaults()
  6643             
  6644             if (luxpath is None) or (sys.exists(luxpath)<=0):
  6645                 print("WARNING: LuxPath \"%s\" is not valid\n"%(luxpath))
  6646                 scn = Scene.GetCurrent()
  6647                 if scn:
  6648                     r = Draw.PupMenu("Installation: Set path to the lux render software?%t|Yes%x1|No%x0|Never%x2")
  6649                     if r == 1:
  6650                         Window.FileSelector(lambda s:luxProp(scn, "lux", "").set(Blender.sys.dirname(s)+os.sep), "Select file in Lux path")
  6651                         saveluxdefaults()
  6652                     if r == 2:
  6653                         newluxdefaults["checkluxpath"] = False
  6654                         saveluxdefaults()
  6655     else    :
  6656         print("Lux path check disabled\n")