LuxBlend_0.1.py
author David Bucciarelli <dade@ngi.it>
Wed Dec 16 15:08:36 2009 +0100 (2009-12-16)
branchv06x
changeset 447 4b8109987265
parent 445 2ce148c6a8b6
child 448 97106ada6b4e
permissions -rw-r--r--
Backported the fix for max. value of network_interval
     1 #!BPY
     2 # -*- coding: utf-8 -*-
     3 # coding=utf-8
     4 """Registration info for Blender menus:
     5 Name: 'LuxBlend v0.6.1 Exporter'
     6 Blender: 248
     7 Group: 'Render'
     8 Tooltip: 'Export/Render to LuxRender v0.6.1 scene format (.lxs)'
     9 """
    10 
    11 __author__ = "radiance, zuegs, ideasman42, luxblender, dougal2"
    12 __version__ = "0.6.1"
    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.1 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         print("    exporting mesh")
   351         if mats == []:
   352             mats = [dummyMat]
   353         usedmats = [f.mat for f in mesh.faces]
   354         for matIndex in range(len(mats)):
   355             if not matIndex in usedmats:
   356                 continue
   357             if not(portal):
   358                 mat = mats[matIndex]
   359                 if not mat:
   360                    mat = dummyMat
   361                 self.exportMaterialLink(file, mat)
   362             mesh_str = self.getMeshType(len(mesh.verts), mats[matIndex])
   363             if not(portal):
   364                 file.write("\tShape %s \"integer indices\" [\n"% mesh_str)
   365             else:
   366                 self.exportMaterialLink(file, mats[matIndex])
   367                 file.write("\tPortalShape %s \"integer indices\" [\n"% mesh_str)
   368             index = 0
   369             ffaces = [f for f in mesh.faces if f.mat == matIndex]
   370             for face in ffaces:
   371                 file.write("%d %d %d\n"%(index, index+1, index+2))
   372                 if (len(face)==4):
   373                     file.write("%d %d %d\n"%(index, index+2, index+3))
   374                 index += len(face.verts)
   375             file.write("\t] \"point P\" [\n")
   376             for face in ffaces:
   377                 for vertex in face:
   378                     file.write("%f %f %f\n"% tuple(vertex.co))
   379             file.write("\t] \"normal N\" [\n")
   380             for face in ffaces:
   381                 normal = face.no
   382                 for vertex in face:
   383                     if (face.smooth):
   384                         normal = vertex.no
   385                     file.write("%f %f %f\n"% tuple(normal))
   386             if (mesh.faceUV):
   387                 file.write("\t] \"float uv\" [\n")
   388                 for face in ffaces:
   389                     for uv in face.uv:
   390                         file.write("%f %f\n"% tuple(uv))
   391             file.write("\t]\n")
   392 
   393     #-------------------------------------------------
   394     # exportMeshOpt(self, file, mesh, mats, name, portal, optNormals)
   395     # exports mesh to the file with optimization.
   396     # portal: export without normals and UVs
   397     # optNormals: speed and filesize optimization, flat faces get exported without normals
   398     #-------------------------------------------------
   399     def exportMeshOpt(self, file, mesh, mats, name, portal=False, optNormals=True):
   400         print("    exporting optimized mesh")
   401         shapeList, smoothFltr, shapeText = [0], [[0,1]], [""]
   402         if portal:
   403             normalFltr, uvFltr, shapeText = [0], [0], ["portal"] # portal, no normals, no UVs
   404         else:
   405             uvFltr, normalFltr, shapeText = [1], [1], ["mixed with normals"] # normals and UVs
   406             if optNormals: # one pass for flat faces without normals and another pass for smoothed faces with normals, all with UVs
   407                 shapeList, smoothFltr, normalFltr, uvFltr, shapeText = [0,1], [[0],[1]], [0,1], [1,1], ["flat w/o normals", "smoothed with normals"]
   408         if mats == []:
   409             mats = [dummyMat]
   410         usedmats = [f.mat for f in mesh.faces]
   411         for matIndex in range(len(mats)):
   412             if not matIndex in usedmats:
   413                 continue
   414             if not(portal):
   415                 mat = mats[matIndex]
   416                 if not mat:
   417                    mat = dummyMat
   418                 self.exportMaterialLink(file, mat)
   419             for shape in shapeList:
   420                 blenderExportVertexMap = []
   421                 exportVerts = []
   422                 exportFaces = []
   423                 ffaces = [f for f in mesh.faces if (f.mat == matIndex) and (f.smooth in smoothFltr[shape])]
   424                 for face in ffaces:
   425                     exportVIndices = []
   426                     index = 0
   427                     for vertex in face:
   428 #                            v = [vertex.co[0], vertex.co[1], vertex.co[2]]
   429                         v = [vertex.co]
   430                         if normalFltr[shape]:
   431                             if (face.smooth):
   432 #                                    v.extend(vertex.no)
   433                                 v.append(vertex.no)
   434                             else:
   435 #                                    v.extend(face.no)
   436                                 v.append(face.no)
   437                         if (uvFltr[shape]) and (mesh.faceUV):
   438 #                                v.extend(face.uv[index])
   439                             v.append(face.uv[index])
   440                         blenderVIndex = vertex.index
   441                         newExportVIndex = -1
   442                         length = len(v)
   443                         if (blenderVIndex < len(blenderExportVertexMap)):
   444                             for exportVIndex in blenderExportVertexMap[blenderVIndex]:
   445                                 v2 = exportVerts[exportVIndex]
   446                                 if (length==len(v2)) and (v == v2):
   447                                     newExportVIndex = exportVIndex
   448                                     break
   449                         if (newExportVIndex < 0):
   450                             newExportVIndex = len(exportVerts)
   451                             exportVerts.append(v)
   452                             while blenderVIndex >= len(blenderExportVertexMap):
   453                                 blenderExportVertexMap.append([])
   454                             blenderExportVertexMap[blenderVIndex].append(newExportVIndex)
   455                         exportVIndices.append(newExportVIndex)
   456                         index += 1
   457                     exportFaces.append(exportVIndices)
   458                 if (len(exportVerts)>0):
   459                     mesh_str = self.getMeshType(len(exportVerts), mats[matIndex])
   460                     if portal:
   461                         file.write("\tPortalShape %s \"integer indices\" [\n"% mesh_str)
   462                     else:
   463                         file.write("\tShape %s \"integer indices\" [\n"% mesh_str)
   464                     for face in exportFaces:
   465                         file.write("%d %d %d\n"%(face[0], face[1], face[2]))
   466                         if (len(face)==4):
   467                             file.write("%d %d %d\n"%(face[0], face[2], face[3]))
   468                     file.write("\t] \"point P\" [\n")
   469 #                        for vertex in exportVerts:
   470 #                            file.write("%f %f %f\n"%(vertex[0], vertex[1], vertex[2]))
   471                     file.write("".join(["%f %f %f\n"%tuple(vertex[0]) for vertex in exportVerts]))
   472                     if normalFltr[shape]:
   473                         file.write("\t] \"normal N\" [\n")
   474 #                            for vertex in exportVerts:
   475 #                                file.write("%f %f %f\n"%(vertex[3], vertex[4], vertex[5]))
   476                         file.write("".join(["%f %f %f\n"%tuple(vertex[1]) for vertex in exportVerts])) 
   477                         if (uvFltr[shape]) and (mesh.faceUV):
   478                             file.write("\t] \"float uv\" [\n")
   479 #                                for vertex in exportVerts:
   480 #                                    file.write("%f %f\n"%(vertex[6], vertex[7]))
   481                             file.write("".join(["%f %f\n"%tuple(vertex[2]) for vertex in exportVerts])) 
   482                     else:            
   483                         if (uvFltr[shape]) and (mesh.faceUV):
   484                             file.write("\t] \"float uv\" [\n")
   485 #                                for vertex in exportVerts:
   486 #                                    file.write("%f %f\n"%(vertex[3], vertex[4]))
   487                             file.write("".join(["%f %f\n"%tuple(vertex[1]) for vertex in exportVerts])) 
   488                     file.write("\t]\n")
   489                     print("  shape(%s): %d vertices, %d faces"%(shapeText[shape], len(exportVerts), len(exportFaces)))
   490     
   491     #-------------------------------------------------
   492     # exportMeshes(self, file)
   493     # exports meshes that uses instancing (meshes that are used by at least "instancing_threshold" objects)
   494     #-------------------------------------------------
   495     def exportMeshes(self, file):
   496         scn = Scene.GetCurrent()
   497         instancing_threshold = luxProp(scn, "instancing_threshold", 2).get()
   498         mesh_optimizing = luxProp(scn, "mesh_optimizing", "true")
   499         mesh = Mesh.New('')
   500         for (mesh_name, objs) in self.meshes.items():
   501             allow_instancing = True
   502             mats = getMaterials(objs[0]) # mats = obj.getData().getMaterials()
   503             for mat in mats: # don't instance if one of the materials is emissive
   504                 if (mat!=None) and (luxProp(mat, "type", "").get()=="light"):
   505                     allow_instancing = False
   506             for obj in objs: # don't instance if the objects with same mesh uses different materials
   507                 ms = getMaterials(obj)
   508                 if ms != mats:
   509                     allow_instancing = False
   510             if obj.modifiers.__len__() > 0:
   511                 allow_instancing = False
   512             if allow_instancing and (len(objs) > instancing_threshold):
   513                 del self.meshes[mesh_name]
   514                 mesh.getFromObject(objs[0], 0, 1)
   515                 print("blender-mesh: %s (%d vertices, %d faces)"%(mesh_name, len(mesh.verts), len(mesh.faces)))
   516                 file.write("ObjectBegin \"%s\"\n"%mesh_name)
   517 
   518                 if (mesh_optimizing.get() == "true"):
   519                     self.exportMeshOpt(file, mesh, mats, mesh_name)
   520                 else:
   521                     self.exportMesh(file, mesh, mats, mesh_name)
   522                 file.write("ObjectEnd # %s\n\n"%mesh_name)
   523         mesh.verts = None
   524 
   525     #-------------------------------------------------
   526     # exportObjects(self, file)
   527     # exports objects to the file
   528     #-------------------------------------------------
   529     def exportObjects(self, file):
   530         scn = Scene.GetCurrent()
   531         cam = scn.getCurrentCamera().data
   532         objectmblur = luxProp(cam, "objectmblur", "true")
   533         usemblur = luxProp(cam, "usemblur", "false")
   534         mesh_optimizing = luxProp(scn, "mesh_optimizing", "true")
   535         mesh = Mesh.New('')
   536         for [obj, matrix] in self.objects:
   537             print("object: %s"%(obj.getName()))
   538             mesh_name = obj.getData(name_only=True)
   539 
   540             motion = None
   541             if(objectmblur.get() == "true" and usemblur.get() == "true"):
   542                 # motion blur
   543                 frame = Blender.Get('curframe')
   544                 Blender.Set('curframe', frame+1)
   545                 m1 = 1.0*matrix # multiply by 1.0 to get a copy of orignal matrix (will be frame-independant) 
   546                 Blender.Set('curframe', frame)
   547                 if m1 != matrix:
   548                     print("  motion blur")
   549                     motion = m1
   550     
   551             if motion: # motion-blur only works with instances, so ensure mesh is exported as instance first
   552                 if mesh_name in self.meshes:
   553                     del self.meshes[mesh_name]
   554                     mesh.getFromObject(obj, 0, 1)
   555                     mats = getMaterials(obj)
   556                     print("  blender-mesh: %s (%d vertices, %d faces)"%(mesh_name, len(mesh.verts), len(mesh.faces)))
   557                     file.write("ObjectBegin \"%s\"\n"%mesh_name)
   558                     if (mesh_optimizing.get() == "true"):
   559                         self.exportMeshOpt(file, mesh, mats, mesh_name)
   560                     else:
   561                         self.exportMesh(file, mesh, mats, mesh_name)
   562                     file.write("ObjectEnd # %s\n\n"%mesh_name)
   563 
   564             file.write("AttributeBegin # %s\n"%obj.getName())
   565             file.write("\tTransform [%s %s %s %s  %s %s %s %s  %s %s %s %s  %s %s %s %s]\n"\
   566                 %(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],\
   567                   matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],\
   568                   matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],\
   569                     matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]))
   570             if motion:
   571                 file.write("\tTransformBegin\n")
   572                 file.write("\t\tIdentity\n")
   573                 file.write("\t\tTransform [%s %s %s %s  %s %s %s %s  %s %s %s %s  %s %s %s %s]\n"\
   574                     %(motion[0][0], motion[0][1], motion[0][2], motion[0][3],\
   575                       motion[1][0], motion[1][1], motion[1][2], motion[1][3],\
   576                       motion[2][0], motion[2][1], motion[2][2], motion[2][3],\
   577                         motion[3][0], motion[3][1], motion[3][2], motion[3][3]))
   578                 file.write("\t\tCoordinateSystem \"%s\"\n"%(obj.getName()+"_motion"))
   579                 file.write("\tTransformEnd\n")
   580             if mesh_name in self.meshes:
   581                 mesh.getFromObject(obj, 0, 1)
   582                 mats = getMaterials(obj)
   583                 print("  blender-mesh: %s (%d vertices, %d faces)"%(mesh_name, len(mesh.verts), len(mesh.faces)))
   584                 if (mesh_optimizing.get() == "true"):
   585                     self.exportMeshOpt(file, mesh, mats, mesh_name)
   586                 else:
   587                     self.exportMesh(file, mesh, mats, mesh_name)
   588             else:
   589                 print("  instance %s"%(mesh_name))
   590                 if motion:
   591                     file.write("\tMotionInstance \"%s\" 0.0 1.0 \"%s\"\n"%(mesh_name, obj.getName()+"_motion"))
   592                 else:
   593                     file.write("\tObjectInstance \"%s\"\n"%mesh_name)
   594             file.write("AttributeEnd\n\n")
   595         mesh.verts = None
   596 
   597     #-------------------------------------------------
   598     # exportPortals(self, file)
   599     # exports portals objects to the file
   600     #-------------------------------------------------
   601     def exportPortals(self, file):
   602         scn = Scene.GetCurrent()
   603         mesh_optimizing = luxProp(scn, "mesh_optimizing", "true")
   604         mesh = Mesh.New('')
   605         for [obj, matrix] in self.portals:
   606             print("portal: %s"%(obj.getName()))
   607             file.write("\tTransform [%s %s %s %s  %s %s %s %s  %s %s %s %s  %s %s %s %s]\n"\
   608                 %(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],\
   609                   matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],\
   610                   matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],\
   611                     matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]))
   612             mesh_name = obj.getData(name_only=True)
   613             mesh.getFromObject(obj, 0, 1)
   614             mats = getMaterials(obj) # mats = obj.getData().getMaterials()
   615             if (mesh_optimizing.get() == "true"):
   616                 self.exportMeshOpt(file, mesh, mats, mesh_name, True)
   617             else:
   618                 self.exportMesh(file, mesh, mats, mesh_name, True)
   619         mesh.verts = None
   620 
   621     #-------------------------------------------------
   622     # exportLights(self, file)
   623     # exports lights to the file
   624     #-------------------------------------------------
   625     def exportLights(self, file):
   626         for [obj, matrix] in self.lights:
   627             ltype = obj.getData(mesh=1).getType() # data
   628             if (ltype == Lamp.Types["Lamp"]) or (ltype == Lamp.Types["Spot"]) or (ltype == Lamp.Types["Area"]):
   629                 print("light: %s"%(obj.getName()))
   630                 if ltype == Lamp.Types["Area"]:
   631                     (str, link) = luxLight("", "", obj, None, 0)
   632                     file.write(str)
   633                 if ltype == Lamp.Types["Area"]: file.write("AttributeBegin # %s\n"%obj.getName())
   634                 else: file.write("TransformBegin # %s\n"%obj.getName())
   635                 file.write("\tTransform [%s %s %s %s  %s %s %s %s  %s %s %s %s  %s %s %s %s]\n"\
   636                     %(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],\
   637                       matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],\
   638                       matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],\
   639                         matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]))
   640                 col = obj.getData(mesh=1).col # data
   641                 energy = obj.getData(mesh=1).energy # data
   642                 if ltype == Lamp.Types["Lamp"]:
   643                     lightgroup = luxProp(obj, "light.lightgroup", "default")
   644                     if luxProp(Scene.GetCurrent(), "nolg", "false").get()!="true":
   645                         file.write("LightGroup \"%s\"\n"%lightgroup.get())
   646                     (str, link) = luxLamp("", "", obj, None, 0)
   647                     file.write(str+"LightSource \"point\""+link+"\n")
   648                 if ltype == Lamp.Types["Spot"]:
   649                     (str, link) = luxSpot("", "", obj, None, 0)
   650                     file.write(str)
   651                     proj = luxProp(obj, "light.usetexproj", "false")
   652                     if luxProp(Scene.GetCurrent(), "nolg", "false").get()!="true":
   653                         lightgroup = luxProp(obj, "light.lightgroup", "default")
   654                         file.write("LightGroup \"%s\"\n"%lightgroup.get())
   655                     if(proj.get() == "true"):
   656                         file.write("Rotate 180 0 1 0\n")
   657                         file.write("LightSource \"projection\" \"float fov\" [%f]"%(obj.getData(mesh=1).spotSize))
   658                     else:
   659                         file.write("LightSource \"spot\" \"point from\" [0 0 0] \"point to\" [0 0 -1] \"float coneangle\" [%f] \"float conedeltaangle\" [%f]"\
   660                             %(obj.getData(mesh=1).spotSize*0.5, obj.getData(mesh=1).spotSize*0.5*obj.getData(mesh=1).spotBlend)) # data
   661                     file.write(link+"\n")
   662                 if ltype == Lamp.Types["Area"]:
   663                     lightgroup = luxProp(obj, "light.lightgroup", "default")
   664                     if luxProp(Scene.GetCurrent(), "nolg", "false").get()!="true":
   665                         file.write("LightGroup \"%s\"\n"%lightgroup.get())
   666                     file.write("\tAreaLightSource \"area\"")
   667                     file.write(link)
   668 #                    file.write(luxLight("", "", obj, None, 0))
   669                     file.write("\n")
   670                     areax = obj.getData(mesh=1).getAreaSizeX()
   671                     # lamps "getAreaShape()" not implemented yet - so we can't detect shape! Using square as default
   672                     # todo: ideasman42
   673                     if (True): areay = areax
   674                     else: areay = obj.getData(mesh=1).getAreaSizeY()
   675                     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})
   676                 if ltype == Lamp.Types["Area"]: file.write("AttributeEnd # %s\n"%obj.getName())
   677                 else: file.write("TransformEnd # %s\n"%obj.getName())
   678                 file.write("\n")
   679 
   680 
   681     #-------------------------------------------------
   682     # exportVolumes(self, file)
   683     # exports volumes to the file
   684     #-------------------------------------------------
   685     def exportVolumes(self, file):
   686         for [obj, matrix] in self.volumes:
   687             print("volume: %s"%(obj.getName()))
   688             file.write("# Volume: %s\n"%(obj.getName()))
   689 
   690             # trickery to obtain objectspace boundingbox AABB
   691             mat = obj.matrixWorld.copy().invert()
   692             bb = [vec * mat for vec in obj.getBoundBox()]
   693             minx = miny = minz = 100000000000000.0
   694             maxx = maxy = maxz = -100000000000000.0
   695             for vec in bb:
   696                 if (vec[0] < minx): minx = vec[0]
   697                 if (vec[1] < miny): miny = vec[1]
   698                 if (vec[2] < minz): minz = vec[2]
   699                 if (vec[0] > maxx): maxx = vec[0]
   700                 if (vec[1] > maxy): maxy = vec[1]
   701                 if (vec[2] > maxz): maxz = vec[2]
   702 
   703             file.write("Transform [%s %s %s %s  %s %s %s %s  %s %s %s %s  %s %s %s %s]\n"\
   704                 %(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],\
   705                   matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],\
   706                   matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],\
   707                     matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]))
   708 
   709             str_opt = (" \"point p0\" [%f %f %f] \"point p1\" [%f %f %f]"%(minx, miny, minz, maxx, maxy, maxz))
   710             mats = getMaterials(obj)
   711             if (len(mats)>0) and (mats[0]!=None) and (luxProp(mats[0], "type", "").get()=="boundvolume"):
   712                 mat = mats[0]
   713                 (str, link) = luxMaterialBlock("", "", "", mat, None, 0, str_opt)
   714                 file.write("%s"%link)
   715                 file.write("\n\n")
   716 
   717 
   718 # Note - radiance - this is a work in progress
   719 def luxFlashBlock(camObj):
   720     str = ""
   721     str += "CoordSysTransform \"camera\"\n"
   722 
   723     str += "Texture \"camflashtex\" \"color\" \"blackbody\" \"float temperature\" [5500.0]"
   724     str += "AreaLightSource \"area\" \"texture L\" [\"camflashtex\"] \"float power\" [100.000000] \"float efficacy\" [17.000000] \"float gain\" [1.000000]\n"
   725 
   726     up = 10.0
   727 
   728     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"
   729 
   730     return str
   731 
   732 
   733 ######################################################
   734 # EXPORT
   735 ######################################################
   736 
   737 def save_lux(filename, unindexedname):
   738     
   739     export_total_steps = 12.0
   740     
   741     global meshlist, matnames, lxs_filename, geom_filename, geom_pfilename, mat_filename, mat_pfilename, vol_filename, vol_pfilename, LuxIsGUI
   742 
   743     global render_status_text
   744     global render_status
   745     render_status_text = 'Exporting...'
   746     render_status = True
   747 
   748     print("Lux Render Export started...\n")
   749     time1 = Blender.sys.time()
   750     scn = Scene.GetCurrent()
   751 
   752     filepath = os.path.dirname(filename)
   753     filebase = os.path.splitext(os.path.basename(filename))[0]
   754 
   755     lxs_filename = filename
   756 
   757     geom_filename = os.path.join(filepath, filebase + "-geom.lxo")
   758     geom_pfilename = filebase + "-geom.lxo"
   759 
   760     mat_filename = os.path.join(filepath, filebase + "-mat.lxm")
   761     mat_pfilename = filebase + "-mat.lxm"
   762     
   763     vol_filename = os.path.join(filepath, filebase + "-vol.lxv")
   764     vol_pfilename = filebase + "-vol.lxv"
   765 
   766     ### Zuegs: initialization for export class
   767     export = luxExport(Blender.Scene.GetCurrent())
   768 
   769     # check if a light is present
   770     envtype = luxProp(scn, "env.type", "infinite").get()
   771     if envtype == "sunsky":
   772         sun = None
   773         for obj in scn.objects:
   774             if (obj.getType() == "Lamp") and ((obj.Layers & scn.Layers) > 0):
   775                 if obj.getData(mesh=1).getType() == 1: # sun object # data
   776                     sun = obj
   777     if not(export.analyseScene()) and not(envtype == "infinite") and not((envtype == "sunsky") and (sun != None)):
   778         print("ERROR: No light source found")
   779         Draw.PupMenu("ERROR: No light source found%t|OK%x1")
   780         render_status_text = ''
   781         render_status = False
   782         Blender.Window.QRedrawAll()
   783         del export
   784         return False
   785 
   786     if LuxIsGUI: DrawProgressBar(0.0/export_total_steps,'Setting up Scene file')
   787     
   788     class output_proxy():
   789         load_result = False
   790         combine_all_output = False
   791         f = None
   792         def close(self):
   793             if self.f is not None: self.f.close()
   794         def write(self, str):
   795             if self.f is not None:
   796                 self.f.write(str)
   797                 self.f.flush()
   798             
   799     class file_output(output_proxy):
   800         def __init__(self,filename):
   801             self.f = open(filename, "w")
   802             
   803     from threading import Thread
   804     class pipe_output(output_proxy, Thread):
   805         combine_all_output = True
   806         
   807         def __init__(self, xr,yr, haltspp, halttime, filename):
   808             Thread.__init__(self)
   809             
   810             self.filename = filename
   811             self.haltspp = haltspp
   812             self.halttime = halttime
   813             self.xr = xr
   814             self.yr = yr
   815             
   816             if self.haltspp > 0 or self.halttime > 0:
   817                 bintype = "luxconsole"
   818                 self.load_result = True
   819             else:
   820                 bintype = "luxrender"
   821                
   822             print("pipe: using %s" % bintype)
   823                 
   824             self.p = get_lux_pipe(scn, 1, bintype)
   825             self.f = self.p.stdin
   826         def close(self):
   827             global render_status_text
   828             global render_status
   829             render_status = True
   830             render_status_text = "Rendering ..."
   831             Blender.Window.QRedrawAll()
   832             self.start()
   833         
   834         def run(self):
   835             if self.load_result: self.data = self.p.communicate()[0]
   836             self.f.close()
   837             if self.load_result: # self.load_image()
   838                 self.load_data()
   839             print("LuxRender process finished")
   840             self.update_status()
   841             
   842         def load_image(self):
   843             i = Blender.Image.Load(self.filename)
   844             i.makeCurrent()
   845             i.reload()
   846            
   847         def load_data(self):
   848             print("processing %i image bytes" % len(self.data))
   849             i = Blender.Image.New('luxrender', self.xr, self.yr, 32)
   850             raw_image = []
   851             for j in self.data:
   852                 raw_image.append(ord(j))
   853             del self.data
   854             bi = 0
   855             for y in range(self.yr-1, -1, -1):
   856                 for x in range(0, self.xr):
   857                     i.setPixelI(x,y, raw_image[bi:bi+3]+[0])
   858                     bi+=3
   859             i.makeCurrent()
   860             
   861         def update_status(self):
   862             global render_status_text
   863             global render_status
   864             render_status = False
   865             render_status_text = "Rendering complete"
   866             if self.haltspp > 0 or self.halttime > 0: render_status_text += ", check Image Editor window"
   867             Blender.Window.QRedrawAll()
   868             
   869     use_pipe_output = luxProp(scn, "pipe", "false").get() == "true" and luxProp(scn, "run", "true").get() == "true"
   870     
   871     file = output_proxy()
   872     
   873     if luxProp(scn, "lxs", "true").get()=="true" or use_pipe_output:
   874         ##### Determine/open files
   875         if use_pipe_output:
   876             print("using pipe output")
   877             print("Exporting scene to pipe")
   878             xr,yr = get_render_resolution(scn)
   879             file = pipe_output(xr, yr,
   880                 luxProp(scn, "haltspp", 0).get(),
   881                 luxProp(scn, "halttime", 0).get(),
   882                 os.path.join(filepath, filebase + ".png")
   883             )
   884         else:
   885             print("using file output")
   886             print("Exporting scene to '" + filename + "'...\n")
   887             file = file_output(filename)
   888 
   889         ##### Write Header ######
   890         file.write("# Lux Render v%s Scene File\n"%__version__)
   891         file.write("# Exported by LuxBlend Blender Exporter\n")
   892         file.write("\n")
   893     
   894         ##### Write camera ######
   895         camObj = scn.getCurrentCamera()
   896 
   897         if LuxIsGUI: DrawProgressBar(1.0/export_total_steps,'Exporting Camera')
   898         if camObj:
   899             print("processing Camera...")
   900             cam = camObj.data
   901             cammblur = luxProp(cam, "cammblur", "true")
   902             usemblur = luxProp(cam, "usemblur", "false")
   903 
   904             matrix = camObj.getMatrix()
   905 
   906             motion = None
   907             if(cammblur.get() == "true" and usemblur.get() == "true"):
   908                 # motion blur
   909                 frame = Blender.Get('curframe')
   910                 Blender.Set('curframe', frame+1)
   911                 m1 = 1.0*matrix # multiply by 1.0 to get a copy of original matrix (will be frame-independant) 
   912                 Blender.Set('curframe', frame)
   913                 if m1 != matrix:
   914                     # Motion detected, write endtransform
   915                     print("  motion blur")
   916                     motion = m1
   917                     pos = m1[3]
   918                     forwards = -m1[2]
   919                     target = pos + forwards
   920                     up = m1[1]
   921                     file.write("TransformBegin\n")
   922                     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] ))
   923                     file.write("   CoordinateSystem \"CameraEndTransform\"\n")
   924                     file.write("TransformEnd\n\n")
   925 
   926             # Write original lookat transform
   927             pos = matrix[3]
   928             forwards = -matrix[2]
   929             target = pos + forwards
   930             up = matrix[1]
   931             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] ))
   932             file.write(luxCamera(camObj.data, scn.getRenderingContext()))
   933             if motion:
   934                 file.write("\n   \"string endtransform\" [\"CameraEndTransform\"]")
   935             file.write("\n")
   936         file.write("\n")
   937     
   938         if LuxIsGUI: DrawProgressBar(2.0/export_total_steps,'Exporting Film Settings')
   939         ##### Write film ######
   940         file.write(luxFilm(scn))
   941         file.write("\n")
   942 
   943         if LuxIsGUI: DrawProgressBar(3.0/export_total_steps,'Exporting Pixel Filter')
   944         ##### Write Pixel Filter ######
   945         file.write(luxPixelFilter(scn))
   946         file.write("\n")
   947     
   948         if LuxIsGUI: DrawProgressBar(4.0/export_total_steps,'Exporting Sampler')
   949         ##### Write Sampler ######
   950         file.write(luxSampler(scn))
   951         file.write("\n")
   952     
   953         if LuxIsGUI: DrawProgressBar(5.0/export_total_steps,'Exporting Surface Integrator')
   954         ##### Write Surface Integrator ######
   955         file.write(luxSurfaceIntegrator(scn))
   956         file.write("\n")
   957         
   958         if LuxIsGUI: DrawProgressBar(6.0/export_total_steps,'Exporting Volume Integrator')
   959         ##### Write Volume Integrator ######
   960         file.write(luxVolumeIntegrator(scn))
   961         file.write("\n")
   962         
   963         if LuxIsGUI: DrawProgressBar(7.0/export_total_steps,'Exporting Accelerator')
   964         ##### Write Acceleration ######
   965         file.write(luxAccelerator(scn))
   966         file.write("\n")    
   967     
   968         ########## BEGIN World
   969         file.write("\n")
   970         file.write("WorldBegin\n")
   971         file.write("\n")
   972 
   973         ########## World scale
   974         #scale = luxProp(scn, "global.scale", 1.0).get()
   975         #if scale != 1.0:
   976         #    # TODO: not working yet !!!
   977         #    # TODO: propabily scale needs to be applyed on camera coords too 
   978         #    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))
   979         #    file.write("\n")
   980         
   981         if LuxIsGUI: DrawProgressBar(8.0/export_total_steps,'Exporting Environment')
   982         ##### Write World Background, Sunsky or Env map ######
   983         env = luxEnvironment(scn)
   984         if env != "":
   985             file.write("AttributeBegin\n")
   986             file.write(env)
   987             export.exportPortals(file)
   988             file.write("AttributeEnd\n")
   989             file.write("\n")    
   990 
   991     # Note - radiance - this is a work in progress
   992 #        flash = luxFlashBlock(camObj)
   993 #        if flash != "":
   994 #            file.write("# Camera flash lamp\n")
   995 #            file.write("AttributeBegin\n")
   996 #            #file.write("CoordSysTransform \"camera\"\n")
   997 #            file.write(flash)
   998 #            file.write("AttributeEnd\n\n")
   999 
  1000         #### Write material & geometry file includes in scene file
  1001         if not file.combine_all_output: file.write("Include \"%s\"\n\n" %(mat_pfilename))
  1002         if not file.combine_all_output: file.write("Include \"%s\"\n\n" %(geom_pfilename))
  1003         if not file.combine_all_output: file.write("Include \"%s\"\n\n" %(vol_pfilename))
  1004         
  1005     if luxProp(scn, "lxm", "true").get()=="true" or use_pipe_output:
  1006         if LuxIsGUI: DrawProgressBar(9.0/export_total_steps,'Exporting Materials')
  1007         ##### Write Material file #####
  1008         if not file.combine_all_output: print("Exporting materials to '" + mat_filename + "'...\n")
  1009         mat_file = open(mat_filename, 'w') if not file.combine_all_output else file
  1010         mat_file.write("")
  1011         export.exportMaterials(mat_file)
  1012         mat_file.write("")
  1013         if not file.combine_all_output: mat_file.close()
  1014     
  1015     if luxProp(scn, "lxo", "true").get()=="true" or use_pipe_output:
  1016         if LuxIsGUI: DrawProgressBar(10.0/export_total_steps,'Exporting Geometry')
  1017         ##### Write Geometry file #####
  1018         if not file.combine_all_output: print("Exporting geometry to '" + geom_filename + "'...\n")
  1019         geom_file = open(geom_filename, 'w') if not file.combine_all_output else file
  1020         meshlist = []
  1021         geom_file.write("")
  1022         export.exportLights(geom_file)
  1023         export.exportMeshes(geom_file)
  1024         export.exportObjects(geom_file)
  1025         geom_file.write("")
  1026         if not file.combine_all_output: geom_file.close()
  1027 
  1028     if luxProp(scn, "lxv", "true").get()=="true" or use_pipe_output:
  1029         if LuxIsGUI: DrawProgressBar(11.0/export_total_steps,'Exporting Volumes')
  1030         ##### Write Volume file #####
  1031         if not file.combine_all_output: print("Exporting volumes to '" + vol_filename + "'...\n")
  1032         vol_file = open(vol_filename, 'w') if not file.combine_all_output else file
  1033         meshlist = []
  1034         vol_file.write("")
  1035         export.exportVolumes(vol_file)
  1036         vol_file.write("")
  1037         if not file.combine_all_output: vol_file.close()
  1038 
  1039     render_status_text = ''
  1040     render_status = False
  1041     Blender.Window.QRedrawAll()
  1042 
  1043     if luxProp(scn, "lxs", "true").get()=="true" or use_pipe_output:
  1044         #### Write End Tag
  1045         file.write("WorldEnd\n\n")
  1046         file.close()
  1047 
  1048     if LuxIsGUI: DrawProgressBar(12.0/export_total_steps,'Export Finished')
  1049     print("Finished.\n")
  1050     del export
  1051     
  1052     time2 = Blender.sys.time()
  1053     print("Processing time: %f\n" %(time2-time1))
  1054 
  1055     if use_pipe_output:
  1056         #if luxProp(scn, "haltspp", 0).get() > 0:
  1057             # Wait for piped luxconsole render thread to end
  1058         file.join()
  1059 
  1060         # Don't launch it again as a piped scene is started implicitly
  1061         return False
  1062 
  1063     return True
  1064 
  1065 ########################################################################
  1066 ####  Construct server string argument
  1067 ########################################################################
  1068 
  1069 def networkstring(scn):
  1070     servers_string = ""
  1071     if  (luxProp(scn,"network","false").get() == "true"):
  1072         if (luxProp(scn,"network_use_file","false").get() == "true"):
  1073             print("read network servers from file: "+ luxProp(scn,"network_file_path","false").get())
  1074             f = open(luxProp(scn,"network_file_path","false").get())
  1075             for s in f:
  1076                 s = s.strip("\n")
  1077                 print("add server :" + s)
  1078                 servers_string=servers_string+" -u "+ s
  1079             f.close
  1080         else : 
  1081              if  luxProp(scn,"network_servers","").get():
  1082                  for server in luxProp(scn,"network_servers","").get().split(","):
  1083                     servers_string=servers_string+" -u "+ server
  1084     return servers_string
  1085 
  1086 
  1087 #########################################################################
  1088 ###     LAUNCH LuxRender AND RENDER CURRENT SCENE
  1089 #########################################################################
  1090 
  1091 def get_lux_exec(scn, type="luxrender"):
  1092     
  1093     #get blenders 'bpydata' directory
  1094     datadir=Blender.Get("datadir")
  1095     
  1096     ic = luxProp(scn, "lux", "").get()
  1097     ic = Blender.sys.dirname(ic) + os.sep + type
  1098     
  1099     if osys.platform == "win32": ic = ic + ".exe"
  1100     
  1101     if type=="luxrender" and osys.platform == "darwin": ic = ic + ".app/Contents/MacOS/luxrender"
  1102     
  1103     return ic
  1104     
  1105 def get_lux_args(filename, extra_args=[], anim=False):
  1106     ostype = osys.platform
  1107     scn = Scene.GetCurrent()
  1108     
  1109     ic = get_lux_exec(scn, type=(anim and 'luxconsole' or 'luxrender'))
  1110     
  1111     servers_string = networkstring(scn)
  1112     update_int=luxProp(scn,"newtork_interval",180).get()
  1113     
  1114     checkluxpath = luxProp(scn, "checkluxpath", True).get()
  1115     if checkluxpath:
  1116         if sys.exists(ic) != 1:
  1117             Draw.PupMenu("Error: Lux renderer not found. Please set path on System page.%t|OK")
  1118             return
  1119     autothreads = luxProp(scn, "autothreads", "true").get()
  1120     threads = luxProp(scn, "threads", 1).get()
  1121     luxnice = luxProp(scn, "luxnice", 0).get()
  1122     noopengl = luxProp(scn, "noopengl", "false").get()
  1123     
  1124     if noopengl == "true" and not anim:
  1125         extra_args.append("--noopengl")
  1126     
  1127     lux_args = "\"%s\" " % ic
  1128     
  1129     extra_args.append('%s'%servers_string)
  1130     extra_args.append("-i %d " % update_int)
  1131     
  1132     if autothreads != "true":
  1133         extra_args.append("--threads=%d " % threads)
  1134     
  1135     lux_args2 = ' '.join(extra_args)
  1136     
  1137     if filename == '-':
  1138         lux_args2 = " - " + lux_args2
  1139     else:
  1140         filename = "\"%s\"" % filename
  1141         lux_args2 = lux_args2 + filename
  1142         
  1143     lux_args += lux_args2
  1144     
  1145     if ostype == "win32":
  1146         prio = ""
  1147         if luxnice > 15: prio = "/low"
  1148         elif luxnice > 5: prio = "/belownormal"
  1149         elif luxnice > -5: prio = "/normal"
  1150         elif luxnice > -15: prio = "/abovenormal"
  1151         else: prio = "/high"
  1152         
  1153         if not anim:
  1154             cmd = "start /b %s \"\" %s" % (prio, lux_args)
  1155         else:
  1156             cmd = "start /WAIT %s \"\" %s" % (prio, lux_args)
  1157         
  1158 #    if ostype == "linux2" or ostype == "darwin":
  1159     else:
  1160         if not anim:
  1161             cmd = "(nice -n %d %s)&"%(luxnice, lux_args)
  1162         else:
  1163             cmd = "(nice -n %d %s)"%(luxnice, lux_args)
  1164     
  1165     return cmd, lux_args2
  1166 
  1167 def get_lux_pipe(scn, buf = 1024, type="luxconsole"):
  1168     bin = "\"%s\"" % get_lux_exec(scn, type)
  1169     
  1170     print("piping to lux binary: " + bin)
  1171     
  1172     PIPE = subprocess.PIPE
  1173     
  1174     cmd, raw_args = get_lux_args('-',
  1175         extra_args=['-b'] if type=="luxconsole" else []
  1176     )
  1177     
  1178     # dirty hack to filter "noopengl" option from luxconsole args
  1179     raw_args = raw_args.replace('--noopengl', '')
  1180 
  1181     return subprocess.Popen(bin + raw_args, shell=True, bufsize=buf, stdin=PIPE, stdout=PIPE, stderr=PIPE)
  1182 
  1183 def launchLux(filename):
  1184     cmd, raw_args = get_lux_args(filename, extra_args=[])
  1185     print("Running Luxrender:\n"+cmd)
  1186     os.system(cmd)
  1187 
  1188 def launchLuxWait(filename, anim=False):
  1189     ostype = osys.platform
  1190     cmd, raw_args = get_lux_args(filename, extra_args=[], anim=anim)
  1191     
  1192     if ostype == "win32":
  1193         os.system(cmd)
  1194     
  1195 #    if ostype == "linux2" or ostype == "darwin":
  1196     else:
  1197         subprocess.call(cmd,shell=True)
  1198 
  1199 #### SAVE ANIMATION ####
  1200 
  1201 
  1202 #def save_anim(filename):
  1203 #    global LuxIsGUI
  1204 #    scn = Scene.GetCurrent()
  1205 #    to = luxProp(scn, 'export.threaded', 'true').get()
  1206 #    run = luxProp(scn, "run", "true").get()
  1207 #    deflt = luxProp(scn, "default", "true").get()
  1208 #    if to == 'true' and run == 'true' and deflt == 'false':
  1209 #        import threading
  1210 #        anim_thread = threading.Thread(target=save_anim_real, args=(filename,True))
  1211 #        anim_thread.start()
  1212 #    else:
  1213 #        save_anim_real(filename)
  1214 
  1215 def save_anim(filename, as_thread=False):
  1216     if as_thread: print('SAR thread started')
  1217     global MatSaved, LuxIsGUI
  1218     
  1219     MatSaved = 0
  1220     startF = Blender.Get('staframe')
  1221     endF = Blender.Get('endframe')
  1222     scn = Scene.GetCurrent()
  1223 
  1224     Run = luxProp(scn, "run", "true").get()
  1225 
  1226     if Run == "true":
  1227         haltspp = luxProp(scn, "haltspp", 0).get()
  1228         halttime = luxProp(scn, "halttime", 0).get()
  1229         if haltspp == 0 and halttime == 0:
  1230             Draw.PupMenu("ERROR: You must set a limit for spp (Output->halt) or for time (Output->time) when doing animation and the 'run' flag is switched on")
  1231             if LuxIsGUI:
  1232                 Draw.Redraw()
  1233             return
  1234 
  1235     print("\n\nRendering animation (frame %i to %i)\n\n"%(startF, endF))
  1236 
  1237     v_frame = Blender.Get('curframe')
  1238 
  1239     for i in range (startF, endF+1):
  1240         # Seems to get stuck unless we redraw the UI
  1241 #        if LuxIsGUI:
  1242 #            Window.QRedrawAll()
  1243         Blender.Set('curframe', i)
  1244         print("Rendering frame %i"%(i))
  1245         Blender.Redraw()
  1246         frameindex = ("-%05d" % (i)) + ".lxs"
  1247         indexedname = sys.makename(filename, frameindex)
  1248         unindexedname = filename
  1249         luxProp(scn, "filename", Blender.Get("filename")).set(sys.makename(filename, "-%05d" %  (Blender.Get('curframe'))))
  1250 
  1251         if Run == "true":
  1252             if save_lux(filename, unindexedname):
  1253                 launchLuxWait(filename, anim=True)
  1254         else:
  1255             save_lux(indexedname, unindexedname)
  1256 
  1257         MatSaved = 1
  1258         # Seems to get stuck unless we redraw the UI
  1259 #        if LuxIsGUI:
  1260 #            Window.QRedrawAll()
  1261             
  1262     Blender.Set('curframe', v_frame)
  1263 
  1264     print("\n\nFinished Rendering animation\n")
  1265     if as_thread: print('SAR thread finished')
  1266 
  1267 #### SAVE STILL (hackish...) ####
  1268 
  1269 #import threading
  1270 #def save_still(filename):
  1271 #    global LuxIsGUI
  1272 #    scn = Scene.GetCurrent()
  1273 #    to = luxProp(scn, 'export.threaded', 'true').get()
  1274 #    if to == 'true' and luxProp(scn, "run", "true").get() == "true":
  1275 #        import threading
  1276 #        still_thread = threading.Thread(target=save_still_real, args=(filename,))
  1277 #        still_thread.start()
  1278 #    else:
  1279 #        save_still_real(filename)
  1280 
  1281 def save_still(filename):
  1282     global MatSaved, runRenderAfterExport
  1283     scn = Scene.GetCurrent()
  1284     luxProp(scn, "filename", Blender.Get("filename")).set(sys.makename(filename, ""))
  1285     MatSaved = 0
  1286     unindexedname = filename
  1287     # Seems to get stuck unless we redraw the UI
  1288 #    if LuxIsGUI:
  1289 #        Window.QRedrawAll()
  1290     if save_lux(filename, unindexedname):
  1291         if runRenderAfterExport and luxProp(scn, "pipe", "false").get() == "false": #(run == None and luxProp(scn, "run", "true").get() == "true") or run:
  1292             launchLux(filename)
  1293             
  1294     # Seems to get stuck unless we redraw the UI
  1295 #    if LuxIsGUI:
  1296 #        Window.QRedrawAll()
  1297 
  1298 
  1299 ######################################################
  1300 # Icons
  1301 ######################################################
  1302 
  1303 def base64value(char):
  1304     if 64 < ord(char) < 91: return ord(char)-65
  1305     if 96 < ord(char) < 123: return ord(char)-97+26
  1306     if 47 < ord(char) < 58: return ord(char)-48+52
  1307     if char == '+': return 62
  1308     return 63
  1309 
  1310 def decodeIconStr(s):
  1311     buf = BGL.Buffer(BGL.GL_BYTE, [16,16,4])
  1312     offset = 0
  1313     for y in range(16):
  1314         for x in range(16):
  1315             for c in range(4):
  1316                 buf[y][x][c] = int(base64value(s[offset])*4.048)
  1317                 offset += 1
  1318     return buf
  1319 
  1320 def decodeLogoStr(s):
  1321     buf = BGL.Buffer(BGL.GL_BYTE, [18,118,4])
  1322     offset = 0
  1323     for y in range(18):
  1324         for x in range(118):
  1325             for c in range(4):
  1326                 buf[y][x][c] = int(base64value(s[offset])*4.048)
  1327                 offset += 1
  1328     return buf
  1329 
  1330 def decodeArrowStr(s):
  1331     buf = BGL.Buffer(BGL.GL_BYTE, [22,22,4])
  1332     offset = 0
  1333     for y in range(22):
  1334         for x in range(22):
  1335             for c in range(4):
  1336                 buf[y][x][c] = int(base64value(s[offset])*4.048)
  1337                 offset += 1
  1338     return buf
  1339 
  1340 def decodeBarStr(s):
  1341     buf = BGL.Buffer(BGL.GL_BYTE, [17,138,4])
  1342     offset = 0
  1343     for y in range(17):
  1344         for x in range(138):
  1345             for c in range(4):
  1346                 buf[y][x][c] = int(base64value(s[offset])*4.048)
  1347                 offset += 1
  1348     return buf
  1349 
  1350 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")
  1351 
  1352 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")
  1353 
  1354 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")
  1355 
  1356 
  1357 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")
  1358 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")
  1359 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")
  1360 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")
  1361 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")
  1362 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")
  1363 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")
  1364 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")
  1365 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")
  1366 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")
  1367 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")
  1368 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")
  1369 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")
  1370 
  1371 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")
  1372 
  1373 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")
  1374 
  1375 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")
  1376 
  1377 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")
  1378 
  1379 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")
  1380 
  1381 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")
  1382 
  1383 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")
  1384 
  1385 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")
  1386 
  1387 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")
  1388 
  1389 
  1390 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")
  1391 
  1392 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//")
  1393 
  1394 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") 
  1395 
  1396 def drawIcon(icon, x, y):
  1397     BGL.glEnable(BGL.GL_BLEND)
  1398     BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA) 
  1399     BGL.glRasterPos2f(int(x)+0.5, int(y)+0.5)
  1400     BGL.glDrawPixels(16, 16, BGL.GL_RGBA, BGL.GL_UNSIGNED_BYTE, icon)
  1401     BGL.glDisable(BGL.GL_BLEND)
  1402 
  1403 def drawArrow(icon, x, y):
  1404     BGL.glEnable(BGL.GL_BLEND)
  1405     BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA) 
  1406     BGL.glRasterPos2f(int(x)+0.5, int(y)+0.5)
  1407     BGL.glDrawPixels(22, 22, BGL.GL_RGBA, BGL.GL_UNSIGNED_BYTE, icon)
  1408     BGL.glDisable(BGL.GL_BLEND)
  1409 
  1410 def drawLogo(icon, x, y):
  1411     BGL.glEnable(BGL.GL_BLEND)
  1412     BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA) 
  1413     BGL.glRasterPos2f(int(x)+0.5, int(y)+0.5)
  1414     BGL.glDrawPixels(118, 18, BGL.GL_RGBA, BGL.GL_UNSIGNED_BYTE, icon)
  1415     BGL.glDisable(BGL.GL_BLEND)
  1416 
  1417 def drawBar(icon, x, y):
  1418     BGL.glEnable(BGL.GL_BLEND)
  1419     BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA) 
  1420     BGL.glRasterPos2f(int(x)+0.5, int(y)+0.5)
  1421     BGL.glDrawPixels(138, 17, BGL.GL_RGBA, BGL.GL_UNSIGNED_BYTE, icon)
  1422     BGL.glDisable(BGL.GL_BLEND)
  1423 
  1424 
  1425 
  1426 #-------------------------------------------------
  1427 # luxImage()
  1428 # helper class to handle images and icons for the GUI
  1429 #-------------------------------------------------
  1430 
  1431 class luxImage:
  1432     def resize(self, width, height):
  1433         self.width = width
  1434         self.height = height
  1435         self.buf = BGL.Buffer(BGL.GL_BYTE, [width,height,4]) # GL buffer
  1436     def __init__(self, width=0, height=0):
  1437         self.resize(width, height)
  1438     def draw(self, x, y):
  1439         BGL.glEnable(BGL.GL_BLEND)
  1440         BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA) 
  1441         BGL.glRasterPos2f(int(x)+0.5, int(y)+0.5)
  1442         BGL.glDrawPixels(self.width, self.height, BGL.GL_RGBA, BGL.GL_UNSIGNED_BYTE, self.buf)
  1443         BGL.glDisable(BGL.GL_BLEND)        
  1444     def decodeStr(self, width, height, s):
  1445         self.resize(width, height)
  1446         offset = 0
  1447         for y in range(self.height):
  1448             for x in range(self.width):
  1449                 for c in range(4):
  1450                     self.buf[y][x][c] = int(base64value(s[offset])*4.048)
  1451                     offset += 1
  1452 
  1453     def decodeLuxConsole(self, width, height, data):
  1454         self.resize(width, height)
  1455         offset = 0
  1456         for y in range(self.height-1,-1,-1):
  1457             for x in range(self.width):
  1458                 for c in range(3):
  1459                     self.buf[y][x][c] = ord(data[offset])
  1460                     offset += 1
  1461                 self.buf[y][x][3] = 255
  1462 
  1463 
  1464 previewCache = {}  # dictionary that will hold all preview images
  1465 
  1466 
  1467 ######################################################
  1468 # New GUI by Zuegs
  1469 ######################################################
  1470 
  1471 from types import *
  1472 
  1473 evtLuxGui = 99
  1474 evtSavePreset = 98
  1475 evtDeletePreset = 97
  1476 evtSaveMaterial = 96
  1477 evtLoadMaterial = 95
  1478 evtDeleteMaterial = 94
  1479 evtConvertMaterial = 92
  1480 evtSaveMaterial2 = 91
  1481 evtLoadMaterial2 = 90
  1482 
  1483 
  1484 # default settings
  1485 defaultsExclude = ['preset','filename','page','link']
  1486 try:
  1487     luxdefaults = Blender.Registry.GetKey('luxblend', True)
  1488     if not(type(luxdefaults) is DictType):
  1489         luxdefaults = {}
  1490 except:
  1491     luxdefaults = {}
  1492 newluxdefaults = luxdefaults.copy()
  1493 
  1494 
  1495 def saveluxdefaults():
  1496     try: del newluxdefaults['page']
  1497     except: pass
  1498     try: Blender.Registry.SetKey('luxblend', newluxdefaults, True)
  1499     except: pass
  1500 
  1501 
  1502 
  1503 
  1504 
  1505 # *** PRESETS **************************************
  1506 presetsExclude = ['preset','lux','datadir','threads','filename','page','RGC','film.gamma','colorclamp','link']
  1507 def getPresets(key):
  1508     presets = Blender.Registry.GetKey(key, True)
  1509     if not(type(presets) is DictType):
  1510         presets = {}
  1511     return presets
  1512 def getScenePresets():
  1513     presets = getPresets('luxblend_presets').copy()
  1514 
  1515     # radiance's hardcoded render presets:
  1516 
  1517     presets['0 Preview - Global Illumination'] = {
  1518     'film.displayinterval': 4,
  1519     'haltspp': 0,
  1520     'halttime': 0,
  1521     'useparamkeys': 'false',
  1522     'sampler.showadvanced': 'false',
  1523     'sintegrator.showadvanced': 'false',
  1524     'pixelfilter.showadvanced': 'false',
  1525 
  1526     'sampler.type': 'lowdiscrepancy',
  1527     'sampler.lowdisc.pixelsamples': 1,
  1528     'sampler.lowdisc.pixelsampler': 'lowdiscrepancy',
  1529 
  1530     'sintegrator.type': 'distributedpath',
  1531     'sintegrator.distributedpath.directsampleall': 'true',
  1532     'sintegrator.distributedpath.directsamples': 1,
  1533     'sintegrator.distributedpath.directdiffuse': 'true',
  1534     'sintegrator.distributedpath.directglossy': 'true',
  1535     'sintegrator.distributedpath.indirectsampleall': 'false',
  1536     'sintegrator.distributedpath.indirectsamples': 1,
  1537     'sintegrator.distributedpath.indirectdiffuse': 'true',
  1538     'sintegrator.distributedpath.indirectglossy': 'true',
  1539     'sintegrator.distributedpath.diffusereflectdepth': 1,
  1540     'sintegrator.distributedpath.diffusereflectsamples': 4,
  1541     'sintegrator.distributedpath.diffuserefractdepth': 4,
  1542     'sintegrator.distributedpath.diffuserefractsamples': 1,
  1543     'sintegrator.distributedpath.glossyreflectdepth': 1,
  1544     'sintegrator.distributedpath.glossyreflectsamples': 2,
  1545     'sintegrator.distributedpath.glossyrefractdepth': 4,
  1546     'sintegrator.distributedpath.glossyrefractsamples': 1,
  1547     'sintegrator.distributedpath.specularreflectdepth': 2,
  1548     'sintegrator.distributedpath.specularrefractdepth': 4,
  1549     'sintegrator.distributedpath.causticsonglossy': 'true',
  1550     'sintegrator.distributedpath.causticsondiffuse': 'false',
  1551     'sintegrator.distributedpath.strategy': 'auto',
  1552 
  1553     'pixelfilter.type': 'mitchell',
  1554     'pixelfilter.mitchell.sharp': 0.250, 
  1555     'pixelfilter.mitchell.xwidth': 2.0, 
  1556     'pixelfilter.mitchell.ywidth': 2.0, 
  1557     'pixelfilter.mitchell.optmode': "slider" }
  1558 
  1559     presets['0b Preview - Direct Lighting'] = {
  1560     'film.displayinterval': 4,
  1561     'haltspp': 0,
  1562     'halttime': 0,
  1563     'useparamkeys': 'false',
  1564     'sampler.showadvanced': 'false',
  1565     'sintegrator.showadvanced': 'false',
  1566     'pixelfilter.showadvanced': 'false',
  1567 
  1568     'sampler.type': 'lowdiscrepancy',
  1569     'sampler.lowdisc.pixelsamples': 1,
  1570     'sampler.lowdisc.pixelsampler': 'lowdiscrepancy',
  1571 
  1572     'sintegrator.type': 'directlighting',
  1573     'sintegrator.dlighting.maxdepth': 5,
  1574 
  1575     'pixelfilter.type': 'mitchell',
  1576     'pixelfilter.mitchell.sharp': 0.250, 
  1577     'pixelfilter.mitchell.xwidth': 2.0, 
  1578     'pixelfilter.mitchell.ywidth': 2.0, 
  1579     'pixelfilter.mitchell.optmode': "slider" }
  1580 
  1581     presets['1 Final - MLT/Bidir Path Tracing (interior) (recommended)'] =  {
  1582     'film.displayinterval': 8,
  1583     'haltspp': 0,
  1584     'halttime': 0,
  1585     'useparamkeys': 'false',
  1586     'sampler.showadvanced': 'false',
  1587     'sintegrator.showadvanced': 'false',
  1588     'pixelfilter.showadvanced': 'false',
  1589 
  1590     'sampler.type': 'metropolis',
  1591     'sampler.metro.strength': 0.6,
  1592     'sampler.metro.lmprob': 0.4,
  1593     'sampler.metro.maxrejects': 512,
  1594     #'sampler.metro.initsamples': 262144,
  1595     'sampler.metro.usevariance': "false",
  1596 
  1597     'sintegrator.type': 'bidirectional',
  1598     'sintegrator.bidir.bounces': 16,
  1599     'sintegrator.bidir.eyedepth': 16,
  1600     'sintegrator.bidir.lightdepth': 16,
  1601 
  1602     'pixelfilter.type': 'mitchell',
  1603     'pixelfilter.mitchell.sharp': 0.250, 
  1604     'pixelfilter.mitchell.xwidth': 2.0, 
  1605     'pixelfilter.mitchell.ywidth': 2.0, 
  1606     'pixelfilter.mitchell.optmode': "slider" }
  1607 
  1608     presets['2 Final - MLT/Path Tracing (exterior)'] =  {
  1609     'film.displayinterval': 8,
  1610     'haltspp': 0,
  1611     'halttime': 0,
  1612     'useparamkeys': 'false',
  1613     'sampler.showadvanced': 'false',
  1614     'sintegrator.showadvanced': 'false',
  1615     'pixelfilter.showadvanced': 'false',
  1616 
  1617     'sampler.type': 'metropolis',
  1618     'sampler.metro.strength': 0.6,
  1619     'sampler.metro.lmprob': 0.4,
  1620     'sampler.metro.maxrejects': 512,
  1621     #'sampler.metro.initsamples': 262144,
  1622     'sampler.metro.usevariance': "false",
  1623 
  1624     'sintegrator.type': 'path',
  1625     'sintegrator.bidir.bounces': 10,
  1626     'sintegrator.bidir.maxdepth': 10,
  1627 
  1628     'pixelfilter.type': 'mitchell',
  1629     'pixelfilter.mitchell.sharp': 0.250, 
  1630     'pixelfilter.mitchell.xwidth': 2.0, 
  1631     'pixelfilter.mitchell.ywidth': 2.0, 
  1632     'pixelfilter.mitchell.optmode': "slider" }
  1633     
  1634     presets['4 '] = { }
  1635 
  1636     presets['5 Progressive - Bidir Path Tracing (interior)'] =  {
  1637     'film.displayinterval': 8,
  1638     'haltspp': 0,
  1639     'halttime': 0,
  1640     'useparamkeys': 'false',
  1641     'sampler.showadvanced': 'false',
  1642     'sintegrator.showadvanced': 'false',
  1643     'pixelfilter.showadvanced': 'false',
  1644 
  1645     'sampler.type': 'lowdiscrepancy',
  1646     'sampler.lowdisc.pixelsamples': 1,
  1647     'sampler.lowdisc.pixelsampler': 'lowdiscrepancy',
  1648 
  1649     'sintegrator.type': 'bidirectional',
  1650     'sintegrator.bidir.bounces': 16,
  1651     'sintegrator.bidir.eyedepth': 16,
  1652     'sintegrator.bidir.lightdepth': 16,
  1653 
  1654     'pixelfilter.type': 'mitchell',
  1655     'pixelfilter.mitchell.sharp': 0.250, 
  1656     'pixelfilter.mitchell.xwidth': 2.0, 
  1657     'pixelfilter.mitchell.ywidth': 2.0, 
  1658     'pixelfilter.mitchell.optmode': "slider" }
  1659 
  1660     presets['6 Progressive - Path Tracing (exterior)'] =  {
  1661     'film.displayinterval': 8,
  1662     'haltspp': 0,
  1663     'halttime': 0,
  1664     'useparamkeys': 'false',
  1665     'sampler.showadvanced': 'false',
  1666     'sintegrator.showadvanced': 'false',
  1667     'pixelfilter.showadvanced': 'false',
  1668 
  1669     'sampler.type': 'lowdiscrepancy',
  1670     'sampler.lowdisc.pixelsamples': 1,
  1671     'sampler.lowdisc.pixelsampler': 'lowdiscrepancy',
  1672 
  1673     'sintegrator.type': 'path',
  1674     'sintegrator.bidir.bounces': 10,
  1675     'sintegrator.bidir.maxdepth': 10,
  1676 
  1677     'pixelfilter.type': 'mitchell',
  1678     'pixelfilter.mitchell.sharp': 0.250, 
  1679     'pixelfilter.mitchell.xwidth': 2.0, 
  1680     'pixelfilter.mitchell.ywidth': 2.0, 
  1681     'pixelfilter.mitchell.optmode': "slider" }
  1682 
  1683     presets['7 '] = { }
  1684 
  1685     presets['8 Bucket - Bidir Path Tracing (interior)'] =  {
  1686     'film.displayinterval': 8,
  1687     'haltspp': 0,
  1688     'halttime': 0,
  1689     'useparamkeys': 'false',
  1690     'sampler.showadvanced': 'false',
  1691     'sintegrator.showadvanced': 'false',
  1692     'pixelfilter.showadvanced': 'false',
  1693 
  1694     'sampler.type': 'lowdiscrepancy',
  1695     'sampler.lowdisc.pixelsamples': 64,
  1696     'sampler.lowdisc.pixelsampler': 'hilbert',
  1697 
  1698     'sintegrator.type': 'bidirectional',
  1699     'sintegrator.bidir.bounces': 8,
  1700     'sintegrator.bidir.eyedepth': 8,
  1701     'sintegrator.bidir.lightdepth': 10,
  1702 
  1703     'pixelfilter.type': 'mitchell',
  1704     'pixelfilter.mitchell.sharp': 0.250, 
  1705     'pixelfilter.mitchell.xwidth': 2.0, 
  1706     'pixelfilter.mitchell.ywidth': 2.0, 
  1707     'pixelfilter.mitchell.optmode': "slider" }
  1708 
  1709     presets['9 Bucket - Path Tracing (exterior)'] =  {
  1710     'film.displayinterval': 8,
  1711     'haltspp': 0,
  1712     'halttime': 0,
  1713     'useparamkeys': 'false',
  1714     'sampler.showadvanced': 'false',
  1715     'sintegrator.showadvanced': 'false',
  1716     'pixelfilter.showadvanced': 'false',
  1717 
  1718     'sampler.type': 'lowdiscrepancy',
  1719     'sampler.lowdisc.pixelsamples': 64,
  1720     'sampler.lowdisc.pixelsampler': 'hilbert',
  1721 
  1722     'sintegrator.type': 'path',
  1723     'sintegrator.bidir.bounces': 8,
  1724     'sintegrator.bidir.maxdepth': 8,
  1725 
  1726     'pixelfilter.type': 'mitchell',
  1727     'pixelfilter.mitchell.sharp': 0.333, 
  1728     'pixelfilter.mitchell.xwidth': 2.0, 
  1729     'pixelfilter.mitchell.ywidth': 2.0, 
  1730     'pixelfilter.mitchell.optmode': "slider" }
  1731 
  1732     presets['A '] = { }
  1733 
  1734     presets['B Anim - Distributed/GI low Q'] =  {
  1735     'film.displayinterval': 8,
  1736     'haltspp': 1,
  1737     'halttime': 0,
  1738     'useparamkeys': 'false',
  1739     'sampler.showadvanced': 'false',
  1740     'sintegrator.showadvanced': 'false',
  1741     'pixelfilter.showadvanced': 'false',
  1742 
  1743     'sampler.type': 'lowdiscrepancy',
  1744     'sampler.lowdisc.pixelsamples': 16,
  1745     'sampler.lowdisc.pixelsampler': 'hilbert',
  1746 
  1747     'sintegrator.type': 'distributedpath',
  1748     'sintegrator.distributedpath.causticsonglossy': 'true',
  1749     'sintegrator.distributedpath.diffuserefractdepth': 5,
  1750     'sintegrator.distributedpath.indirectglossy': 'true',
  1751     'sintegrator.distributedpath.directsamples': 1,
  1752     'sintegrator.distributedpath.diffuserefractsamples': 1,
  1753     'sintegrator.distributedpath.glossyreflectdepth': 2,
  1754     'sintegrator.distributedpath.causticsondiffuse': 'false',
  1755     'sintegrator.distributedpath.directsampleall': 'true',
  1756     'sintegrator.distributedpath.indirectdiffuse': 'true',
  1757     'sintegrator.distributedpath.specularreflectdepth': 3,
  1758     'sintegrator.distributedpath.diffusereflectsamples': 1,
  1759     'sintegrator.distributedpath.glossyreflectsamples': 1,
  1760     'sintegrator.distributedpath.glossyrefractdepth': 5,
  1761     'sintegrator.distributedpath.diffusereflectdepth': '2',
  1762     'sintegrator.distributedpath.indirectsamples': 1,
  1763     'sintegrator.distributedpath.indirectsampleall': 'false',
  1764     'sintegrator.distributedpath.glossyrefractsamples': 1,
  1765     'sintegrator.distributedpath.directdiffuse': 'true',
  1766     'sintegrator.distributedpath.directglossy': 'true',
  1767     'sintegrator.distributedpath.strategy': 'auto',
  1768     'sintegrator.distributedpath.specularrefractdepth': 5,
  1769 
  1770     'pixelfilter.type': 'mitchell',
  1771     'pixelfilter.mitchell.sharp': 0.333, 
  1772     'pixelfilter.mitchell.xwidth': 2.0, 
  1773     'pixelfilter.mitchell.ywidth': 2.0, 
  1774     'pixelfilter.mitchell.optmode': "slider" }
  1775 
  1776     presets['C Anim - Distributed/GI medium Q'] =  {
  1777     'film.displayinterval': 8,
  1778     'haltspp': 1,
  1779     'halttime': 0,
  1780     'useparamkeys': 'false',
  1781     'sampler.showadvanced': 'false',
  1782     'sintegrator.showadvanced': 'false',
  1783     'pixelfilter.showadvanced': 'false',
  1784 
  1785     'sampler.type': 'lowdiscrepancy',
  1786     'sampler.lowdisc.pixelsamples': 64,
  1787     'sampler.lowdisc.pixelsampler': 'hilbert',
  1788 
  1789     'sintegrator.type': 'distributedpath',
  1790     'sintegrator.distributedpath.causticsonglossy': 'true',
  1791     'sintegrator.distributedpath.diffuserefractdepth': 5,
  1792     'sintegrator.distributedpath.indirectglossy': 'true',
  1793     'sintegrator.distributedpath.directsamples': 1,
  1794     'sintegrator.distributedpath.diffuserefractsamples': 1,
  1795     'sintegrator.distributedpath.glossyreflectdepth': 2,
  1796     'sintegrator.distributedpath.causticsondiffuse': 'false',
  1797     'sintegrator.distributedpath.directsampleall': 'true',
  1798     'sintegrator.distributedpath.indirectdiffuse': 'true',
  1799     'sintegrator.distributedpath.specularreflectdepth': 3,
  1800     'sintegrator.distributedpath.diffusereflectsamples': 1,
  1801     'sintegrator.distributedpath.glossyreflectsamples': 1,
  1802     'sintegrator.distributedpath.glossyrefractdepth': 5,
  1803     'sintegrator.distributedpath.diffusereflectdepth': '2',
  1804     'sintegrator.distributedpath.indirectsamples': 1,
  1805     'sintegrator.distributedpath.indirectsampleall': 'false',
  1806     'sintegrator.distributedpath.glossyrefractsamples': 1,
  1807     'sintegrator.distributedpath.directdiffuse': 'true',
  1808     'sintegrator.distributedpath.directglossy': 'true',
  1809     'sintegrator.distributedpath.strategy': 'auto',
  1810     'sintegrator.distributedpath.specularrefractdepth': 5,
  1811 
  1812     'pixelfilter.type': 'mitchell',
  1813     'pixelfilter.mitchell.sharp': 0.333, 
  1814     'pixelfilter.mitchell.xwidth': 2.0, 
  1815     'pixelfilter.mitchell.ywidth': 2.0, 
  1816     'pixelfilter.mitchell.optmode': "slider" }
  1817     
  1818     presets['D Anim - Distributed/GI high Q'] =  {
  1819     'film.displayinterval': 8,
  1820     'haltspp': 1,
  1821     'halttime': 0,
  1822     'useparamkeys': 'false',
  1823     'sampler.showadvanced': 'false',
  1824     'sintegrator.showadvanced': 'false',
  1825     'pixelfilter.showadvanced': 'false',
  1826 
  1827     'sampler.type': 'lowdiscrepancy',
  1828     'sampler.lowdisc.pixelsamples': 256,
  1829     'sampler.lowdisc.pixelsampler': 'hilbert',
  1830 
  1831     'sintegrator.type': 'distributedpath',
  1832     'sintegrator.distributedpath.causticsonglossy': 'true',
  1833     'sintegrator.distributedpath.diffuserefractdepth': 5,
  1834     'sintegrator.distributedpath.indirectglossy': 'true',
  1835     'sintegrator.distributedpath.directsamples': 1,
  1836     'sintegrator.distributedpath.diffuserefractsamples': 1,
  1837     'sintegrator.distributedpath.glossyreflectdepth': 2,
  1838     'sintegrator.distributedpath.causticsondiffuse': 'false',
  1839     'sintegrator.distributedpath.directsampleall': 'true',
  1840     'sintegrator.distributedpath.indirectdiffuse': 'true',
  1841     'sintegrator.distributedpath.specularreflectdepth': 3,
  1842     'sintegrator.distributedpath.diffusereflectsamples': 1,
  1843     'sintegrator.distributedpath.glossyreflectsamples': 1,
  1844     'sintegrator.distributedpath.glossyrefractdepth': 5,
  1845     'sintegrator.distributedpath.diffusereflectdepth': '2',
  1846     'sintegrator.distributedpath.indirectsamples': 1,
  1847     'sintegrator.distributedpath.indirectsampleall': 'false',
  1848     'sintegrator.distributedpath.glossyrefractsamples': 1,
  1849     'sintegrator.distributedpath.directdiffuse': 'true',
  1850     'sintegrator.distributedpath.directglossy': 'true',
  1851     'sintegrator.distributedpath.strategy': 'auto',
  1852     'sintegrator.distributedpath.specularrefractdepth': 5,
  1853 
  1854     'pixelfilter.type': 'mitchell',
  1855     'pixelfilter.mitchell.sharp': 0.333, 
  1856     'pixelfilter.mitchell.xwidth': 2.0, 
  1857     'pixelfilter.mitchell.ywidth': 2.0, 
  1858     'pixelfilter.mitchell.optmode': "slider" }
  1859 
  1860     presets['E Anim - Distributed/GI very high Q'] =  {
  1861     'film.displayinterval': 8,
  1862     'haltspp': 1,
  1863     'halttime': 0,
  1864     'useparamkeys': 'false',
  1865     'sampler.showadvanced': 'false',
  1866     'sintegrator.showadvanced': 'false',
  1867     'pixelfilter.showadvanced': 'false',
  1868 
  1869     'sampler.type': 'lowdiscrepancy',
  1870     'sampler.lowdisc.pixelsamples': 512,
  1871     'sampler.lowdisc.pixelsampler': 'hilbert',
  1872 
  1873     'sintegrator.type': 'distributedpath',
  1874     'sintegrator.distributedpath.causticsonglossy': 'true',
  1875     'sintegrator.distributedpath.diffuserefractdepth': 5,
  1876     'sintegrator.distributedpath.indirectglossy': 'true',
  1877     'sintegrator.distributedpath.directsamples': 1,
  1878     'sintegrator.distributedpath.diffuserefractsamples': 1,
  1879     'sintegrator.distributedpath.glossyreflectdepth': 2,
  1880     'sintegrator.distributedpath.causticsondiffuse': 'false',
  1881     'sintegrator.distributedpath.directsampleall': 'true',
  1882     'sintegrator.distributedpath.indirectdiffuse': 'true',
  1883     'sintegrator.distributedpath.specularreflectdepth': 3,
  1884     'sintegrator.distributedpath.diffusereflectsamples': 1,
  1885     'sintegrator.distributedpath.glossyreflectsamples': 1,
  1886     'sintegrator.distributedpath.glossyrefractdepth': 5,
  1887     'sintegrator.distributedpath.diffusereflectdepth': '2',
  1888     'sintegrator.distributedpath.indirectsamples': 1,
  1889     'sintegrator.distributedpath.indirectsampleall': 'false',
  1890     'sintegrator.distributedpath.glossyrefractsamples': 1,
  1891     'sintegrator.distributedpath.directdiffuse': 'true',
  1892     'sintegrator.distributedpath.directglossy': 'true',
  1893     'sintegrator.distributedpath.strategy': 'auto',
  1894     'sintegrator.distributedpath.specularrefractdepth': 5,
  1895 
  1896     'pixelfilter.type': 'mitchell',
  1897     'pixelfilter.mitchell.sharp': 0.333, 
  1898     'pixelfilter.mitchell.xwidth': 2.0, 
  1899     'pixelfilter.mitchell.ywidth': 2.0, 
  1900     'pixelfilter.mitchell.optmode': "slider" }
  1901 
  1902     return presets
  1903 
  1904 def getMaterialPresets():
  1905     return getPresets('luxblend_materials')
  1906 
  1907 def savePreset(key, name, d):
  1908     try:
  1909         presets = getPresets(key)
  1910         if d:
  1911             presets[name] = d.copy()
  1912         else:
  1913             del presets[name]
  1914         Blender.Registry.SetKey(key, presets, True)
  1915     except: pass    
  1916 def saveScenePreset(name, d):
  1917     try:
  1918         for n in presetsExclude:
  1919             try: del d[n]
  1920             except: pass
  1921         savePreset('luxblend_presets', name, d)
  1922     except: pass
  1923 def saveMaterialPreset(name, d):
  1924     try:
  1925         for n in presetsExclude:
  1926             try: del d[n]
  1927             except: pass
  1928         savePreset('luxblend_materials', name, d)
  1929     except: pass
  1930 
  1931 
  1932 # **************************************************
  1933 
  1934 
  1935 
  1936 
  1937 
  1938 usedproperties = {} # global variable to collect used properties for storing presets
  1939 usedpropertiesfilterobj = None # assign a object to only collect the properties that are assigned to this object
  1940 
  1941 # class to access properties (for lux settings)
  1942 class luxProp:
  1943     def __init__(self, obj, name, default):
  1944         self.obj = obj
  1945         self.name = name
  1946 #        if len(name)>31: print("Warning: property-name \"%s\" has more than 31 chars."%(name))
  1947         self.hashmode = len(name)>31   # activate hash mode for keynames longer 31 chars (limited by blenders ID-prop)
  1948         self.hashname = "__hash:%x"%(name.__hash__())
  1949         self.default = default
  1950     def parseassignment(self, s, name):
  1951         l = s.split(" = ")
  1952         if l[0] != name: print("Warning: property-name \"%s\" has hash-collide with \"%s\"."%(name, l[0]))
  1953         return l[1]
  1954     def createassignment(self, name, value):
  1955         return "%s = %s"%(name, value)
  1956     def get(self):
  1957         global usedproperties, usedpropertiesfilterobj, luxdefaults
  1958         if self.obj:
  1959             try:
  1960                 value = self.obj.properties['luxblend'][self.name]
  1961                 if not(usedpropertiesfilterobj) or (usedpropertiesfilterobj == self.obj):
  1962                     usedproperties[self.name] = value
  1963                 return value
  1964             except KeyError:
  1965                 try:
  1966                     value = self.parseassignment(self.obj.properties['luxblend'][self.hashname], self.name)
  1967                     if not(usedpropertiesfilterobj) or (usedpropertiesfilterobj == self.obj):
  1968                         usedproperties[self.name] = value
  1969                     return value
  1970                 except KeyError:
  1971                     if self.obj.__class__.__name__ == "Scene": # luxdefaults only for global setting
  1972                         try:
  1973                             value = luxdefaults[self.name]
  1974                             if not(usedpropertiesfilterobj) or (usedpropertiesfilterobj == self.obj):
  1975                                 usedproperties[self.name] = value
  1976                             return value
  1977                         except KeyError:
  1978                             if not(usedpropertiesfilterobj) or (usedpropertiesfilterobj == self.obj):
  1979                                 usedproperties[self.name] = self.default
  1980                             return self.default
  1981                     if not(usedpropertiesfilterobj) or (usedpropertiesfilterobj == self.obj):
  1982                         usedproperties[self.name] = self.default
  1983                     return self.default
  1984         return None
  1985     def getobj(self):
  1986         if self.obj:
  1987             return self.obj
  1988         else:
  1989             return None
  1990     def getname(self):
  1991         if self.name:
  1992             return self.name
  1993         else:
  1994             return None
  1995     def set(self, value):
  1996         global newluxdefaults
  1997         if self.obj:
  1998             if self.hashmode: n, v = self.hashname, self.createassignment(self.name, value)
  1999             else: n, v = self.name, value
  2000             if value is not None:
  2001                 try: self.obj.properties['luxblend'][n] = v
  2002                 except (KeyError, TypeError):
  2003                     self.obj.properties['luxblend'] = {}
  2004                     self.obj.properties['luxblend'][n] = v
  2005             else:
  2006                 try: del self.obj.properties['luxblend'][n]
  2007                 except:    pass
  2008             if self.obj.__class__.__name__ == "Scene": # luxdefaults only for global setting
  2009                 # value has changed, so this are user settings, remove preset reference
  2010                 if not(self.name in defaultsExclude):
  2011                     newluxdefaults[self.name] = value
  2012                     try: self.obj.properties['luxblend']['preset']=""
  2013                     except: pass
  2014     def delete(self):
  2015         if self.obj:
  2016             try: del self.obj.properties['luxblend'][self.name]
  2017             except:    pass
  2018             try: del self.obj.properties['luxblend'][self.hashname]
  2019             except:    pass
  2020     def getFloat(self):
  2021         v = self.get()
  2022         if type(v) == types.FloatType: return float(v)
  2023         try:
  2024             if type(v) == types.StringType: return float(v.split(" ")[0])
  2025         except: pass
  2026         v = self.default
  2027         if type(v) == types.FloatType: return float(v)
  2028         try:
  2029             if type(v) == types.StringType: return float(v.split(" ")[0])
  2030         except: pass
  2031         return 0.0
  2032     def getInt(self):
  2033         try: return int(self.get())
  2034         except: return int(self.default)
  2035     def getRGB(self):
  2036         return self.getVector()
  2037     def getVector(self):
  2038         v = self.get()
  2039         if type(v) in [types.FloatType, types.IntType]: return (float(v), float(v), float(v))
  2040         l = None
  2041         try:
  2042             if type(v) == types.StringType: l = self.get().split(" ")
  2043         except: pass
  2044         try:
  2045             if (l==None) or (len(l) != 3): l = self.default.split(" ")
  2046             return (float(l[0]), float(l[1]), float(l[2]))
  2047         except AttributeError:
  2048             return (float(l[0]), float(l[0]), float(l[0]))
  2049         
  2050     def getVectorStr(self):
  2051         return "%f %f %f"%self.getVector()
  2052     def isFloat(self):
  2053         return type(self.get()) == types.FloatType
  2054     def getRGC(self):
  2055         col = self.getRGB()
  2056         return "%f %f %f"%(rg(col[0]), rg(col[1]),rg(col[2]))
  2057     def setRGB(self, value):
  2058         self.set("%f %f %f"%(value[0], value[1], value[2]))
  2059     def setVector(self, value):
  2060         self.set("%f %f %f"%(value[0], value[1], value[2]))
  2061 
  2062 
  2063 # class to access blender attributes (for lux settings)
  2064 class luxAttr:
  2065     def __init__(self, obj, name):
  2066         self.obj = obj
  2067         self.name = name
  2068     def get(self):
  2069         if self.obj:
  2070             return getattr(self.obj, self.name)
  2071         else:
  2072             return None
  2073     def getFloat(self):
  2074         return float(self.get())
  2075     def getInt(self):
  2076         return int(self.get())
  2077     def getobj(self):
  2078         if self.obj:
  2079             return self.obj
  2080         else:
  2081             return None
  2082     def getname(self):
  2083         if self.name:
  2084             return self.name
  2085         else:
  2086             return None
  2087     def set(self, value):
  2088         if self.obj:
  2089             setattr(self.obj, self.name, value)
  2090             Window.QRedrawAll()
  2091 
  2092 
  2093 # class for dynamic gui
  2094 class luxGui:
  2095     def __init__(self, y=200):
  2096         self.x = 110 # left start position after captions
  2097         self.xmax = 110+2*(140+4)
  2098         self.y = y
  2099         self.w = 140 # default element width in pixels
  2100         self.h = 18  # default element height in pixels
  2101         self.hmax = 0
  2102         self.xgap = 4
  2103         self.ygap = 4
  2104         self.resethmax = False
  2105     def getRect(self, wu, hu):
  2106         w = int(self.w * wu + self.xgap * (wu-1))
  2107         h = int(self.h * hu + self.ygap * (hu-1))
  2108         if self.x + w > self.xmax: self.newline()
  2109         if self.resethmax: self.hmax = 0; self.resethmax = False
  2110         rect = [int(self.x), int(self.y-h), int(w), int(h)]
  2111         self.x += int(w + self.xgap)
  2112         if h+self.ygap > self.hmax: self.hmax = int(h+self.ygap)
  2113         return rect
  2114     def newline(self, title="", distance=0, level=0, icon=None, color=None):
  2115         self.x = 110
  2116         if not(self.resethmax): self.y -= int(self.hmax + distance)
  2117         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)
  2118         if icon!=None: drawIcon(icon, 2+level*10, self.y-16)
  2119         self.resethmax = True
  2120         if title!="":
  2121             self.getRect(0, 1)
  2122             BGL.glColor3f(0.9,0.9,0.9); BGL.glRasterPos2i(20+level*10,self.y-self.h+5); Draw.Text(title)
  2123     
  2124 def luxHelp(name, lux, caption, hint, gui, width=1.0):
  2125     if gui:
  2126         r = gui.getRect(width, 1)
  2127         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)]))
  2128         drawIcon(icon_help, r[0], r[1])
  2129 
  2130     return "\n   \"bool %s\" [\"%s\"]"%(name, lux.get())
  2131 
  2132 # lux parameter types
  2133 def luxOption(name, lux, options, caption, hint, gui, width=1.0):
  2134     if gui:
  2135         menustr = caption+": %t"
  2136         for i, v in enumerate(options): menustr = "%s %%x%d|%s"%(v, i, menustr)
  2137         try:
  2138             i = options.index(lux.get())
  2139         except ValueError:
  2140             try:
  2141                 lux.set(lux.default) # not found, so try default value
  2142                 i = options.index(lux.get())
  2143             except ValueError:
  2144                 print("value %s not found in options list"%(lux.get()))
  2145                 i = 0
  2146         r = gui.getRect(width, 1)
  2147         Draw.Menu(menustr, evtLuxGui, r[0], r[1], r[2], r[3], i, hint, lambda e,v: lux.set(options[v]))
  2148     return "\n   \"string %s\" [\"%s\"]"%(name, lux.get())
  2149 
  2150 def luxOptionRect(name, lux, options, caption, hint, gui, x, y, xx, yy):
  2151     if gui:
  2152         menustr = caption+": %t"
  2153         for i, v in enumerate(options): menustr = "%s %%x%d|%s"%(v, i, menustr)
  2154         try:
  2155             i = options.index(lux.get())
  2156         except ValueError:
  2157             try:
  2158                 lux.set(lux.default) # not found, so try default value
  2159                 i = options.index(lux.get())
  2160             except ValueError:
  2161                 print ("value %s not found in options list"%(lux.get()))
  2162                 i = 0
  2163         Draw.Menu(menustr, evtLuxGui, x, y, xx, yy, i, hint, lambda e,v: lux.set(options[v]))
  2164     return "\n   \"string %s\" [\"%s\"]"%(name, lux.get())
  2165 
  2166 def luxIdentifier(name, lux, options, caption, hint, gui, icon=None, width=1.0):
  2167     if gui: gui.newline(caption+":", 8, 0, icon, [0.75,0.5,0.25])
  2168     luxOption(name, lux, options, caption, hint, gui, width)
  2169     return "\n%s \"%s\""%(name, lux.get())
  2170 
  2171 def luxFloat(name, lux, min, max, caption, hint, gui, width=1.0, useslider=0):
  2172     if gui:
  2173         if (luxProp(Scene.GetCurrent(), "useparamkeys", "false").get()=="true"):
  2174             r = gui.getRect(width-0.12, 1)
  2175         else:
  2176             r = gui.getRect(width, 1)
  2177 
  2178         # Value
  2179         if(useslider==1):
  2180             Draw.Slider(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.getFloat(), min, max, 0, hint, lambda e,v: lux.set(v))
  2181         else:
  2182             Draw.Number(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.getFloat(), min, max, hint, lambda e,v: lux.set(v))
  2183         if (luxProp(Scene.GetCurrent(), "useparamkeys", "false").get()=="true"):
  2184             # IPO Curve
  2185             obj = lux.getobj()
  2186             keyname = lux.getname()
  2187     
  2188             useipo = luxProp(obj, keyname+".IPOuse", "false")
  2189             i = gui.getRect(0.12, 1)
  2190             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)]))
  2191             
  2192             if useipo.get() == "true":
  2193                 if gui: gui.newline(caption+"IPO:", 8, 0, None, [0.5,0.45,0.35])
  2194                 curve = luxProp(obj, keyname+".IPOCurveName", "") 
  2195                 if curve.get() == "":
  2196                     c = gui.getRect(2.0, 1)
  2197                 else:
  2198                     c = gui.getRect(1.1, 1)
  2199                 
  2200                 Draw.String("Ipo:", evtLuxGui, c[0], c[1], c[2], c[3], curve.get(), 250, "Set IPO Name", lambda e,v: curve.set(v))
  2201                 
  2202                 usemapping = luxProp(obj, keyname+".IPOmap", "false")
  2203                 icu_value = 0
  2204     
  2205                 # Apply IPO to value
  2206                 if curve.get() != "":
  2207                     try:
  2208                         ipoob = Blender.Ipo.Get(curve.get())
  2209                     except: 
  2210                         curve.set("")
  2211                     pass
  2212                     if curve.get() != "":
  2213                         names = list([x[0] for x in ipoob.curveConsts.items()])
  2214                         ipotype = luxProp(obj, keyname+".IPOCurveType", "OB_LOCZ")
  2215                         luxOption("ipocurve", ipotype, names, "IPO Curve", "Set IPO Curve", gui, 0.6)
  2216     
  2217                         icu = ipoob[eval("Blender.Ipo.%s" % (ipotype.get()))]
  2218                         icu_value = icu[Blender.Get('curframe')]
  2219                         if usemapping.get() == "false": # if true is set during mapping below
  2220                             lux.set(icu_value)    
  2221     
  2222                         # Mapping options
  2223                         m = gui.getRect(0.3, 1)
  2224                         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)]))
  2225                         if usemapping.get() == "true":
  2226                             if gui: gui.newline(caption+"IPO:", 8, 0, None, [0.5,0.45,0.35])
  2227                             fmin = luxProp(obj, keyname+".IPOCurvefmin", 0.0)
  2228                             luxFloatNoIPO("ipofmin", fmin, -100, 100, "fmin", "Map minimum value from Curve", gui, 0.5)
  2229                             fmax = luxProp(obj, keyname+".IPOCurvefmax", 1.0)
  2230                             luxFloatNoIPO("ipofmax", fmax, -100, 100, "fmax", "Map maximum value from Curve", gui, 0.5)
  2231                             tmin = luxProp(obj, keyname+".IPOCurvetmin", min)
  2232                             luxFloatNoIPO("ipotmin", tmin, min, max, "tmin", "Map miminum value to", gui, 0.5)
  2233                             tmax = luxProp(obj, keyname+".IPOCurvetmax", max)
  2234                             luxFloatNoIPO("ipotmax", tmax, min, max, "tmax", "Map maximum value to", gui, 0.5)
  2235     
  2236                             sval = (icu_value - fmin.getFloat()) / (fmax.getFloat() - fmin.getFloat())
  2237                             lux.set(tmin.getFloat() + (sval * (tmax.getFloat() - tmin.getFloat())))
  2238 
  2239                             # invert
  2240                             #v = gui.getRect(0.5, 1)
  2241                             #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)]))
  2242     else:
  2243         if (luxProp(Scene.GetCurrent(), "useparamkeys", "false").get()=="true"):
  2244             obj = lux.getobj()
  2245             keyname = lux.getname()
  2246             useipo = luxProp(obj, keyname+".IPOuse", "false")
  2247             if useipo.get() == "true":
  2248                 curve = luxProp(obj, keyname+".IPOCurveName", "") 
  2249                 try:
  2250                     ipoob = Blender.Ipo.Get(curve.get())
  2251                 except: 
  2252                     curve.set("")
  2253                 pass
  2254                 usemapping = luxProp(obj, keyname+".IPOmap", "false")
  2255                 icu_value = 0
  2256                 if curve.get() != "":
  2257                     names = list([x[0] for x in ipoob.curveConsts.items()])
  2258                     ipotype = luxProp(obj, keyname+".IPOCurveType", "OB_LOCZ")
  2259     
  2260                     icu = ipoob[eval("Blender.Ipo.%s" % (ipotype.get()))]
  2261                     icu_value = icu[Blender.Get('curframe')]
  2262                     if usemapping.get() == "false": # if true is set during mapping below
  2263                         lux.set(icu_value)    
  2264     
  2265                 if usemapping.get() == "true":
  2266                     if gui: gui.newline(caption+"IPO:", 8, 0, None, [0.5,0.45,0.35])
  2267                     fmin = luxProp(obj, keyname+".IPOCurvefmin", 0.0)
  2268                     fmax = luxProp(obj, keyname+".IPOCurvefmax", 1.0)
  2269                     tmin = luxProp(obj, keyname+".IPOCurvetmin", min)
  2270                     tmax = luxProp(obj, keyname+".IPOCurvetmax", max)
  2271                     sval = (icu_value - fmin.getFloat()) / (fmax.getFloat() - fmin.getFloat())
  2272                     lux.set(tmin.getFloat() + (sval * (tmax.getFloat() - tmin.getFloat())))
  2273 
  2274     return "\n   \"float %s\" [%f]"%(name, lux.getFloat())
  2275 
  2276 def luxFloatNoIPO(name, lux, min, max, caption, hint, gui, width=1.0, useslider=0):
  2277     if gui:
  2278         r = gui.getRect(width, 1)
  2279         if(useslider==1):
  2280             Draw.Slider(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.getFloat(), min, max, 0, hint, lambda e,v: lux.set(v))
  2281         else:
  2282             Draw.Number(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.getFloat(), min, max, hint, lambda e,v: lux.set(v))
  2283     return "\n   \"float %s\" [%f]"%(name, lux.getFloat())
  2284 
  2285 
  2286 
  2287 def luxInt(name, lux, min, max, caption, hint, gui, width=1.0):
  2288     if gui:
  2289         r = gui.getRect(width, 1)
  2290         Draw.Number(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.getInt(), min, max, hint, lambda e,v: lux.set(v))
  2291     return "\n   \"integer %s\" [%d]"%(name, lux.getInt())
  2292 
  2293 def luxBool(name, lux, caption, hint, gui, width=1.0):
  2294     if gui:
  2295         r = gui.getRect(width, 1)
  2296         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)]))
  2297     return "\n   \"bool %s\" [\"%s\"]"%(name, lux.get())
  2298 
  2299 def luxLabel(caption, gui):
  2300     if gui:
  2301         r = gui.getRect(2,1); BGL.glRasterPos2i(r[0],r[1]+5)
  2302         Draw.Text(caption)
  2303 
  2304 def luxCollapse(name, lux, caption, hint, gui, width=1.0):
  2305     if gui:
  2306         r = gui.getRect(width, 1)
  2307         if lux.get() == "true":
  2308             drawArrow(arrow_down, r[0]-22, r[1]-2)
  2309         else:
  2310             drawArrow(arrow_right, r[0]-22, r[1]-2)
  2311         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)]))
  2312     return "\n   \"bool %s\" [\"%s\"]"%(name, lux.get())
  2313 
  2314 def luxString(name, lux, caption, hint, gui, width=1.0):
  2315     if gui:
  2316         r = gui.getRect(width, 1)
  2317         Draw.String(caption+": ", evtLuxGui, r[0], r[1], r[2], r[3], lux.get(), 250, hint, lambda e,v: lux.set(v))
  2318     if lux.get()==lux.default: return ""
  2319     else: return "\n   \"string %s\" [\"%s\"]"%(name, luxstr(lux.get()))
  2320 
  2321 def luxFile(name, lux, caption, hint, gui, width=1.0):
  2322     if gui:
  2323         r = gui.getRect(width, 1)
  2324         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))
  2325         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()))
  2326     return "\n   \"string %s\" [\"%s\"]"%(name, luxstr(luxFilePath(lux.get())))
  2327 
  2328 def luxPath(name, lux, caption, hint, gui, width=1.0):
  2329     if gui:
  2330         r = gui.getRect(width, 1)
  2331         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))
  2332         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()))
  2333     return "\n   \"string %s\" [\"%s\"]"%(name, luxstr(lux.get()))
  2334 
  2335 def luxRGB(name, lux, max, caption, hint, gui, width=2.0):
  2336     if gui:
  2337         r = gui.getRect(width, 1)
  2338         scale = 1.0
  2339         rgb = lux.getRGB()
  2340         if max > 1.0:
  2341             for i in range(3):
  2342                 if rgb[i] > scale: scale = rgb[i]
  2343             rgb = (rgb[0]/scale, rgb[1]/scale, rgb[2]/scale)
  2344         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)))
  2345         w = int((r[2]-r[3])/3); m = max
  2346         if max > 1.0:
  2347             w = int((r[2]-r[3])/4); m = 1.0
  2348         drawR, drawG, drawB, drawS = Draw.Create(rgb[0]), Draw.Create(rgb[1]), Draw.Create(rgb[2]), Draw.Create(scale)
  2349         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)))
  2350         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)))
  2351         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)))
  2352         if max > 1.0:
  2353             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)))
  2354     if max <= 1.0:
  2355         return "\n   \"color %s\" [%s]"%(name, lux.getRGC())
  2356     return "\n   \"color %s\" [%s]"%(name, lux.get())
  2357 
  2358 def luxVector(name, lux, min, max, caption, hint, gui, width=2.0):
  2359     if gui:
  2360         r = gui.getRect(width, 1)
  2361         vec = lux.getVector()
  2362         w = int(r[2]/3)
  2363         drawX, drawY, drawZ = Draw.Create(vec[0]), Draw.Create(vec[1]), Draw.Create(vec[2])
  2364         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)))
  2365         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)))
  2366         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)))
  2367     return "\n   \"vector %s\" [%s]"%(name, lux.get())
  2368 
  2369 def luxVectorUniform(name, lux, min, max, caption, hint, gui, width=2.0):
  2370     def setUniform(lux, value):
  2371         if value: lux.set(lux.getFloat())
  2372         else: lux.setVector(lux.getVector())
  2373     if gui:
  2374         r = gui.getRect(width, 1)
  2375         vec = lux.getVector()
  2376         Draw.Toggle("U", evtLuxGui, r[0], r[1], gui.h, gui.h, lux.isFloat(), "uniform", lambda e,v: setUniform(lux, v))
  2377         if lux.isFloat():
  2378             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))
  2379         else:
  2380             w = int((r[2]-gui.h)/3)
  2381             drawX, drawY, drawZ = Draw.Create(vec[0]), Draw.Create(vec[1]), Draw.Create(vec[2])
  2382             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)))
  2383             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)))
  2384             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)))
  2385     return "\n   \"vector %s\" [%s]"%(name, lux.getVectorStr())
  2386 
  2387 
  2388 # lux individual identifiers
  2389 def luxCamera(cam, context, gui=None):
  2390     global icon_c_camera
  2391     str = ""
  2392     if cam:
  2393         camtype = luxProp(cam, "camera.type", "perspective")
  2394         # Radiance - remarked 'realistic' for v0.6 release
  2395         #str = luxIdentifier("Camera", camtype, ["perspective","orthographic","environment","realistic"], "CAMERA", "select camera type", gui, icon_c_camera)
  2396         str = luxIdentifier("Camera", camtype, ["perspective","orthographic","environment"], "CAMERA", "select camera type", gui, icon_c_camera)
  2397         scale = 1.0
  2398         if camtype.get() == "perspective":
  2399             if gui: gui.newline("  View:")
  2400             str += luxFloat("fov", luxAttr(cam, "angle"), 8.0, 170.0, "fov", "camera field-of-view angle", gui)
  2401             fl = luxAttr(cam, "lens")
  2402             if gui:
  2403                 luxFloat("lens", fl, 1.0, 250.0, "focallength", "camera focal length", gui)
  2404             
  2405         if camtype.get() == "orthographic" :
  2406             str += luxFloat("scale", luxAttr(cam, "scale"), 0.01, 1000.0, "scale", "orthographic camera scale", gui)
  2407             scale = cam.scale / 2
  2408         if camtype.get() == "realistic":
  2409             
  2410             if gui: gui.newline("  View:")
  2411             fov = luxAttr(cam, "angle")
  2412             str += luxFloat("fov", fov, 8.0, 170.0, "fov", "camera field-of-view angle", gui)
  2413             if gui: luxFloat("lens", luxAttr(cam, "lens"), 1.0, 250.0, "focallength", "camera focal length", gui)
  2414             
  2415             
  2416             if gui: gui.newline()
  2417             str += luxFile("specfile", luxProp(cam, "camera.realistic.specfile", ""), "spec-file", "", gui, 1.0)
  2418 #            if gui: gui.newline()
  2419 # auto calc        str += luxFloat("filmdistance", luxProp(cam, "camera.realistic.filmdistance", 70.0), 0.1, 1000.0, "film-dist", "film-distance [mm]", gui)
  2420             filmdiag = luxProp(cam, "camera.realistic.filmdiag", 35.0)
  2421             str += luxFloat("filmdiag", filmdiag, 0.1, 1000.0, "film-diag", "[mm]", gui)
  2422             if gui: gui.newline()
  2423             fstop = luxProp(cam, "camera.realistic.fstop", 1.0)
  2424             luxFloat("aperture_diameter", fstop, 0.1, 100.0, "f-stop", "", gui)
  2425             dofdist = luxAttr(cam, "dofDist")
  2426             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)
  2427             if gui:
  2428                 Draw.Button("S", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, "focus selected object", lambda e,v:setFocus("S"))
  2429                 Draw.Button("C", evtLuxGui, gui.x+gui.h, gui.y-gui.h, gui.h, gui.h, "focus cursor", lambda e,v:setFocus("C"))
  2430             focal = filmdiag.get()*0.001 / math.tan(fov.get() * math.pi / 360.0) / 2.0
  2431             print("calculated focal length: %f mm"%(focal * 1000.0))
  2432             aperture_diameter = focal / fstop.get()
  2433             print("calculated aperture diameter: %f mm"%(aperture_diameter * 1000.0))
  2434             str += "\n   \"float aperture_diameter\" [%f]"%(aperture_diameter*1000.0)
  2435             filmdistance = dofdist.get() * focal / (dofdist.get() - focal)
  2436             print("calculated film distance: %f mm"%(filmdistance * 1000.0))
  2437             str += "\n   \"float filmdistance\" [%f]"%(filmdistance*1000.0)
  2438 
  2439         # Clipping
  2440         useclip = luxProp(cam, "useclip", "false")
  2441         luxCollapse("useclip", useclip, "Near & Far Clipping", "Enable Camera near and far clipping options", gui, 2.0)
  2442         if(useclip.get() == "true"):
  2443             if gui: gui.newline("  Clipping:")
  2444             str += luxFloat("hither", luxAttr(cam, "clipStart"), 0.0, 100.0, "start", "near clip distance", gui)
  2445             str += luxFloat("yon", luxAttr(cam, "clipEnd"), 1.0, 10000.0, "end", "far clip distance", gui)
  2446 
  2447         # Depth of Field
  2448         usedof = luxProp(cam, "usedof", "false")
  2449         
  2450         if camtype.get() in ["perspective", "orthographic"]:
  2451             luxCollapse("usedof", usedof, "Depth of Field & Bokeh", "Enable Depth of Field & Aperture options", gui, 2.0)
  2452             
  2453             
  2454             if usedof.get() == "true":
  2455                 
  2456                 if gui: gui.newline("  DOF:")
  2457                 
  2458                 lr = luxProp(cam, "camera.lensradius", 0.01)
  2459                 fs = luxProp(cam, "camera.fstop", 2.8)
  2460                 
  2461                 if camtype.get() == "perspective":
  2462                     
  2463                     usefstop = luxProp(cam, "usefstop", "false")
  2464                     luxBool("usefstop", usefstop, "Use f/stop", "Use f/stop to define DOF effect", gui, 1.0)
  2465                     
  2466                     LR_SCALE = 1000.0       # lr in metres -> mm
  2467                     FL_SCALE = 1.0          # fl in mm -> mm
  2468                     
  2469                     def lr_2_fs(fl, lr):
  2470                         lr += 0.00000001
  2471                         return fl / ( 2.0 * lr )
  2472                     
  2473                     def fs_2_lr(fl, fs):
  2474                         return fl / ( 2.0 * fs )
  2475                     
  2476                     if usefstop.get() == 'true':
  2477                         lr.set(fs_2_lr(fl.get() * FL_SCALE, fs.get()) / LR_SCALE)
  2478                         luxFloat("fstop", fs, 0.9, 64.0, "fstop", "Defines the lens aperture.", gui)
  2479                         str += luxFloat("lensradius", lr, 0.0, 1.0, "", "", None)
  2480                     else:
  2481                         fs.set(lr_2_fs(fl.get() * FL_SCALE, lr.get() * LR_SCALE))
  2482                         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)
  2483                 else:
  2484                     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)
  2485                 
  2486                 focustype = luxProp(cam, "camera.focustype", "autofocus")
  2487                 luxOption("focustype", focustype, ["autofocus", "manual", "object"], "Focus Type", "Choose the focus behaviour", gui)
  2488                 
  2489     
  2490                 if focustype.get() == "autofocus":
  2491                     str += luxBool("autofocus",luxProp(cam, "camera.autofocus", "true"), "autofocus", "Enable automatic focus", gui)
  2492                 if focustype.get() == "object":
  2493                     objectfocus = luxProp(cam, "camera.objectfocus", "")
  2494                     luxString("objectfocus", objectfocus, "object", "Always focus camera on named object", gui, 1.0)
  2495                     dofdist = luxAttr(cam, "dofDist")
  2496                     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)
  2497                     if objectfocus.get() != "":
  2498                         try:
  2499                             setFocus(objectfocus.get())
  2500                         except:
  2501                             luxProp(cam, "camera.objectfocus", "").set("")
  2502                             Draw.PupMenu("WARNING: focus-object does not match existing object-name")
  2503                             if LuxIsGUI: Draw.Redraw()
  2504                                                                   
  2505                 if focustype.get() == "manual":
  2506                     dofdist = luxAttr(cam, "dofDist")
  2507                     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)
  2508                     if gui:
  2509                         Draw.Button("S", evtLuxGui, gui.x, gui.y-gui.h, gui.h, gui.h, "focus selected object", lambda e,v:setFocus("S"))
  2510                         Draw.Button("C", evtLuxGui, gui.x+gui.h, gui.y-gui.h, gui.h, gui.h, "focus cursor", lambda e,v:setFocus("C"))
  2511 
  2512         if camtype.get() == "perspective" and usedof.get() == "true":
  2513             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)
  2514             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)
  2515             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)
  2516 
  2517         useaspect = luxProp(cam, "useaspectratio", "false")
  2518         aspectratio = luxProp(cam, "ratio", 1.3333)
  2519         if camtype.get() in ["perspective", "orthographic"]:
  2520             useshift = luxProp(cam, "camera.useshift", "false")
  2521             luxCollapse("useshift", useshift, "Architectural (Lens Shift) & Aspect Ratio", "Enable Lens Shift and Aspect Ratio options", gui, 2.0)
  2522             if(useshift.get() == "true"):
  2523                 if gui: gui.newline("  Shift:")
  2524                 luxFloat("X", luxAttr(cam, "shiftX"), -2.0, 2.0, "X", "horizontal lens shift", gui)
  2525                 luxFloat("Y", luxAttr(cam, "shiftY"), -2.0, 2.0, "Y", "vertical lens shift", gui)
  2526 
  2527                 if gui: gui.newline("  AspectRatio:")
  2528                 luxBool("useaspectratio", useaspect, "Custom", "Define a custom frame aspect ratio", gui)
  2529                 if useaspect.get() == "true":
  2530                     str += luxFloat("frameaspectratio", aspectratio, 0.0001, 3.0, "aspectratio", "Frame aspect ratio", gui)
  2531             if context:
  2532                 if useaspect.get() == "true":
  2533                     ratio = 1./aspectratio.get()
  2534                 else:
  2535                         ratio = float(context.sizeY)/float(context.sizeX)
  2536                 if ratio < 1.0:
  2537                     screenwindow = [(2*cam.shiftX-1)*scale, (2*cam.shiftX+1)*scale, (2*cam.shiftY-ratio)*scale, (2*cam.shiftY+ratio)*scale]
  2538                 else:
  2539                     screenwindow = [(2*cam.shiftX-1/ratio)*scale, (2*cam.shiftX+1/ratio)*scale, (2*cam.shiftY-1)*scale, (2*cam.shiftY+1)*scale]
  2540                 # render region option
  2541                 if context.borderRender:
  2542                     (x1,y1,x2,y2) = context.border
  2543                     screenwindow = [screenwindow[0]*(1-x1)+screenwindow[1]*x1, screenwindow[0]*(1-x2)+screenwindow[1]*x2,\
  2544                             screenwindow[2]*(1-y1)+screenwindow[3]*y1, screenwindow[2]*(1-y2)+screenwindow[3]*y2]
  2545                 str += "\n   \"float screenwindow\" [%f %f %f %f]"%(screenwindow[0], screenwindow[1], screenwindow[2], screenwindow[3])
  2546 
  2547         # Note - radiance - this is a work in progress
  2548         # Flash lamp option for perspective and ortho cams
  2549 #        if camtype.get() in ["perspective", "orthographic"]:
  2550 #            useflash = luxProp(cam, "useflash", "false")
  2551 #            luxBool("useflash", useflash, "Flash Lamp", "Enable Camera mounted flash lamp options", gui, 2.0)
  2552 
  2553         # Motion Blur Options (common to all cameras)
  2554         usemblur = luxProp(cam, "usemblur", "false")
  2555         luxCollapse("usemblur", usemblur, "Motion Blur", "Enable Motion Blur", gui, 2.0)
  2556         if(usemblur.get() == "true"):    
  2557             if gui: gui.newline("  Shutter:")
  2558             mblurpreset = luxProp(cam, "mblurpreset", "true")
  2559             luxBool("mblurpreset", mblurpreset, "Preset", "Enable use of Shutter Presets", gui, 0.4)
  2560             if(mblurpreset.get() == "true"):
  2561                 shutterpresets = ["full frame", "half frame", "quarter frame", "1/25", "1/30", "1/45", "1/60", "1/85", "1/125", "1/250", "1/500"]        
  2562                 shutterpreset = luxProp(cam, "camera.shutterspeedpreset", "full frame")
  2563                 luxOption("shutterpreset", shutterpreset, shutterpresets, "shutterspeed", "Choose the Shutter speed preset.", gui, 1.0)
  2564 
  2565                 fpspresets = ["10 FPS", "12 FPS", "20 FPS", "25 FPS", "29.99 FPS", "30 FPS", "50 FPS", "60 FPS"]
  2566                 shutfps = luxProp(cam, "camera.shutfps", "25 FPS")
  2567                 luxOption("shutfps", shutfps, fpspresets, "@", "Choose the number of frames per second as the time base.", gui, 0.6)
  2568 
  2569                 sfps = shutfps.get()
  2570                 fps = 25
  2571                 if sfps == "10 FPS": fps = 10
  2572                 elif sfps == "12 FPS": fps = 12
  2573                 elif sfps == "20 FPS": fps = 20
  2574                 elif sfps == "25 FPS": fps = 25
  2575                 elif sfps == "29.99 FPS": fps = 29.99
  2576                 elif sfps == "30 FPS": fps = 30
  2577                 elif sfps == "50 FPS": fps = 50
  2578                 elif sfps == "60 FPS": fps = 60
  2579 
  2580                 spre = shutterpreset.get()
  2581                 open = 0.0
  2582                 close = 1.0
  2583                 if spre == "full frame": close = 1.0
  2584                 elif spre == "half frame": close = 0.5
  2585                 elif spre == "quarter frame": close = 0.25
  2586                 elif spre == "1/25": close = 1.0 / 25.0 * fps
  2587                 elif spre == "1/30": close = 1.0 / 30.0 * fps
  2588                 elif spre == "1/45": close = 1.0 / 45.0 * fps
  2589                 elif spre == "1/60": close = 1.0 / 60.0 * fps
  2590                 elif spre == "1/85": close = 1.0 / 85.0 * fps
  2591                 elif spre == "1/125": close = 1.0 / 125.0 * fps
  2592                 elif spre == "1/250": close = 1.0 / 250.0 * fps
  2593                 elif spre == "1/500": close = 1.0 / 500.0 * fps
  2594 
  2595                 str += "\n   \"float shutteropen\" [%f]\n   \"float shutterclose\" [%f] "%(open,close)
  2596 
  2597             else:
  2598                 str += luxFloat("shutteropen", luxProp(cam, "camera.shutteropen", 0.0), 0.0, 100.0, "open", "time in seconds when shutter opens", gui, 0.8)
  2599                 str += luxFloat("shutterclose", luxProp(cam, "camera.shutterclose", 1.0), 0.0, 100.0, "close", "time in seconds when shutter closes", gui, 0.8)
  2600 
  2601             str += luxOption("shutterdistribution", luxProp(cam, "camera.shutterdistribution", "uniform"), ["uniform", "gaussian"], "distribution", "Choose the shutter sampling distribution.", gui, 2.0)
  2602             objectmblur = luxProp(cam, "objectmblur", "true")
  2603             luxBool("objectmblur", objectmblur, "Object", "Enable Motion Blur for scene object motions", gui, 1.0)
  2604             cammblur = luxProp(cam, "cammblur", "true")
  2605             luxBool("cammblur", cammblur, "Camera", "Enable Motion Blur for Camera motion", gui, 1.0)
  2606     return str
  2607 
  2608 
  2609 def get_render_resolution(scn, gui = None):
  2610     context = scn.getRenderingContext()
  2611     scale = luxProp(scn, "film.scale", "100 %")
  2612     scale = int(scale.get()[:-1])
  2613     xr = luxAttr(context, "sizeX").get()*scale/100
  2614     yr = luxAttr(context, "sizeY").get()*scale/100
  2615     
  2616     return xr, yr
  2617 
  2618 def luxFilm(scn, gui=None):
  2619     str = ""
  2620     if scn:
  2621         filmtype = luxProp(scn, "film.type", "fleximage")
  2622         str = luxIdentifier("Film", filmtype, ["fleximage"], "FILM", "select film type", gui)
  2623         if filmtype.get() == "fleximage":
  2624             context = scn.getRenderingContext()
  2625             if context:
  2626                 if gui: gui.newline("  Resolution:")
  2627                 
  2628                 xr,yr = get_render_resolution(scn, gui)
  2629                 
  2630                 luxInt("xresolution", luxAttr(context, "sizeX"), 0, 8192, "X", "width of the render", gui, 0.666)
  2631                 luxInt("yresolution", luxAttr(context, "sizeY"), 0, 8192, "Y", "height of the render", gui, 0.666)
  2632                 scale = luxProp(scn, "film.scale", "100 %")
  2633                 luxOption("", scale, ["400 %", "200 %", "100 %", "75 %", "50 %", "25 %"], "scale", "scale resolution", gui, 0.666)
  2634                 
  2635                 # render region option
  2636                 if context.borderRender:
  2637                     (x1,y1,x2,y2) = context.border
  2638                     if (x1==x2) and (y1==y2): print("WARNING: empty render-region, use SHIFT-B to set render region in Blender.")
  2639                     str += "\n   \"integer xresolution\" [%d] \n   \"integer yresolution\" [%d]"%(xr*(x2-x1), yr*(y2-y1))
  2640                 else:
  2641                     str += "\n   \"integer xresolution\" [%d] \n   \"integer yresolution\" [%d]"%(xr, yr)
  2642 
  2643             if gui: gui.newline("  Halt:")
  2644             str += luxInt("haltspp", luxProp(scn, "haltspp", 0), 0, 32768, "haltspp", "Stop rendering after specified amount of samples per pixel / 0 = never halt", gui)
  2645             str += luxInt("halttime", luxProp(scn, "halttime", 0), 0, 86400, "halttime", "Stop rendering after specified number of seconds / 0 = never halt", gui)
  2646             palpha = luxProp(scn, "film.premultiplyalpha", "false")
  2647             str += luxBool("premultiplyalpha", palpha, "premultiplyalpha", "Pre multiply film alpha channel during normalization", gui)
  2648     
  2649             if gui: gui.newline("  Tonemap:")
  2650             tonemapkernel =    luxProp(scn, "film.tonemapkernel", "reinhard")
  2651             str += luxOption("tonemapkernel", tonemapkernel, ["reinhard", "linear", "contrast", "maxwhite"], "Tonemapping Kernel", "Select the tonemapping kernel to use", gui, 2.0)
  2652             if tonemapkernel.get() == "reinhard":
  2653                 autoywa = luxProp(scn, "film.reinhard.autoywa", "true")
  2654                 #str += luxBool("reinhard_autoywa", autoywa, "auto Ywa", "Automatically determine World Adaption Luminance", gui)
  2655                 if autoywa.get() == "false":
  2656                     str += luxFloat("reinhard_ywa", luxProp(scn, "film.reinhard.ywa", 0.1), 0.001, 1.0, "Ywa", "Display/World Adaption Luminance", gui)
  2657                 str += luxFloat("reinhard_prescale", luxProp(scn, "film.reinhard.prescale", 1.0), 0.0, 10.0, "preScale", "Image scale before tonemap operator", gui)
  2658                 str += luxFloat("reinhard_postscale", luxProp(scn, "film.reinhard.postscale", 1.2), 0.0, 10.0, "postScale", "Image scale after tonemap operator", gui)
  2659                 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)
  2660             elif tonemapkernel.get() == "linear":
  2661                 str += luxFloat("linear_sensitivity", luxProp(scn, "film.linear.sensitivity", 50.0), 0.0, 1000.0, "sensitivity", "Adaption/Sensitivity", gui)
  2662                 str += luxFloat("linear_exposure", luxProp(scn, "film.linear.exposure", 1.0), 0.001, 1.0, "exposure", "Exposure duration in seconds", gui)
  2663                 str += luxFloat("linear_fstop", luxProp(scn, "film.linear.fstop", 2.8), 0.1, 64.0, "Fstop", "F-Stop", gui)
  2664                 str += luxFloat("linear_gamma", luxProp(scn, "film.linear.gamma", 1.0), 0.0, 8.0, "gamma", "Tonemap operator gamma correction", gui)
  2665             elif tonemapkernel.get() == "contrast":
  2666                 str += luxFloat("contrast_ywa", luxProp(scn, "film.contrast.ywa", 0.1), 0.001, 1.0, "Ywa", "Display/World Adaption Luminance", gui)
  2667 
  2668             if gui: gui.newline("  Display:")
  2669             str += luxInt("displayinterval", luxProp(scn, "film.displayinterval", 12), 4, 3600, "interval", "Set display Interval (seconds)", gui)
  2670             
  2671             if gui: gui.newline("  Write:")
  2672             str += luxInt("writeinterval", luxProp(scn, "film.writeinterval", 120), 12, 3600, "interval", "Set display Interval (seconds)", gui)
  2673 
  2674         # Image File Outputs
  2675 
  2676         # LDR clamping method
  2677         if gui: gui.newline("  Clamping:")
  2678         ldrclampmethod = luxProp(scn, "film.ldr_clamp_method", "lum")
  2679         str += luxOption("ldr_clamp_method", ldrclampmethod, ["lum", "hue", "cut"], "LDR clamping", "Method to clamp high luminance values for LDR output", gui, 0.5)
  2680         if gui: gui.newline()
  2681 
  2682         # OpenEXR Output
  2683         saveexr = luxProp(scn, "film.write_exr", "false")
  2684         str += luxCollapse("write_exr", saveexr, "OpenEXR Output", "Enable OpenEXR output", gui, 2.0)
  2685 
  2686         if saveexr.get() == "true":
  2687             if gui: gui.newline("  OpenEXR:")
  2688 
  2689             exrchannels = luxProp(scn, "film.write_exr_channels", "RGBA")
  2690             str += luxOption("write_exr_channels", exrchannels, ["Y", "YA", "RGB", "RGBA"], "Channels", "Select channels type to write", gui, 0.5)
  2691             exrres = luxProp(scn, "film.write_exr_halftype", "true")
  2692             str += luxBool("write_exr_halftype", exrres, "16bit Half", "Enable 16bit Half resolution output, otherwise 32bit float", gui, 0.5)
  2693             exrcompression = luxProp(scn, "film.write_exr_compression", "PIZ (lossless)")
  2694             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)
  2695 
  2696             exrimaging = luxProp(scn, "film.write_exr_imaging", "true")
  2697             str += luxBool("write_exr_applyimaging", exrimaging, "Apply Imaging/Tonemapping", "Apply Imaging and Tonemapping pipeline", gui, 1.2)
  2698         
  2699             if exrimaging.get()=="true":
  2700                 exrgamutclamp = luxProp(scn, "film.write_exr_gamutclamp", "true")
  2701                 str += luxBool("write_exr_gamutclamp", exrgamutclamp, "Gamut Clamp", "Clamp out of gamut (bright) pixel values", gui, 0.8)
  2702 
  2703             if gui: gui.newline()
  2704             # Zbuf output
  2705             exrZ = luxProp(scn, "film.write_exr_Z", "true")
  2706             str += luxBool("write_exr_ZBuf", exrZ, "ZBuf", "Enable Z Depth Buffer channel", gui, 0.8)
  2707             if exrZ.get() == "true":
  2708                 exrZNormalize = luxProp(scn, "film.write_exr_ZNorm", "None")
  2709                 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)
  2710 
  2711         # PNG Output
  2712         savepng = luxProp(scn, "film.write_png", "true")
  2713         str += luxCollapse("write_png", savepng, "PNG Output", "Enable PNG (Portable Network Graphics) output", gui, 2.0)
  2714 
  2715         if savepng.get() == "true":
  2716             if gui: gui.newline("  PNG:")
  2717             pngchannels = luxProp(scn, "film.write_png_channels", "RGB")
  2718             str += luxOption("write_png_channels", pngchannels, ["Y", "YA", "RGB", "RGBA"], "Channels", "Select channels type to write", gui, 0.5)
  2719             png16bit = luxProp(scn, "film.write_png_16bit", "false")
  2720             str += luxBool("write_png_16bit", png16bit, "16bit", "Enable 16bits per channel resolution PNG output", gui, 0.5)
  2721             pnggamutclamp = luxProp(scn, "film.write_png_gamutclamp", "true")
  2722             str += luxBool("write_png_gamutclamp", pnggamutclamp, "Gamut Clamp", "Clamp out of gamut (bright) pixel values", gui, 1.0)
  2723 
  2724         # Zbuf output
  2725         #pngZ = luxProp(scn, "film.write_png_ZBuf", "false")
  2726         #str += luxBool("write_png_ZBuf", pngZ, "ZBuf (Separate)", "Enable Z Depth Buffer channel", gui, 0.8)
  2727         #if pngZ.get() == "true":
  2728         #    pngZNormalize = luxProp(scn, "film.write_png_ZNorm", "Min/Max")
  2729         #    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)
  2730 
  2731         # TGA Output
  2732         savetga = luxProp(scn, "film.write_tga", "false")
  2733         str += luxCollapse("write_tga", savetga, "TGA Output", "Enable TGA output", gui, 2.0)
  2734 
  2735         if savetga.get() == "true":
  2736             if gui: gui.newline("  TGA:")
  2737             tgachannels = luxProp(scn, "film.write_tga_channels", "RGB")
  2738             str += luxOption("write_tga_channels", tgachannels, ["Y", "RGB", "RGBA"], "Channels", "Select channels type to write", gui, 0.5)
  2739             tgagamutclamp = luxProp(scn, "film.write_tga_gamutclamp", "true")
  2740             str += luxBool("write_tga_gamutclamp", tgagamutclamp, "Gamut Clamp", "Clamp out of gamut (bright) pixel values", gui, 1.5)
  2741 
  2742         # Zbuf output
  2743         #tgaZ = luxProp(scn, "film.write_tga_ZBuf", "false")
  2744         #str += luxBool("write_tga_ZBuf", tgaZ, "ZBuf (Separate)", "Enable Z Depth Buffer channel", gui, 0.8)
  2745         #if tgaZ.get() == "true":
  2746         #    tgaZNormalize = luxProp(scn, "film.write_tga_ZNorm", "Min/Max")
  2747         #    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)
  2748 
  2749 
  2750         # override output image dir in case of command line batch mode 
  2751         overrideop = luxProp(scn, "overrideoutputpath", "")
  2752         if overrideop.get() != "":
  2753             filebase = os.path.splitext(os.path.basename(Blender.Get('filename')))[0]
  2754             filename = overrideop.get() + "/" + filebase + "-%05d" %  (Blender.Get('curframe'))
  2755             str += "\n   \"string filename\" [\"%s\"]"%(filename)
  2756         else:
  2757             fn = luxProp(scn, "filename", "default-%05d" %  (Blender.Get('curframe')))
  2758             str += luxString("filename", fn, "File name", "save file name", None)
  2759     
  2760         if gui: gui.newline("  Resume:")
  2761         resumeflm = luxProp(scn, "film.write_resume_flm", "false")
  2762         str += luxBool("write_resume_flm", resumeflm, "Write/Use FLM", "Write a resume fleximage .flm file, or resume rendering if it already exists", gui)
  2763         restartflm = luxProp(scn, "film.restart_resume_flm", "true")
  2764         str += luxBool("restart_resume_flm", restartflm, "Restart/Erase", "Restart with a black flm, even it a previous flm exists", gui)
  2765         if gui: gui.newline("  Reject:")
  2766         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)
  2767         debugmode = luxProp(scn, "film.debug", "false")
  2768         str += luxBool("debug", debugmode, "debug", "Turn on debug reporting and switch off reject", gui)
  2769     
  2770         # Colorspace
  2771         if gui: gui.newline("  Colorspace:")
  2772     
  2773         cspaceusepreset = luxProp(scn, "film.colorspaceusepreset", "true")
  2774         luxBool("colorspaceusepreset", cspaceusepreset, "Preset", "Select from a list of predefined presets", gui, 0.4)
  2775     
  2776         # Default values for 'sRGB - HDTV (ITU-R BT.709-5)'
  2777         cspacewhiteX = luxProp(scn, "film.cspacewhiteX", 0.314275)
  2778         cspacewhiteY = luxProp(scn, "film.cspacewhiteY", 0.329411)
  2779         cspaceredX = luxProp(scn, "film.cspaceredX", 0.63)
  2780         cspaceredY = luxProp(scn, "film.cspaceredY", 0.34)
  2781         cspacegreenX = luxProp(scn, "film.cspacegreenX", 0.31)
  2782         cspacegreenY = luxProp(scn, "film.cspacegreenY", 0.595)
  2783         cspaceblueX = luxProp(scn, "film.cspaceblueX", 0.155)
  2784         cspaceblueY = luxProp(scn, "film.cspaceblueY", 0.07)
  2785         gamma = luxProp(scn, "film.gamma", 2.2)
  2786     
  2787         if(cspaceusepreset.get() == "true"):
  2788             # preset controls
  2789             cspace = luxProp(scn, "film.colorspace", "sRGB - HDTV (ITU-R BT.709-5)")
  2790             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"]
  2791             luxOption("colorspace", cspace, cspaces, "Colorspace", "select output working colorspace", gui, 1.6)
  2792     
  2793             if cspace.get()=="ROMM RGB":
  2794                 cspacewhiteX.set(0.346); cspacewhiteY.set(0.359) # D50
  2795                 cspaceredX.set(0.7347); cspaceredY.set(0.2653)
  2796                 cspacegreenX.set(0.1596); cspacegreenY.set(0.8404)
  2797                 cspaceblueX.set(0.0366); cspaceblueY.set(0.0001)
  2798             elif cspace.get()=="Adobe RGB 98":
  2799                 cspacewhiteX.set(0.313); cspacewhiteY.set(0.329) # D65
  2800                 cspaceredX.set(0.64); cspaceredY.set(0.34)
  2801                 cspacegreenX.set(0.21); cspacegreenY.set(0.71)
  2802                 cspaceblueX.set(0.15); cspaceblueY.set(0.06)
  2803             elif cspace.get()=="Apple RGB":
  2804                 cspacewhiteX.set(0.313); cspacewhiteY.set(0.329) # D65
  2805                 cspaceredX.set(0.625); cspaceredY.set(0.34)
  2806                 cspacegreenX.set(0.28); cspacegreenY.set(0.595)
  2807                 cspaceblueX.set(0.155); cspaceblueY.set(0.07)
  2808             elif cspace.get()=="NTSC (FCC 1953, ITU-R BT.470-2 System M)":
  2809                 cspacewhiteX.set(0.310); cspacewhiteY.set(0.316) # C
  2810                 cspaceredX.set(0.67); cspaceredY.set(0.33)
  2811                 cspacegreenX.set(0.21); cspacegreenY.set(0.71)
  2812                 cspaceblueX.set(0.14); cspaceblueY.set(0.08)
  2813             elif cspace.get()=="NTSC (1979) (SMPTE C, SMPTE-RP 145)":
  2814                 cspacewhiteX.set(0.313); cspacewhiteY.set(0.329) # D65
  2815                 cspaceredX.set(0.63); cspaceredY.set(0.34)
  2816                 cspacegreenX.set(0.31); cspacegreenY.set(0.595)
  2817                 cspaceblueX.set(0.155); cspaceblueY.set(0.07)
  2818             elif cspace.get()=="PAL/SECAM (EBU 3213, ITU-R BT.470-6)":
  2819                 cspacewhiteX.set(0.313); cspacewhiteY.set(0.329) # D65
  2820                 cspaceredX.set(0.64); cspaceredY.set(0.33)
  2821                 cspacegreenX.set(0.29); cspacegreenY.set(0.60)
  2822                 cspaceblueX.set(0.15); cspaceblueY.set(0.06)
  2823             elif cspace.get()=="CIE (1931) E":
  2824                 cspacewhiteX.set(0.333); cspacewhiteY.set(0.333) # E
  2825                 cspaceredX.set(0.7347); cspaceredY.set(0.2653)
  2826                 cspacegreenX.set(0.2738); cspacegreenY.set(0.7174)
  2827                 cspaceblueX.set(0.1666); cspaceblueY.set(0.0089)
  2828     
  2829             whitepointusecspace = luxProp(scn, "film.whitepointusecolorspace", "true")
  2830             luxBool("whitepointusecolorspace", whitepointusecspace, "Colorspace Whitepoint", "Use default whitepoint for selected colorspace", gui, 1.0)
  2831             gammausecspace = luxProp(scn, "film.gammausecolorspace", "true")
  2832             luxBool("gammausecolorspace", gammausecspace, "Colorspace Gamma", "Use default output gamma for selected colorspace", gui, 1.0)
  2833     
  2834             if(whitepointusecspace.get() == "false"):
  2835                 if gui: gui.newline("  Whitepoint:")
  2836                 whitepointusepreset = luxProp(scn, "film.whitepointusepreset", "true")
  2837                 luxBool("whitepointusepreset", whitepointusepreset, "Preset", "Select from a list of predefined presets", gui, 0.4)
  2838     
  2839                 if(whitepointusepreset.get() == "true"):
  2840                     whitepointpresets = ["E", "D50", "D55", "D65", "D75", "A", "B", "C", "9300", "F2", "F7", "F11"]
  2841                     whitepointpreset = luxProp(scn, "film.whitepointpreset", "D65")
  2842                     luxOption("whitepointpreset", whitepointpreset, whitepointpresets, "  PRESET", "select Whitepoint preset", gui, 1.6)
  2843     
  2844                     if whitepointpreset.get()=="E": cspacewhiteX.set(0.333); cspacewhiteY.set(0.333)
  2845                     elif whitepointpreset.get()=="D50": cspacewhiteX.set(0.346); cspacewhiteY.set(0.359)
  2846                     elif whitepointpreset.get()=="D55": cspacewhiteX.set(0.332); cspacewhiteY.set(0.347)
  2847                     elif whitepointpreset.get()=="D65": cspacewhiteX.set(0.313); cspacewhiteY.set(0.329)
  2848                     elif whitepointpreset.get()=="D75": cspacewhiteX.set(0.299); cspacewhiteY.set(0.315)
  2849                     elif whitepointpreset.get()=="A": cspacewhiteX.set(0.448); cspacewhiteY.set(0.407)
  2850                     elif whitepointpreset.get()=="B": cspacewhiteX.set(0.348); cspacewhiteY.set(0.352)
  2851                     elif whitepointpreset.get()=="C": cspacewhiteX.set(0.310); cspacewhiteY.set(0.316)
  2852                     elif whitepointpreset.get()=="9300": cspacewhiteX.set(0.285); cspacewhiteY.set(0.293)
  2853                     elif whitepointpreset.get()=="F2": cspacewhiteX.set(0.372); cspacewhiteY.set(0.375)
  2854                     elif whitepointpreset.get()=="F7": cspacewhiteX.set(0.313); cspacewhiteY.set(0.329)
  2855                     elif whitepointpreset.get()=="F11": cspacewhiteX.set(0.381); cspacewhiteY.set(0.377)
  2856                 else:
  2857                     luxFloat("white X", cspacewhiteX, 0.0, 1.0, "white X", "Whitepoint X weight", gui, 0.8)
  2858                     luxFloat("white Y", cspacewhiteY, 0.0, 1.0, "white Y", "Whitepoint Y weight", gui, 0.8)
  2859     
  2860             if(gammausecspace.get() == "false"):
  2861                 if gui: gui.newline("  Gamma:")
  2862                 luxFloat("gamma", gamma, 0.1, 6.0, "gamma", "Output and RGC Gamma", gui, 2.0)
  2863         else:
  2864             # manual controls
  2865             luxFloat("white X", cspacewhiteX, 0.0, 1.0, "white X", "Whitepoint X weight", gui, 0.8)
  2866             luxFloat("white Y", cspacewhiteY, 0.0, 1.0, "white Y", "Whitepoint Y weight", gui, 0.8)
  2867             luxFloat("red X", cspaceredX, 0.0, 1.0, "red X", "Red component X weight", gui, 1.0)
  2868             luxFloat("red Y", cspaceredY, 0.0, 1.0, "red Y", "Red component Y weight", gui, 1.0)
  2869             luxFloat("green X", cspacegreenX, 0.0, 1.0, "green X", "Green component X weight", gui, 1.0)
  2870             luxFloat("green Y", cspacegreenY, 0.0, 1.0, "green Y", "Green component Y weight", gui, 1.0)
  2871             luxFloat("blue X", cspaceblueX, 0.0, 1.0, "blue X", "Blue component X weight", gui, 1.0)
  2872             luxFloat("blue Y", cspaceblueY, 0.0, 1.0, "blue Y", "Blue component Y weight", gui, 1.0)
  2873             if gui: gui.newline("  Gamma:")
  2874             luxFloat("gamma", gamma, 0.1, 6.0, "gamma", "Output and RGC Gamma", gui, 2.0)
  2875             
  2876         str += "\n   \"float colorspace_white\" [%f %f]"%(cspacewhiteX.get(), cspacewhiteY.get())
  2877         str += "\n   \"float colorspace_red\" [%f %f]"%(cspaceredX.get(), cspaceredY.get())
  2878         str += "\n   \"float colorspace_green\" [%f %f]"%(cspacegreenX.get(), cspacegreenY.get())
  2879         str += "\n   \"float colorspace_blue\" [%f %f]"%(cspaceblueX.get(), cspaceblueY.get())
  2880         str += "\n   \"float gamma\" [%f]"%(gamma.get())
  2881 
  2882     return str
  2883 
  2884 
  2885 def luxPixelFilter(scn, gui=None):
  2886     global icon_c_filter
  2887     str = ""
  2888     if scn:
  2889         filtertype = luxProp(scn, "pixelfilter.type", "mitchell")
  2890         str = luxIdentifier("PixelFilter", filtertype, ["box", "gaussian", "mitchell", "sinc", "triangle"], "FILTER", "select pixel filter type", gui, icon_c_filter)
  2891 
  2892         # Advanced toggle
  2893         parammodeadvanced = luxProp(scn, "parammodeadvanced", "false")
  2894         showadvanced = luxProp(scn, "pixelfilter.showadvanced", parammodeadvanced.get())
  2895         luxBool("advanced", showadvanced, "Advanced", "Show advanced options", gui, 0.6)
  2896         # Help toggle
  2897         showhelp = luxProp(scn, "pixelfilter.showhelp", "false")
  2898         luxHelp("help", showhelp, "Help", "Show Help Information", gui, 0.4)
  2899 
  2900         if filtertype.get() == "box":
  2901             if showadvanced.get()=="true":
  2902                 # Advanced parameters
  2903                 if gui: gui.newline()
  2904                 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)
  2905                 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)
  2906         if filtertype.get() == "gaussian":
  2907             if showadvanced.get()=="true":
  2908                 # Advanced parameters
  2909                 if gui: gui.newline()
  2910                 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)
  2911                 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)
  2912                 if gui: gui.newline()
  2913                 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)
  2914         if filtertype.get() == "mitchell":
  2915             if showadvanced.get()=="false":
  2916                 # Default parameters
  2917                 if gui: gui.newline("", 8, 0, None, [0.4,0.4,0.4])
  2918                 slidval = luxProp(scn, "pixelfilter.mitchell.sharp", 0.25)
  2919                 luxFloat("sharpness", slidval, 0.0, 1.0, "sharpness", "Specify amount between blurred (left) and sharp/ringed (right)", gui, 2.0, 1)
  2920                 # rule: B + 2*c = 1.0
  2921                 C = slidval.getFloat() * 0.5
  2922                 B = 1.0 - slidval.getFloat()
  2923                 str += "\n   \"float B\" [%f]"%(B)
  2924                 str += "\n   \"float C\" [%f]"%(C)
  2925 
  2926             if showadvanced.get()=="true":
  2927                 # Advanced parameters
  2928                 if gui: gui.newline()
  2929                 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)
  2930                 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)
  2931                 if gui: gui.newline()
  2932     
  2933                 optmode = luxProp(scn, "pixelfilter.mitchell.optmode", "slider")
  2934                 luxOption("optmode", optmode, ["slider", "preset", "manual"], "Mode", "Mode of configuration", gui, 0.5)
  2935     
  2936                 if(optmode.get() == "slider"):
  2937                     slidval = luxProp(scn, "pixelfilter.mitchell.sharp", 0.33)
  2938                     luxFloat("sharpness", slidval, 0.0, 1.0, "sharpness", "Specify amount between blurred (left) and sharp/ringed (right)", gui, 1.5, 1)
  2939                     # rule: B + 2*c = 1.0
  2940                     C = slidval.getFloat() * 0.5
  2941                     B = 1.0 - slidval.getFloat()
  2942                     str += "\n   \"float B\" [%f]"%(B)
  2943                     str += "\n   \"float C\" [%f]"%(C)
  2944                 elif(optmode.get() == "preset"):
  2945                     print("not implemented")
  2946                 else:
  2947                     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)
  2948                     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)
  2949 
  2950         if filtertype.get() == "sinc":
  2951             if showadvanced.get()=="true":
  2952                 # Advanced parameters
  2953                 if gui: gui.newline()
  2954                 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)
  2955                 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)
  2956                 if gui: gui.newline()
  2957                 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)
  2958         if filtertype.get() == "triangle":
  2959             if showadvanced.get()=="true":
  2960                 # Advanced parameters
  2961                 if gui: gui.newline()
  2962                 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)
  2963                 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)
  2964     return str            
  2965 
  2966 def luxSampler(scn, gui=None):
  2967     global icon_c_sampler, icon_help
  2968     str = ""
  2969     if scn:
  2970         samplertype = luxProp(scn, "sampler.type", "metropolis")
  2971         str = luxIdentifier("Sampler", samplertype, ["metropolis", "erpt", "lowdiscrepancy", "random"], "SAMPLER", "select sampler type", gui, icon_c_sampler)
  2972 
  2973         # Advanced toggle
  2974         parammodeadvanced = luxProp(scn, "parammodeadvanced", "false")
  2975         showadvanced = luxProp(scn, "sampler.showadvanced", parammodeadvanced.get())
  2976         luxBool("advanced", showadvanced, "Advanced", "Show advanced options", gui, 0.6)
  2977         # Help toggle
  2978         showhelp = luxProp(scn, "sampler.showhelp", "false")
  2979         luxHelp("help", showhelp, "Help", "Show Help Information", gui, 0.4)
  2980 
  2981         if samplertype.get() == "metropolis":
  2982             if showadvanced.get()=="false":
  2983                 # Default parameters
  2984                 if gui: gui.newline("  Mutation:", 8, 0, None, [0.4,0.4,0.4])
  2985                 strength = luxProp(scn, "sampler.metro.strength", 0.6)
  2986                 luxFloat("strength", strength, 0.0, 1.0, "strength", "Mutation Strength (lmprob = 1.0-strength)", gui, 2.0, 1)
  2987                 v = 1.0 - strength.get()
  2988                 str += "\n   \"float largemutationprob\" [%f]"%v
  2989             if showadvanced.get()=="true":
  2990                 # Advanced parameters
  2991                 if gui: gui.newline("  Mutation:")
  2992                 str += luxFloat("largemutationprob", luxProp(scn, "sampler.metro.lmprob", 0.4), 0.0, 1.0, "LM.prob.", "Probability of generating a large sample (mutation)", gui)
  2993                 str += luxInt("maxconsecrejects", luxProp(scn, "sampler.metro.maxrejects", 512), 0, 32768, "max.rejects", "number of consecutive rejects before a new mutation is forced", gui)
  2994                 if gui: gui.newline("  Screen:")
  2995                 #str += luxInt("initsamples", luxProp(scn, "sampler.metro.initsamples", 262144), 1, 1000000, "initsamples", "", gui)
  2996                 str += luxBool("usevariance",luxProp(scn, "sampler.metro.usevariance", "false"), "usevariance", "Accept based on variance", gui, 1.0)
  2997 
  2998             if showhelp.get()=="true":
  2999                 if gui: gui.newline("  Description:", 8, 0, icon_help, [0.4,0.5,0.56])
  3000                 r = gui.getRect(2,1); BGL.glRasterPos2i(r[0],r[1]+5) 
  3001                 Draw.Text("A Metropolis-Hastings mutating sampler which implements MLT", 'small')    
  3002 
  3003         if samplertype.get() == "erpt":
  3004             #str += luxInt("initsamples", luxProp(scn, "sampler.erpt.initsamples", 100000), 1, 1000000, "initsamples", "", gui)
  3005             if gui: gui.newline("  Mutation:")
  3006             str += luxInt("chainlength", luxProp(scn, "sampler.erpt.chainlength", 512), 1, 32768, "chainlength", "The number of mutations from a given seed", gui)
  3007             if gui: gui.newline()
  3008             str += luxInt("stratawidth", luxProp(scn, "sampler.erpt.stratawidth", 256), 1, 32768, "stratawidth", "The number of x/y strata for stratified sampling of seeds", gui)
  3009 
  3010         if samplertype.get() == "lowdiscrepancy":
  3011             if gui: gui.newline("  PixelSampler:")
  3012             str += luxOption("pixelsampler", luxProp(scn, "sampler.lowdisc.pixelsampler", "lowdiscrepancy"), ["linear", "tile", "random", "vegas","lowdiscrepancy","hilbert"], "pixel-sampler", "select pixel-sampler", gui)
  3013             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)
  3014 
  3015         if samplertype.get() == "random":
  3016             if gui: gui.newline("  PixelSampler:")
  3017             str += luxOption("pixelsampler", luxProp(scn, "sampler.random.pixelsampler", "vegas"), ["linear", "tile", "random", "vegas","lowdiscrepancy","hilbert"], "pixel-sampler", "select pixel-sampler", gui)
  3018             if gui: gui.newline()
  3019             str += luxInt("pixelsamples", luxProp(scn, "sampler.random.pixelsamples", 4), 1, 512, "pixelsamples", "Allows you to specify how many samples per pixel are computed", gui)
  3020     return str            
  3021 
  3022 def luxSurfaceIntegrator(scn, gui=None):
  3023     global icon_c_integrator
  3024     str = ""
  3025     if scn:
  3026         integratortype = luxProp(scn, "sintegrator.type", "bidirectional")
  3027         
  3028         str = luxIdentifier("SurfaceIntegrator", integratortype, ["directlighting", "path", "bidirectional", "exphotonmap", "distributedpath", "igi" ], "INTEGRATOR", "select surface integrator type", gui, icon_c_integrator)
  3029 
  3030         # Advanced toggle
  3031         parammodeadvanced = luxProp(scn, "parammodeadvanced", "false")
  3032         showadvanced = luxProp(scn, "sintegrator.showadvanced", parammodeadvanced.get())
  3033         luxBool("advanced", showadvanced, "Advanced", "Show advanced options", gui, 0.6)
  3034         # Help toggle
  3035         showhelp = luxProp(scn, "sintegrator.showhelp", "false")
  3036         luxHelp("help", showhelp, "Help", "Show Help Information", gui, 0.4)
  3037 
  3038         if integratortype.get() == "directlighting":
  3039             if showadvanced.get()=="false":
  3040                 # Default parameters
  3041                 if gui: gui.newline("  Depth:", 8, 0, None, [0.4,0.4,0.4])
  3042                 str += luxInt("maxdepth", luxProp(scn, "sintegrator.dlighting.maxdepth", 8), 0, 2048, "bounces", "The maximum recursion depth for ray casting", gui, 2.0)
  3043 
  3044             if showadvanced.get()=="true":
  3045                 # Advanced parameters
  3046                 str += luxOption("strategy", luxProp(scn, "sintegrator.dlighting.strategy", "auto"), ["one", "all", "auto"], "strategy", "select directlighting strategy", gui)
  3047                 if gui: gui.newline("  Depth:")
  3048                 str += luxInt("maxdepth", luxProp(scn, "sintegrator.dlighting.maxdepth", 8), 0, 2048, "max-depth", "The maximum recursion depth for ray casting", gui)
  3049                 if gui: gui.newline()
  3050 
  3051         if integratortype.get() == "path":
  3052             if showadvanced.get()=="false":
  3053                 # Default parameters
  3054                 if gui: gui.newline("  Depth:", 8, 0, None, [0.4,0.4,0.4])
  3055                 str += luxInt("maxdepth", luxProp(scn, "sintegrator.path.maxdepth", 10), 0, 2048, "bounces", "The maximum recursion depth for ray casting", gui, 1.0)
  3056                 ienv = luxProp(scn, "sintegrator.path.ienvironment", "true")
  3057                 str += luxBool("includeenvironment", ienv, "Include Environment", "Enable/Disable rendering of environment lightsources", gui)
  3058 
  3059             if showadvanced.get()=="true":
  3060                 # Advanced parameters
  3061                 if gui: gui.newline("  Depth:")
  3062                 str += luxInt("maxdepth", luxProp(scn, "sintegrator.path.maxdepth", 10), 0, 2048, "maxdepth", "The maximum recursion depth for ray casting", gui)
  3063                 str += luxOption("strategy", luxProp(scn, "sintegrator.path.strategy", "auto"), ["one", "all", "auto"], "strategy", "select directlighting strategy", gui)
  3064                 if gui: gui.newline("  RR:")
  3065                 rrstrat = luxProp(scn, "sintegrator.path.rrstrategy", "efficiency")
  3066                 str += luxOption("rrstrategy", rrstrat, ["efficiency", "probability", "none"], "RR strategy", "select Russian Roulette path termination strategy", gui)
  3067                 if rrstrat.get() == "probability":
  3068                     str += luxFloat("rrcontinueprob", luxProp(scn, "sintegrator.path.rrcontinueprob", 0.65), 0.0, 1.0, "rrprob", "Russian roulette continue probability", gui)
  3069                 ienv = luxProp(scn, "sintegrator.path.ienvironment", "true")
  3070                 str += luxBool("includeenvironment", ienv, "Include Environment", "Enable/Disable rendering of environment lightsources", gui)
  3071 
  3072         if integratortype.get() == "bidirectional":
  3073             if showadvanced.get()=="false":
  3074                 # Default parameters
  3075                 if gui: gui.newline("  Depth:", 8, 0, None, [0.4,0.4,0.4])
  3076                 bounces = luxProp(scn, "sintegrator.bidir.bounces", 16)
  3077                 luxInt("bounces", bounces, 5, 32, "bounces", "The maximum recursion depth for ray casting (in both directions)", gui, 2.0)
  3078                 str += "\n   \"integer eyedepth\" [%i]\n"%bounces.get()
  3079                 str += "   \"integer lightdepth\" [%i]"%bounces.get()
  3080 
  3081             if showadvanced.get()=="true":
  3082                 # Advanced parameters
  3083                 if gui: gui.newline("  Depth:")
  3084                 str += luxInt("eyedepth", luxProp(scn, "sintegrator.bidir.eyedepth", 16), 0, 2048, "eyedepth", "The maximum recursion depth for ray casting", gui)
  3085                 str += luxInt("lightdepth", luxProp(scn, "sintegrator.bidir.lightdepth", 16), 0, 2048, "lightdepth", "The maximum recursion depth for light ray casting", gui)
  3086                 str += luxOption("strategy", luxProp(scn, "sintegrator.bidir.strategy", "auto"), ["one", "all", "auto"], "strategy", "select directlighting strategy", gui)
  3087                 
  3088                 str += luxFloat('eyerrthreshold', luxProp(scn, "sintegrator.bidir.eyerrthreshold", 0), 0, 1, "eyerrthreshold", "The minimum probability for russian roulette eye subpath termination ", gui)
  3089                 str += luxFloat('lightrrthreshold', luxProp(scn, "sintegrator.bidir.lightrrthreshold", 0), 0, 1, "lightrrthreshold", "The minimum probability for russian roulette light subpath termination ", gui)
  3090 
  3091         if integratortype.get() == "exphotonmap":
  3092             if gui: gui.newline("  Render:")
  3093             str += luxOption("renderingmode", luxProp(scn, "sintegrator.photonmap.renderingmode", "directlighting"), ["directlighting", "path"], "renderingmode", "select rendering mode", gui)
  3094             str += luxOption("strategy", luxProp(scn, "sintegrator.photonmap.strategy", "auto"), ["one", "all", "auto"], "strategy", "select directlighting strategy", gui)
  3095             str += luxInt("maxphotondepth", luxProp(scn, "sintegrator.photonmap.maxphotondepth", 10), 1, 1024, "maxphotondepth", "The maximum recursion depth of photon tracing", gui)
  3096             str += luxInt("maxdepth", luxProp(scn, "sintegrator.photonmap.maxdepth", 6), 1, 1024, "maxdepth", "The maximum recursion depth of specular reflection and refraction", gui)
  3097             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)
  3098             str += luxInt("nused", luxProp(scn, "sintegrator.photonmap.nused", 50), 0, 1000000, "nused", "The number of photons to use in density estimation", gui)
  3099 
  3100             if gui: gui.newline("  Photons:")
  3101             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)
  3102             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)
  3103             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)
  3104             if gui: gui.newline("  FinalGather:")
  3105             fg = luxProp(scn, "sintegrator.photonmap.fgather", "true")
  3106             str += luxBool("finalgather", fg, "finalgather", "Enable use of final gather during rendering", gui)
  3107             if fg.get() == "true":
  3108                 rrstrat = luxProp(scn, "sintegrator.photonmap.gatherrrstrategy", "efficiency")
  3109                 str += luxOption("gatherrrstrategy", rrstrat, ["efficiency", "probability", "none"], "RR strategy", "select Russian Roulette gather termination strategy", gui)
  3110                 str += luxInt("finalgathersamples", luxProp(scn, "sintegrator.photonmap.fgathers", 32), 1, 1024, "samples", "The number of finalgather samples to take per pixel during rendering", gui)
  3111                 str += luxFloat("gatherangle", luxProp(scn, "sintegrator.photonmap.gangle", 10.0), 0.0, 360.0, "gatherangle", "Angle for final gather", gui)
  3112                 if rrstrat.get() == "probability":
  3113                     str += luxFloat("gatherrrcontinueprob", luxProp(scn, "sintegrator.photonmap.gatherrrcontinueprob", 0.65), 0.0, 1.0, "rrcontinueprob", "Probability for russian roulette particle tracing termination", gui)
  3114 
  3115         if integratortype.get() == "distributedpath":
  3116             str += luxOption("strategy", luxProp(scn, "sintegrator.distributedpath.strategy", "auto"), ["one", "all", "auto"], "strategy", "select directlighting strategy", gui)
  3117             if gui: gui.newline("  Direct:")
  3118             str += luxBool("directsampleall",luxProp(scn, "sintegrator.distributedpath.directsampleall", "true"), "Direct ALL", "Include diffuse direct light sample at first vertex", gui, 0.7)
  3119             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)
  3120             str += luxBool("indirectsampleall",luxProp(scn, "sintegrator.distributedpath.indirectsampleall", "false"), "Indirect ALL", "Include diffuse direct light sample at first vertex", gui, 0.7)
  3121             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)
  3122             if gui: gui.newline("  Diffuse:")
  3123             str += luxInt("diffusereflectdepth", luxProp(scn, "sintegrator.distributedpath.diffusereflectdepth", 3), 0, 2048, "Reflect", "The maximum recursion depth for diffuse reflection ray casting", gui, 0.5)
  3124             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)
  3125             str += luxInt("diffuserefractdepth", luxProp(scn, "sintegrator.distributedpath.diffuserefractdepth", 5), 0, 2048, "Refract", "The maximum recursion depth for diffuse refraction ray casting", gui, 0.5)
  3126             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)
  3127             str += luxBool("directdiffuse",luxProp(scn, "sintegrator.distributedpath.directdiffuse", "true"), "DL", "Include diffuse direct light sample at first vertex", gui, 0.20)
  3128             str += luxBool("indirectdiffuse",luxProp(scn, "sintegrator.distributedpath.indirectdiffuse", "true"), "IDL", "Include diffuse indirect light sample at first vertex", gui, 0.20)
  3129             if gui: gui.newline("  Glossy:")
  3130             str += luxInt("glossyreflectdepth", luxProp(scn, "sintegrator.distributedpath.glossyreflectdepth", 2), 0, 2048, "Reflect", "The maximum recursion depth for glossy reflection ray casting", gui, 0.50)
  3131             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)
  3132             str += luxInt("glossyrefractdepth", luxProp(scn, "sintegrator.distributedpath.glossyrefractdepth", 5), 0, 2048, "Refract", "The maximum recursion depth for glossy refraction ray casting", gui, 0.50)
  3133             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)
  3134             str += luxBool("directglossy",luxProp(scn, "sintegrator.distributedpath.directglossy", "true"), "DL", "Include glossy direct light sample at first vertex", gui, 0.20)
  3135             str += luxBool("indirectglossy",luxProp(scn, "sintegrator.distributedpath.indirectglossy", "true"), "IDL", "Include glossy indirect light sample at first vertex", gui, 0.20)
  3136             if gui: gui.newline("  Specular:")
  3137             str += luxInt("specularreflectdepth", luxProp(scn, "sintegrator.distributedpath.specularreflectdepth", 3), 0, 2048, "Reflect", "The maximum recursion depth for specular reflection ray casting", gui, 1.0)
  3138             str += luxInt("specularrefractdepth", luxProp(scn, "sintegrator.distributedpath.specularrefractdepth", 5), 0, 2048, "Refract", "The maximum recursion depth for specular refraction ray casting", gui, 1.0)
  3139             #if gui: gui.newline("  Caustics:")
  3140             #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)
  3141             #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)
  3142 
  3143             usereject = luxProp(scn, "sintegrator.distributedpath.usereject", "false")
  3144             luxCollapse("usereject", usereject, "Rejection", "Enable Rejection system to eliminate bright contributions", gui, 2.0)
  3145 
  3146             if usereject.get()=="true":
  3147                 if gui: gui.newline("  Diffuse:")
  3148                 
  3149                 diffusereflectreject = luxProp(scn, "sintegrator.distributedpath.difreflreject", "false")
  3150                 str += luxBool("diffusereflectreject", diffusereflectreject, "Reflect", "Enable Rejection for Diffuse Reflection", gui, 0.4)
  3151                 if diffusereflectreject.get()=="true":
  3152                     str += luxFloat("diffusereflectreject_threshold", luxProp(scn, "sintegrator.distributedpath.difreflrejectthr", 10.0), 0.01, 10.0, "Thr", "The Average Threshold to reject", gui, 0.6)
  3153             
  3154                 diffuserefractreject = luxProp(scn, "sintegrator.distributedpath.difrefrreject", "false")
  3155                 str += luxBool("diffuserefractreject", diffuserefractreject, "Refract", "Enable Rejection for Diffuse Refraction", gui, 0.4)
  3156                 if diffuserefractreject.get()=="true":
  3157                     str += luxFloat("diffuserefractreject_threshold", luxProp(scn, "sintegrator.distributedpath.difrefrrejectthr", 10.0), 0.01, 10.0, "Thr", "The Average Threshold to reject", gui, 0.6)
  3158             
  3159                 if gui: gui.newline("  Glossy:")
  3160                 
  3161                 glossyreflectreject = luxProp(scn, "sintegrator.distributedpath.glosreflreject", "false")
  3162                 str += luxBool("glossyreflectreject", glossyreflectreject, "Reflect", "Enable Rejection for Glossy Reflection", gui, 0.4)
  3163                 if glossyreflectreject.get()=="true":
  3164                     str += luxFloat("glossyreflectreject_threshold", luxProp(scn, "sintegrator.distributedpath.glosreflrejectthr", 10.0), 0.01, 10.0, "Thr", "The Average Threshold to reject", gui, 0.6)
  3165             
  3166                 glossyrefractreject = luxProp(scn, "sintegrator.distributedpath.glosrefrreject", "false")
  3167                 str += luxBool("glossyrefractreject", glossyrefractreject, "Refract", "Enable Rejection for Glossy Refraction", gui, 0.4)
  3168                 if glossyrefractreject.get()=="true":
  3169                     str += luxFloat("glossyrefractreject_threshold", luxProp(scn, "sintegrator.distributedpath.glosrefrrejectthr", 10.0), 0.01, 10.0, "Thr", "The Average Threshold to reject", gui, 0.6)
  3170     
  3171         if integratortype.get() == "igi":
  3172             if gui: gui.newline("  Depth:", 8, 0, None, [0.4,0.4,0.4])
  3173             depth = luxProp(scn, "sintegrator.igi.maxdepth", 5)
  3174             luxInt("maxdepth", depth, 1, 32, "maxdepth", "The maximum recursion depth for ray casting", gui, 2.0)
  3175             if showadvanced.get()=="true":
  3176                 # Advanced parameters
  3177                 if gui: gui.newline("  VLights:")
  3178                 str += luxInt("nsets", luxProp(scn, "sintegrator.igi.nsets", 4), 1, 100, "nsets", "The number of virtual lights sets", gui)
  3179                 str += luxInt("nlights", luxProp(scn, "sintegrator.igi.nlights", 64), 1, 1000, "nlights", "The number of light paths per light set", gui)
  3180                 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)
  3181 
  3182     
  3183     return str
  3184 
  3185 def luxVolumeIntegrator(scn, gui=None):
  3186     global icon_c_volumeintegrator
  3187     str = ""
  3188     if scn:
  3189         integratortype = luxProp(scn, "vintegrator.type", "single")
  3190         str = luxIdentifier("VolumeIntegrator", integratortype, ["emission", "single"], "VOLUME INT", "select volume integrator type", gui, icon_c_volumeintegrator)
  3191         if integratortype.get() == "emission":
  3192             str += luxFloat("stepsize", luxProp(scn, "vintegrator.emission.stepsize", 1.0), 0.0, 100.0, "stepsize", "Stepsize for volumes", gui)
  3193         if integratortype.get() == "single":
  3194             str += luxFloat("stepsize", luxProp(scn, "vintegrator.emission.stepsize", 1.0), 0.0, 100.0, "stepsize", "Stepsize for volumes", gui)
  3195     return str
  3196 
  3197 def luxEnvironment(scn, gui=None):
  3198     global icon_c_environment
  3199     str = ""
  3200     if scn:
  3201         envtype = luxProp(scn, "env.type", "infinite")
  3202         lsstr = luxIdentifier("LightSource", envtype, ["none", "infinite", "sunsky"], "ENVIRONMENT", "select environment light type", gui, icon_c_environment)
  3203         if gui: gui.newline()
  3204         str = ""
  3205         
  3206         if envtype.get() != "none":
  3207             
  3208             if envtype.get() in ["infinite", "sunsky"]:
  3209                 env_lg = luxProp(scn, "env.lightgroup", "default")
  3210                 luxString("env.lightgroup", env_lg, "lightgroup", "Environment light group", gui)
  3211                 if luxProp(scn, "nolg", "false").get()!="true":
  3212                     lsstr = '\nLightGroup "' + env_lg.get() + '"' + lsstr
  3213                 rotZ = luxProp(scn, "env.rotation", 0.0)
  3214                 rotY = luxProp(scn, "env.rotationY", 0.0)
  3215                 rotX = luxProp(scn, "env.rotationX", 0.0)
  3216                 if gui: gui.newline()
  3217                 luxFloat("rotation", rotX, 0.0, 360.0, "rot X", "environment rotation X", gui, 0.66)
  3218                 luxFloat("rotation", rotY, 0.0, 360.0, "rot Y", "environment rotation Y", gui, 0.66)
  3219                 luxFloat("rotation", rotZ, 0.0, 360.0, "rot Z", "environment rotation Z", gui, 0.66)
  3220                 if rotZ.get() != 0 or rotY.get() != 0 or rotX.get() != 0:
  3221                     str += "\tRotate %d 1 0 0\n"%(rotX.get())
  3222                     str += "\tRotate %d 0 1 0\n"%(rotY.get())
  3223                     str += "\tRotate %d 0 0 1\n"%(rotZ.get())
  3224             str += "\t"+lsstr
  3225 
  3226             infinitehassun = 0
  3227             if envtype.get() == "infinite":
  3228                 mapping = luxProp(scn, "env.infinite.mapping", "latlong")
  3229                 mappings = ["latlong","angular","vcross"]
  3230                 mapstr = luxOption("mapping", mapping, mappings, "mapping", "Select mapping type", gui, 0.5)
  3231                 map = luxProp(scn, "env.infinite.mapname", "")
  3232                 mapstr += luxFile("mapname", map, "map-file", "filename of the environment map", gui, 1.5)
  3233                 mapstr += luxFloat("gamma", luxProp(scn, "env.infinite.gamma", 1.0), 0.0, 6.0, "gamma", "", gui, 1.0)
  3234                 
  3235                 if map.get() != "":
  3236                     str += mapstr
  3237                 else:
  3238                     try:
  3239                         worldcolor = Blender.World.Get('World').getHor()
  3240                         str += "\n   \"color L\" [%g %g %g]" %(worldcolor[0], worldcolor[1], worldcolor[2])
  3241                     except: pass
  3242 
  3243                 str += luxFloat("gain", luxProp(scn, "env.infinite.gain", 1.0), 0.0001, 100.0, "gain", "Infinite Env Gain", gui, 1.0)
  3244 
  3245                 infinitesun = luxProp(scn, "env.infinite.hassun", "false")
  3246                 luxCollapse("infinitesun", infinitesun, "Sun Component", "Add Sunlight Component", gui, 2.0)
  3247                 if(infinitesun.get() == "true"):
  3248                     sun_lg = luxProp(scn, "env.sun_lightgroup", "default")
  3249                     luxString("env.lightgroup", sun_lg, "lightgroup", "Sun component light group", gui)
  3250                     if luxProp(scn, "nolg", "false").get()!="true":
  3251                         str += '\nLightGroup "' + sun_lg.get() + '"'
  3252                     str += "\nLightSource \"sun\" "
  3253                     infinitehassun = 1
  3254 
  3255 
  3256             if envtype.get() == "sunsky" or infinitehassun == 1:
  3257                 
  3258                 
  3259                 sun = None
  3260                 for obj in scn.objects:
  3261                     if (obj.getType() == "Lamp") and ((obj.Layers & scn.Layers) > 0):
  3262                         if obj.getData(mesh=1).getType() == 1: # sun object # data
  3263                             sun = obj
  3264                 if sun:
  3265                     str += luxFloat("gain", luxProp(scn, "env.sunsky.gain", 1.0), 0.0001, 100.0, "gain", "Sky gain", gui)
  3266                     
  3267                     invmatrix = Mathutils.Matrix(sun.getInverseMatrix())
  3268                     str += "\n   \"vector sundir\" [%f %f %f]\n" %(invmatrix[0][2], invmatrix[1][2], invmatrix[2][2])
  3269                     str += luxFloat("relsize", luxProp(scn, "env.sunsky.relsize", 1.0), 0.0, 100.0, "rel.size", "relative sun size", gui)
  3270                     str += luxFloat("turbidity", luxProp(scn, "env.sunsky.turbidity", 2.2), 2.0, 50.0, "turbidity", "Sky turbidity", gui)
  3271                     
  3272                     showGeo = luxProp(sun, 'sc.show', 'false')
  3273                     if gui:
  3274                         luxCollapse("sc.show", showGeo, "Geographic Sun", "Set sun position by world location, date and time", gui, 2.0)
  3275                     if gui and showGeo.get() == 'true':
  3276                         gui.newline("Geographic:")
  3277                         sc = sun_calculator(sun)
  3278                         
  3279                         luxInt("sc.day", luxProp(sun, "sc.day", 1), 1, 31, "day", "Local date: day", gui, 0.66)
  3280                         luxInt("sc.month", luxProp(sun, "sc.month", 1), 1, 12, "month", "Local date: month", gui, 0.67)
  3281                         luxInt("sc.year", luxProp(sun, "sc.year", 2009), 1800, 2100, "year", "Local date: year", gui, 0.66)
  3282                         
  3283                         luxInt("sc.hour", luxProp(sun, "sc.hour", 0), 0, 23, "hour", "Local time: hour", gui, 0.72)
  3284                         luxInt("sc.minute", luxProp(sun, "sc.minute", 0), 0, 59, "minute", "Local time: minute", gui, 0.72)
  3285                         luxBool("sc.dst", luxProp(sun, "sc.dst", 'false'), "DST", "DST", gui, 0.28)
  3286                         r = gui.getRect(0.28,1)
  3287                         Draw.Button("NOW", 0, r[0], r[1], r[2], r[3], "Set to current time", lambda e,v: sc.now())
  3288                         
  3289                         r = gui.getRect(0.3,1)
  3290                         Draw.Button("Preset", 0, r[0], r[1], r[2], r[3], "Choose a preset location", lambda e,v: sc.set_location(
  3291                             Draw.PupTreeMenu(sun_calculator.location_list)
  3292                         ))
  3293                         
  3294                         luxFloat("sc.lat", luxProp(sun, "sc.lat", 0.0), -90.0, 90.0, "lat", "Location: latitude", gui, 0.56)
  3295                         luxFloat("sc.long", luxProp(sun, "sc.long", 0.0), -180.0, 180.0, "long", "Location: longitude", gui, 0.56)
  3296                         luxInt("sc.tz", luxProp(sun, "sc.tz", 0), -12, 12, "timezone", "Local time: timezone offset from GMT", gui, 0.56)
  3297                         
  3298                         r = gui.getRect(2,1)
  3299                         Draw.Button("Calculate", 0, r[0], r[1], r[2], r[3], "Calculate sun's position", lambda e,v: sc.compute())
  3300                     
  3301                 else:
  3302                     if gui:
  3303                         gui.newline(); r = gui.getRect(2,1); BGL.glRasterPos2i(r[0],r[1]+5) 
  3304                         Draw.Text("create a blender Sun Lamp")
  3305 
  3306 
  3307             str += "\n"
  3308         #if gui: gui.newline("GLOBAL:", 8, 0, None, [0.75,0.5,0.25])
  3309         #luxFloat("scale", luxProp(scn, "global.scale", 1.0), 0.0, 10.0, "scale", "global world scale", gui)
  3310         
  3311     return str
  3312 
  3313 class sun_calculator:
  3314     #Based on SunLight v1.0 by Miguel Kabantsov (miguelkab@gmail.com)
  3315     #Replaces the faulty sun position calculation algorythm with a precise calculation (Source for algorythm: http://de.wikipedia.org/wiki/Sonnenstand),
  3316     #Co-Ordinates: http://www.bcca.org/misc/qiblih/latlong.html
  3317     #Author: Nils-Peter Fischer (Nils-Peter.Fischer@web.de)
  3318     
  3319     sun = None
  3320     
  3321     lat = 0
  3322     long = 0
  3323     
  3324     hour = 0
  3325     min = 0
  3326     tz = 0
  3327     dst = 'false'
  3328     
  3329     day = 0
  3330     month = 0
  3331     year = 0
  3332     
  3333     location_list = [
  3334         ("EUROPE",[
  3335             ("Antwerp, Belgium",          67),
  3336             ("Berlin, Germany",            1),
  3337             ("Bratislava, Slovak Republic", 70),
  3338             ("Brno, Czech Republic",      72),
  3339             ("Brussles, Belgium",         68),
  3340             ("Geneva, Switzerland",       65),
  3341             ("Helsinki, Finland",          7),
  3342             ("Innsbruck, Austria",        62),
  3343             ("Kyiv, Ukraine",             64),
  3344             ("London, England",           10),
  3345             ("Lyon, France",              66),
  3346             ("Nitra, Slovak Republic",    69),
  3347             ("Oslo, Norway",              58),
  3348             ("Paris, France",             15),
  3349             ("Praha, Czech Republic",     71),
  3350             ("Rome, Italy",               18),
  3351             ("Telfs, Austria",            63),
  3352             ("Warsaw, Poland",            74),
  3353             ("Wroclaw, Poland",           73),
  3354             ("Zurich, Switzerland",       21),
  3355         ]),
  3356     
  3357         ("WORLD CITIES", [
  3358             ("Beijing, China",             0),
  3359             ("Bombay, India",              2),
  3360             ("Buenos Aires, Argentina",    3),
  3361             ("Cairo, Egypt",               4),
  3362             ("Cape Town, South Africa",    5),
  3363             ("Caracas, Venezuela",         6),
  3364             ("Curitiba, Brazil",          60),
  3365             ("Hong Kong, China",           8),
  3366             ("Jerusalem, Israel",          9),
  3367             ("Joinville, Brazil",         61),
  3368             ("Mexico City, Mexico",       11),
  3369             ("Moscow, Russia",            12),
  3370             ("New Delhi, India",          13),
  3371             ("Ottawa, Canada",            14),
  3372             ("Rio de Janeiro, Brazil",    16),
  3373             ("Riyadh, Saudi Arabia",      17),
  3374             ("Sao Paulo, Brazil",         59),
  3375             ("Sydney, Australia",         19),
  3376             ("Tokyo, Japan",              20), 
  3377         ]),
  3378         
  3379         ("US CITIES", [
  3380             ("Albuquerque, NM",           22),
  3381             ("Anchorage, AK",             23),
  3382             ("Atlanta, GA",               24),
  3383             ("Austin, TX",                25),
  3384             ("Birmingham, AL",            26),
  3385             ("Bismarck, ND",              27),
  3386             ("Boston, MA",                28),
  3387             ("Boulder, CO",               29),
  3388             ("Chicago, IL",               30),
  3389             ("Dallas, TX",                31),
  3390             ("Denver, CO",                32),
  3391             ("Detroit, MI",               33),
  3392             ("Honolulu, HI",              34),
  3393             ("Houston, TX",               35),
  3394             ("Indianapolis, IN",          36),
  3395             ("Jackson, MS",               37),
  3396             ("Kansas City, MO",           38),
  3397             ("Los Angeles, CA",           39),
  3398             ("Menomonee Falls, WI",       40),
  3399             ("Miami, FL",                 41),
  3400             ("Minneapolis, MN",           42),
  3401             ("New Orleans, LA",           43),
  3402             ("New York City, NY",         44),
  3403             ("Oklahoma City, OK",         45),
  3404             ("Philadelphia, PA",          46),
  3405             ("Phoenix, AZ",               47),
  3406             ("Pittsburgh, PA",            48),
  3407             ("Portland, ME",              49),
  3408             ("Portland, OR",              50),
  3409             ("Raleigh, NC",               51),
  3410             ("Richmond, VA",              52),
  3411             ("Saint Louis, MO",           53),
  3412             ("San Diego, CA",             54),
  3413             ("San Francisco, CA",         55),
  3414             ("Seattle, WA",               56),
  3415             ("Washington DC",             57),
  3416         ])
  3417     ]
  3418 
  3419     location_data = {
  3420         # Europe
  3421         67:   ( 51.2167, 4.4, 1),
  3422         1:    ( 52.33, 13.30, 1),
  3423         70:   ( 48.17, 17.17, 1),
  3424         72:   ( 49.2, 16.63, 1),
  3425         68:   ( 58.8467, 4.3525, 1),
  3426         65:   ( 46.217, 6.150, 1),
  3427         7:    ( 60.1667, 24.9667,2),
  3428         62:   ( 47.2672, 11.3928, 1),
  3429         64:   ( 50.75, 30.0833, 2),
  3430         10:   ( 51.50, 0.0, 0),
  3431         66:   ( 45.767, 4.833, 1),
  3432         69:   ( 48.32, 18.07, 1),
  3433         58:   ( 59.56, 10.41, 1),
  3434         15:   ( 48.8667, 2.667, 1),
  3435         71:   ( 50.08, 14.46, 1),
  3436         18:   ( 41.90, 12.4833, 1),
  3437         63:   ( 47.3, 11.0667, 1),
  3438         74:   ( 52.232, 21.008, 1),
  3439         73:   ( 51.108, 17.038, 1),
  3440         21:   ( 47.3833, 8.5333, 1),
  3441     
  3442         # World Cities
  3443         0:    ( 39.9167, 116.4167, 8),
  3444         2:    ( 18.9333, 72.8333, 5.5),
  3445         3:    (-34.60, -58.45, -3),
  3446         4:    ( 30.10, 31.3667, 2),
  3447         5:    (-33.9167, 18.3667, 2),
  3448         6:    ( 10.50, -66.9333, -4),
  3449         60:   (-25.4278, -49.2731, -3),
  3450         8:    ( 22.25, 114.1667, 8),
  3451         9:    ( 31.7833, 35.2333, 2),
  3452         61:   (-29.3044, -48.8456, -3),
  3453         11:   ( 19.4, -99.15, -6),
  3454         12:   ( 55.75, 37.5833, 3),
  3455         13:   ( 28.6, 77.2, 5.5),
  3456         14:   ( 45.41667, -75.7, -5),
  3457         16:   (-22.90, -43.2333, -3),
  3458         17:   ( 24.633, 46.71667, 3),
  3459         59:   ( -23.5475, -46.6361, -3),
  3460         19:   (-33.8667,151.2167,10),
  3461         20:   ( 35.70, 139.7667, 9), 
  3462     
  3463         # US Cities
  3464         22:   ( 35.0833, -106.65, -7),
  3465         23:   ( 61.217, -149.90, -9),
  3466         24:   ( 33.733, -84.383, -5),
  3467         25:   ( 30.283, -97.733, -6),
  3468         26:   ( 33.521, -86.8025, -6),
  3469         27:   ( 46.817, -100.783, -6),
  3470         28:   ( 42.35, -71.05, -5),
  3471         29:   ( 40.125, -105.237, -7),
  3472         30:   ( 41.85, -87.65, -6),
  3473         31:   ( 32.46, -96.47, -6),
  3474         32:   ( 39.733, -104.983, -7),
  3475         33:   ( 42.333, -83.05, -5),
  3476         34:   ( 21.30, -157.85, -10),
  3477         35:   ( 29.75, -95.35, -6),
  3478         36:   ( 39.767, -86.15, -5),
  3479         37:   ( 32.283, -90.183, -6),
  3480         38:   ( 39.083, -94.567, -6),
  3481         39:   ( 34.05, -118.233, -8),
  3482         40:   ( 43.11, -88.10, -6),
  3483         41:   ( 25.767, -80.183, -5),
  3484         42:   ( 44.967, -93.25, -6),
  3485         43:   ( 29.95, -90.067, -6),
  3486         44:   ( 40.7167, -74.0167, -5),
  3487         45:   ( 35.483, -97.533, -6),
  3488         46:   ( 39.95, -75.15, -5),
  3489         47:   ( 33.433, -112.067,-7),
  3490         48:   ( 40.433, -79.9833, -5),
  3491         49:   ( 43.666, -70.283, -5),
  3492         50:   ( 45.517, -122.65, -8),
  3493         51:   ( 35.783, -78.65, -5),
  3494         52:   ( 37.5667, -77.450, -5),
  3495         53:   ( 38.6167, -90.1833, -6),
  3496         54:   ( 32.7667, -117.2167, -8),
  3497         55:   ( 37.7667, -122.4167, -8),
  3498         56:   ( 47.60, -122.3167, -8),
  3499         57:   ( 38.8833, -77.0333, -5),
  3500     }
  3501 
  3502     def __init__(self, sun):
  3503         self.sun = sun
  3504     
  3505     def now(self):
  3506         ct = time.localtime()
  3507         
  3508         if ct[8] == 0:
  3509             dst = 'false'
  3510         else:
  3511             dst = 'true'
  3512         
  3513         luxProp(self.sun, 'sc.day', 0).set(ct[2])
  3514         luxProp(self.sun, 'sc.month', 0).set(ct[1])
  3515         luxProp(self.sun, 'sc.year', 0).set(ct[0])
  3516         luxProp(self.sun, 'sc.hour', 0).set(ct[3])
  3517         luxProp(self.sun, 'sc.minute', 0).set(ct[4])
  3518         luxProp(self.sun, 'sc.dst', 0).set(dst)
  3519         
  3520         self.compute()
  3521         
  3522     def set_location(self, location):
  3523         if location < 0: return
  3524         
  3525         lat, long, tz = self.location_data[location]
  3526         luxProp(self.sun, "sc.lat", 0).set(lat)
  3527         luxProp(self.sun, "sc.long", 0).set(long)
  3528         luxProp(self.sun, "sc.tz", 0).set(tz)
  3529         
  3530         self.compute()
  3531     
  3532     def compute(self):
  3533         
  3534         self.lat  = luxProp(self.sun, "sc.lat", 0).get()
  3535         self.long = luxProp(self.sun, "sc.long", 0).get()
  3536         self.tz   = luxProp(self.sun, "sc.tz", 0).get()
  3537         
  3538         self.hour = luxProp(self.sun, "sc.hour", 0).get()
  3539         self.min  = luxProp(self.sun, "sc.minute", 0).get()
  3540         self.dst  = luxProp(self.sun, "sc.dst", 'false').get()
  3541         if self.dst == 'true':
  3542             self.dst = 1
  3543         else:
  3544             self.dst = 0
  3545         
  3546         self.day   = luxProp(self.sun, "sc.day", 0).get()
  3547         self.month = luxProp(self.sun, "sc.month", 0).get()
  3548         self.year  = luxProp(self.sun, "sc.year", 0).get()
  3549         
  3550         
  3551         az,el = self.geoSunData(
  3552             self.lat,
  3553             self.long,
  3554             self.year,
  3555             self.month,
  3556             self.day,
  3557             self.hour + self.min/60.0,
  3558             -self.tz + self.dst
  3559         )
  3560         
  3561         self.sun.rot = math.radians(90-el), 0, math.radians(-az)
  3562         
  3563         Window.Redraw()
  3564         
  3565         
  3566     # --- THE FOLLOWING METHODS ARE ADAPTED FROM LUXMAYA ---
  3567     
  3568     # mathematical helpers
  3569     def sind(self, deg):
  3570         return math.sin(math.radians(deg))
  3571     
  3572     def cosd(self, deg):
  3573         return math.cos(math.radians(deg))
  3574     
  3575     def tand(self, deg):
  3576         return math.tan(math.radians(deg))
  3577     
  3578     def asind(self, deg):
  3579         return math.degrees(math.asin(deg))
  3580     
  3581     def atand(self, deg):
  3582         return math.degrees(math.atan(deg))
  3583     
  3584     
  3585     def geo_sun_astronomicJulianDate(self, Year, Month, Day, LocalTime, Timezone):
  3586         """
  3587         See quoted source in class header for explanation
  3588         """
  3589         
  3590         if Month > 2.0:
  3591             Y = Year
  3592             M = Month
  3593         else:
  3594             Y = Year - 1.0
  3595             M = Month + 12.0
  3596             
  3597         UT = LocalTime - Timezone
  3598         hour = UT / 24.0
  3599         A = int(Y/100.0)
  3600         B = 2.0 - A+int(A/4.0)
  3601         
  3602         JD = math.floor(365.25*(Y+4716.0)) + math.floor(30.6001*(M+1.0)) + Day + hour + B - 1524.4
  3603         
  3604         return JD
  3605     
  3606     def geoSunData(self, Latitude, Longitude, Year, Month, Day, LocalTime, Timezone):
  3607         """
  3608         See quoted source in class header for explanation
  3609         """
  3610         
  3611         JD = self.geo_sun_astronomicJulianDate(Year, Month, Day, LocalTime, Timezone)
  3612         
  3613         phi = Latitude
  3614         llambda = Longitude
  3615                 
  3616         n = JD - 2451545.0
  3617         LDeg = (280.460 + 0.9856474*n) - (math.floor((280.460 + 0.9856474*n)/360.0) * 360.0)
  3618         gDeg = (357.528 + 0.9856003*n) - (math.floor((357.528 + 0.9856003*n)/360.0) * 360.0)
  3619         LambdaDeg = LDeg + 1.915 * self.sind(gDeg) + 0.02 * self.sind(2.0*gDeg)
  3620         
  3621         epsilonDeg = 23.439 - 0.0000004*n
  3622         
  3623         alphaDeg = self.atand( (self.cosd(epsilonDeg) * self.sind(LambdaDeg)) / self.cosd(LambdaDeg) )
  3624         if self.cosd(LambdaDeg) < 0.0:
  3625             alphaDeg += 180.0
  3626             
  3627         deltaDeg = self.asind( self.sind(epsilonDeg) * self.sind(LambdaDeg) )
  3628         
  3629         JDNull = self.geo_sun_astronomicJulianDate(Year, Month, Day, 0.0, 0.0)
  3630         
  3631         TNull = (JDNull - 2451545.0) / 36525.0
  3632         T = LocalTime - Timezone
  3633         
  3634         thetaGh = 6.697376 + 2400.05134*TNull + 1.002738*T
  3635         thetaGh -= math.floor(thetaGh/24.0) * 24.0
  3636         
  3637         thetaG = thetaGh * 15.0
  3638         theta = thetaG + llambda
  3639         
  3640         tau = theta - alphaDeg
  3641         
  3642         a = self.atand( self.sind(tau) / ( self.cosd(tau)*self.sind(phi) - self.tand(deltaDeg)*self.cosd(phi)) )
  3643         if self.cosd(tau)*self.sind(phi) - self.tand(deltaDeg)*self.cosd(phi) < 0.0:
  3644             a += 180.0
  3645         
  3646         h = self.asind( self.cosd(deltaDeg)*self.cosd(tau)*self.cosd(phi) + self.sind(deltaDeg)*self.sind(phi) )
  3647         
  3648         R = 1.02 / (self.tand (h+(10.3/(h+5.11))))
  3649         hR = h + R/60.0
  3650         
  3651         azimuth = a
  3652         elevation = hR
  3653         
  3654         return azimuth, elevation
  3655 
  3656 def luxAccelerator(scn, gui=None):
  3657     str = ""
  3658     if scn:
  3659         acceltype = luxProp(scn, "accelerator.type", "tabreckdtree")
  3660         str = luxIdentifier("Accelerator", acceltype, ["none", "tabreckdtree", "grid", "bvh", "qbvh"], "ACCEL", "select accelerator type", gui)
  3661         if acceltype.get() == "tabreckdtree":
  3662             if gui: gui.newline()
  3663             str += luxInt("intersectcost", luxProp(scn, "accelerator.kdtree.interscost", 80), 0, 1000, "inters.cost", "specifies how expensive ray-object intersections are", gui)
  3664             str += luxInt("traversalcost", luxProp(scn, "accelerator.kdtree.travcost", 1), 0, 1000, "trav.cost", "specifies how expensive traversing a ray through the kdtree is", gui)
  3665             if gui: gui.newline()
  3666             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)
  3667             if gui: gui.newline()
  3668             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)
  3669             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)
  3670         if acceltype.get() == "unsafekdtree":
  3671             if gui: gui.newline()
  3672             str += luxInt("intersectcost", luxProp(scn, "accelerator.kdtree.interscost", 80), 0, 1000, "inters.cost", "specifies how expensive ray-object intersections are", gui)
  3673             str += luxInt("traversalcost", luxProp(scn, "accelerator.kdtree.travcost", 1), 0, 1000, "trav.cost", "specifies how expensive traversing a ray through the kdtree is", gui)
  3674             if gui: gui.newline()
  3675             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)
  3676             if gui: gui.newline()
  3677             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)
  3678             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)
  3679         if acceltype.get() == "grid":
  3680             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)
  3681         if acceltype.get() == "qbvh":
  3682             if gui: gui.newline()
  3683             str += luxInt("maxprimsperleaf", luxProp(scn, "accelerator.qbvh.maxprimsperleaf", 4), 1, 64, "maxprimsperleaf", "Maximum number of primitives to leave in one leaf node", gui)
  3684     return str
  3685 
  3686 def luxSystem(scn, gui=None):
  3687     if scn:
  3688         if gui: gui.newline("PATHS:", 10)
  3689         lp = luxProp(scn, "lux", "")
  3690         lp.set(Blender.sys.dirname(lp.get())+os.sep)
  3691         luxPath("LUX dir", lp, "lux binary dir", "Lux installation path", gui, 2.0)
  3692 
  3693 #        luxFile("GUI filename", luxProp(scn, "lux", ""), "lux-file", "filename and path of the lux GUI executable", gui, 2.0)
  3694 #        luxFile("Console filename", luxProp(scn, "luxconsole", ""), "lux-file-console", "filename and path of the lux console executable", gui, 2.0)
  3695         if gui: gui.newline()
  3696         luxFile("datadir", luxProp(scn, "datadir", ""), "default out dir", "default.lxs save path", gui, 2.0)
  3697 
  3698         if gui: gui.newline()
  3699         pm = ["absolute","relative","flat"]
  3700         luxOption("pathmode", luxProp(scn, "pathmode", "absolute"), pm, "path-mode", "select format for paths on export", gui, 2.0)
  3701 
  3702         if gui: gui.newline("PRIORITY:", 10)
  3703         luxnice = luxProp(scn, "luxnice", 10)
  3704         if osys.platform=="win32":
  3705             r = gui.getRect(2, 1)
  3706             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))
  3707         else: luxInt("nice", luxnice, -20, 19, "nice", "nice value. Range goes from -20 (highest priority) to 19 (lowest)", gui)
  3708 
  3709         luxBool("noopengl", luxProp(scn, "noopengl", "false"), "Disable OpenGL", "(workaround for some buggy display drivers)", gui, 1.0)
  3710 
  3711 
  3712         if gui: gui.newline("THREADS:", 10)
  3713         autothreads = luxProp(scn, "autothreads", "true")
  3714         luxBool("autothreads", autothreads, "Auto Detect", "Automatically use all available processors", gui, 1.0)
  3715         if autothreads.get()=="false":
  3716             luxInt("threads", luxProp(scn, "threads", 1), 1, 100, "threads", "number of threads used for rendering", gui, 1.0)
  3717 #        luxBool('export.threaded', luxProp(scn, 'export.threaded', 'true'), 'Pipe in background', 'When using pipe export, do not block Blender UI', gui, 1.0)
  3718 
  3719         if gui: gui.newline("ANIM:", 10)
  3720         useparamkeys = luxProp(scn, "useparamkeys", "false")
  3721         luxBool("useparamkeys", useparamkeys, "Enable Parameter IPO Keyframing", "Enables keyframing of luxblend parameters", gui, 2.0)
  3722 
  3723         if gui: gui.newline("PARAMS:", 10)
  3724         parammodeadvanced = luxProp(scn, "parammodeadvanced", "false")
  3725         luxBool("parammodeadvanced", parammodeadvanced, "Default Advanced Parameters", "Always use advanced parameters by default", gui, 2.0)
  3726 
  3727         if gui: gui.newline("PREVIEW:", 10)
  3728         qs = ["low","medium","high","very high"]
  3729         defprevmat = luxProp(scn, "defprevmat", "high")
  3730         luxOption("defprevmat", defprevmat, qs, "Materials", "Select default preview quality in material editor for materials", gui, 1.0)
  3731 
  3732         if gui: gui.newline("GAMMA:", 10)
  3733         luxBool("RGC", luxProp(scn, "RGC", "true"), "RGC", "use reverse gamma correction", gui)
  3734         luxBool("ColClamp", luxProp(scn, "colorclamp", "false"), "ColClamp", "clamp all colors to 0.0-0.9", gui)
  3735         if gui: gui.newline("MESH:", 10)
  3736         luxBool("mesh_optimizing", luxProp(scn, "mesh_optimizing", "true"), "optimize meshes", "Optimize meshes during export", gui, 2.0)
  3737         #luxInt("trianglemesh thr", luxProp(scn, "trianglemesh_thr", 0), 0, 10000000, "trianglemesh threshold", "Vertex threshold for exporting (wald) trianglemesh object(s)", gui, 2.0)
  3738         #if gui: gui.newline()
  3739         #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)
  3740         if gui: gui.newline("INSTANCING:", 10)
  3741         luxInt("instancing_threshold", luxProp(scn, "instancing_threshold", 2), 0, 1000000, "object instancing threshold", "Threshold to created instanced objects", gui, 2.0)
  3742         
  3743         # dougal2 packed images, enable this when implemented in Lux itself
  3744         #if gui: gui.newline('TEXTURES:',10)
  3745         #impack = luxProp(scn, 'packtextures', 'false')
  3746         #luxBool('impack', impack, 'Pack All Images', '', gui, 2.0)
  3747         
  3748         if gui: 
  3749             network=luxProp(scn,"network","false")
  3750             gui.newline("NETWORK:", 10)
  3751             luxCollapse("network",network, "network", "enable network option", gui, 2.0)
  3752             if(network.get() == "true"):
  3753                 network_use_file=luxProp(scn,"network_use_file","false")
  3754                 luxBool ("use file",network_use_file,"use file", "get list of servers from file; one per line",gui,2.0)
  3755                 if (network_use_file.get() == "true"):
  3756                     luxFile("file", luxProp(scn, "network_file_path", ""), "file", "file where servers are defined", gui, 1.0)         
  3757                 else :     
  3758                     #gui.newline("")
  3759                     luxString("Servers",luxProp(scn,"network_servers",""),"servers","coma separated list of servers",gui,1.0)
  3760                 #gui.newline("")
  3761                 luxInt("network_interval",luxProp(scn,"newtork_interval",180),0,9999,"update interval","interval between network refresh",gui)
  3762 
  3763 
  3764 def scalelist(list, factor):
  3765     for i in range(len(list)): list[i] = list[i] * factor
  3766     return list
  3767 
  3768 
  3769 def luxMapping(key, mat, gui, level=0):
  3770     global icon_map2d, icon_map2dparam
  3771     if gui: gui.newline("2Dmap:", -2, level, icon_map2d)
  3772     mapping = luxProp(mat, key+".mapping", "uv")
  3773     mappings = ["uv","spherical","cylindrical","planar"]
  3774     str = luxOption("mapping", mapping, mappings, "mapping", "", gui, 0.5)
  3775     if mapping.get() == "uv":
  3776     	if gui: gui.newline()
  3777         str += luxFloat("uscale", luxProp(mat, key+".uscale", 1.0), -100.0, 100.0, "Us", "u-scale", gui, 0.5)
  3778         str += luxFloat("vscale", luxProp(mat, key+".vscale", -1.0), -100.0, 100.0, "Vs", "v-scale", gui, 0.5)
  3779         str += luxFloat("udelta", luxProp(mat, key+".udelta", 0.0), -100.0, 100.0, "Ud", "u-delta", gui, 0.5)
  3780         str += luxFloat("vdelta", luxProp(mat, key+".vdelta", 0.0), -100.0, 100.0, "Vd", "v-delta", gui, 0.5)
  3781     if mapping.get() == "planar":
  3782         str += luxFloat("udelta", luxProp(mat, key+".udelta", 0.0), -100.0, 100.0, "Ud", "u-delta", gui, 0.75)
  3783         str += luxFloat("vdelta", luxProp(mat, key+".vdelta", 0.0), -100.0, 100.0, "Vd", "v-delta", gui, 0.75)
  3784         if gui: gui.newline("v1:", -2, level+1, icon_map2dparam)
  3785         str += luxVector("v1", luxProp(mat, key+".v1", "1 0 0"), -100.0, 100.0, "v1", "v1-vector", gui, 2.0)
  3786         if gui: gui.newline("v2:", -2, level+1, icon_map2dparam)
  3787         str += luxVector("v2", luxProp(mat, key+".v2", "0 1 0"), -100.0, 100.0, "v2", "v2-vector", gui, 2.0)
  3788     return str
  3789 
  3790 def lux3DMapping(key, mat, gui, level=0):
  3791     global icon_map3dparam
  3792     str = ""
  3793     if gui: gui.newline("scale:", -2, level, icon_map3dparam)
  3794     str += luxVectorUniform("scale", luxProp(mat, key+".3dscale", 1.0), 0.001, 1000.0, "scale", "scale-vector", gui, 2.0)
  3795     if gui: gui.newline("rot:", -2, level, icon_map3dparam)
  3796     str += luxVector("rotate", luxProp(mat, key+".3drotate", "0 0 0"), -360.0, 360.0, "rotate", "rotate-vector", gui, 2.0)
  3797     if gui: gui.newline("move:", -2, level, icon_map3dparam)
  3798     str += luxVector("translate", luxProp(mat, key+".3dtranslate", "0 0 0"), -1000.0, 1000.0, "move", "translate-vector", gui, 2.0)
  3799     return str
  3800     
  3801 def getTreeNameById(tree, i): # helper function to retrive name of the selected treemenu-item
  3802     for t in tree:
  3803         if type(t)==types.TupleType:
  3804             if type(t[1])==types.ListType: 
  3805                 n=getTreeNameById(t[1], i)
  3806                 if n: return n
  3807             elif t[1]==i: return t[0]
  3808     return None    
  3809 
  3810 def luxTexture(name, parentkey, type, default, min, max, caption, hint, mat, gui, matlevel, texlevel=0, lightsource=0, overrideicon=""):
  3811     global icon_tex, icon_texcol, icon_texmix, icon_texmixcol, icon_texparam, icon_spectex
  3812     def c(t1, t2):
  3813         return (t1[0]+t2[0], t1[1]+t2[1])
  3814     def alternativedefault(type, default):
  3815         if type=="float": return 0.0
  3816         else: return "0.0 0.0 0.0"
  3817     level = matlevel + texlevel
  3818     keyname = "%s:%s"%(parentkey, name)
  3819     texname = "%s:%s"%(mat.getName(), keyname)
  3820 #    if gui: gui.newline(caption+":", 0, level)
  3821     if(lightsource == 0):
  3822         if texlevel == 0: texture = luxProp(mat, keyname+".texture", "imagemap")
  3823         else: texture = luxProp(mat, keyname+".texture", "constant")
  3824     else:
  3825         texture = luxProp(mat, keyname+".texture", "blackbody")
  3826 
  3827     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"]
  3828 
  3829     if gui:
  3830         if(overrideicon != ""):
  3831             icon = overrideicon
  3832         else:
  3833             icon = icon_tex
  3834             if texture.get() in ["mix", "scale", "checkerboard", "dots"]:
  3835                 if type=="color": icon = icon_texmixcol
  3836                 else: icon = icon_texmix
  3837             elif texture.get() in ["constant", "blackbody", "equalenergy", "frequency", "gaussian", "regulardata", "irregulardata"]:
  3838                 icon = icon_spectex
  3839             else:
  3840                 if type=="color": icon = icon_texcol
  3841                 else: icon = icon_tex
  3842         if (texlevel > 0): gui.newline(caption+":", -2, level, icon, scalelist([0.5,0.5,0.5],2.0/(level+2)))
  3843         else: gui.newline("texture:", -2, level, icon, scalelist([0.5,0.5,0.5],2.0/(level+2)))
  3844     luxOption("texture", texture, textures, "texture", "", gui, 2)
  3845     str = "Texture \"%s\" \"%s\" \"%s\""%(texname, type, texture.get())
  3846 
  3847     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))
  3848     if gui: # Draw Texture level Material preview
  3849         luxPreview(mat, parentkey, 1, False, False, name, gui, texlevel, [0.5, 0.5, 0.5])
  3850         # Add an offset for next controls
  3851         #r = gui.getRect(1.0, 1)
  3852         #gui.x += 140
  3853 
  3854     if texture.get() == "constant":
  3855         value = luxProp(mat, keyname+".value", default)
  3856         if type == "float": luxFloat("value", value, min, max, "", "", gui, 1.1)
  3857         elif type == "color": luxRGB("value", value, max, "", "", gui, 2)
  3858 # direct version
  3859         if type == "color": return ("", " \"%s %s\" [%s]"%(type, name, value.getRGC()))
  3860         return ("", " \"%s %s\" [%s]"%(type, name, value.get()))
  3861 # indirect version
  3862 #        if type == "color": str += " \"%s value\" [%s]"%(type, value.getRGC())
  3863 #        else: str += " \"%s value\" [%s]"%(type, value.get())
  3864 
  3865     if texture.get() == "blackbody":
  3866         if gui:
  3867             if gui.xmax-gui.x < gui.w: gui.newline()
  3868             r = gui.getRect(1.0, 1)
  3869             gui.newline()
  3870             drawBar(bar_blackbody, gui.xmax-gui.w-7, r[1])
  3871         str += luxFloat("temperature", luxProp(mat, keyname+".bbtemp", 6500.0), 1000.0, 10000.0, "temperature", "Black Body temperature in degrees Kelvin", gui, 2.0, 1)
  3872 
  3873     if texture.get() == "lampspectrum":
  3874         lampstring = luxProp(mat, keyname+".lampstring", "Incandescent2")
  3875         lamppreset = luxProp(mat, keyname+".lampspectrum", "PHILIPS [Argenta] 200W Incandescent Lamp")
  3876         if gui:
  3877             def setLamp(i, value, preset, tree, dict): # callback function to set ior value after selection
  3878                 if i >= 0:
  3879                     value.set(dict[i])
  3880                     preset.set(getTreeNameById(tree, i))
  3881 
  3882             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) ] ) ] 
  3883 
  3884             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" }
  3885 
  3886             r = gui.getRect(2.0, 1)
  3887             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))
  3888         str += luxString("name", lampstring, "Lamp", "Choose measured Lamp Spectrum", None, 2.0)
  3889 
  3890     if texture.get() == "equalenergy":
  3891         if gui:
  3892             if gui.xmax-gui.x < gui.w: gui.newline()
  3893             r = gui.getRect(1.0, 1)
  3894             gui.newline()
  3895             drawBar(bar_equalenergy, gui.xmax-gui.w-7, r[1])
  3896         str += luxFloat("energy", luxProp(mat, keyname+".energy", 1.0), 0.0, 1.0, "energy", "Energy of each spectral band", gui, 2.0, 1)
  3897 
  3898     if texture.get() == "frequency":
  3899         str += luxFloat("freq", luxProp(mat, keyname+".freq", 0.01), 0.01, 100.0, "frequency", "Frequency in nm", gui, 2.0, 1)
  3900         str += luxFloat("phase", luxProp(mat, keyname+".phase", 0.5), 0.0, 1.0, "phase", "Phase", gui, 1.1, 1)
  3901         str += luxFloat("energy", luxProp(mat, keyname+".energy", 1.0), 0.0, 1.0, "energy", "Amount of mean energy", gui, 0.9, 1)
  3902 
  3903     if texture.get() == "gaussian":
  3904         if gui:
  3905             if gui.xmax-gui.x < gui.w: gui.newline()
  3906             r = gui.getRect(1.0, 1)
  3907             gui.newline()
  3908             drawBar(bar_spectrum, gui.xmax-gui.w-7, r[1])
  3909         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)
  3910         str += luxFloat("width", luxProp(mat, keyname+".width", 50.0), 20.0, 300.0, "width", "Width of gaussian distribution in nm", gui, 1.1, 1)
  3911         str += luxFloat("energy", luxProp(mat, keyname+".energy", 1.0), 0.0, 1.0, "energy", "Amount of mean energy", gui, 0.9, 1)
  3912 
  3913     if texture.get() == "imagemap":
  3914         if gui: gui.newline("IM-clip:", -2, level)
  3915         str += luxOption("wrap", luxProp(mat, keyname+".wrap", "repeat"), ["repeat","black","clamp"], "repeat", "", gui, 1.0)
  3916 
  3917         if gui: gui.newline("IM-source:", -2, level)
  3918 
  3919         # ZANQDO
  3920         texturefilename = luxProp(mat, keyname+".filename", "")
  3921         extimage = luxProp(mat, keyname+'.externalimage', "true")
  3922         luxBool("External Image", extimage, "External Image", "External Image", gui, 1.0)
  3923         if gui: gui.newline("IM-path:", -2, level)
  3924         if extimage.get() == "true":
  3925             luxFile("filename", texturefilename, "file", "texture file path", gui, 2.0)
  3926         else:
  3927             bil = [i.filename for i in Image.Get() if '.' in i.filename]
  3928             try:
  3929                 uti = [i.filename for i in Image.Get() if '.' not in i.filename]
  3930                 if len(uti) > 0:
  3931                     luxLabel("INFO: Images not listed here must be saved first", gui)
  3932             except: pass    
  3933             if len(bil) > 0:
  3934                 luxOption("Image", texturefilename, bil, "Blender Images", "Blender Image", gui, 2.0)
  3935             else:
  3936                 luxLabel("No Blender Images - Load Image in the Image Editor", gui)
  3937         # dougal2 image file packing
  3938         impack = luxProp(Scene.GetCurrent(), 'packtextures', 'false')
  3939         
  3940         if impack.get() == 'false':
  3941             str += luxFile("filename", texturefilename, "file", "texture file path", None, 2.0)
  3942         else:
  3943             import zlib, base64
  3944             def get_image_data(filename):
  3945                 try:
  3946                     f=open(filename,'rb')
  3947                     d=f.read()
  3948                     f.close()
  3949                 except:
  3950                     print('Error reading image data from %s' % filename)
  3951                     d = ''
  3952                 return base64.b64encode(zlib.compress(d))
  3953             imdata = get_image_data(texturefilename.get())
  3954             str += '\r\n   "string imagedata" ["%s"]' % imdata
  3955         
  3956         useseq = luxProp(mat, keyname+".useseq", "false")
  3957         luxCollapse("usesew", useseq, "Sequence", "", gui, 2.0)
  3958     
  3959         if useseq.get() == "true":
  3960             seqframes = luxProp(mat, keyname+".seqframes", 100)
  3961             luxInt("frames", seqframes, 1, 100000, "Frames", "", gui, 0.5)
  3962             seqoffset = luxProp(mat, keyname+".seqoffset", 0)
  3963             luxInt("offset", seqoffset, 0, 100000, "Offset", "", gui, 0.5)
  3964             seqstartframe = luxProp(mat, keyname+".seqsframe", 1)
  3965             luxInt("startframe", seqstartframe, 1, 100000, "StartFr", "", gui, 0.5)
  3966             seqcyclic = luxProp(mat, keyname+".seqcycl", "false")
  3967             luxBool("cyclic", seqcyclic, "Cyclic", "", gui, 0.5)
  3968     
  3969             
  3970             totalframes = seqframes.get()
  3971             currentframe = Blender.Get('curframe')
  3972     
  3973             if(currentframe < seqstartframe.get()):
  3974                 fnumber = 1 + seqoffset.get()
  3975             else:
  3976                 fnumber = (currentframe - (seqstartframe.get()-1)) + seqoffset.get()
  3977     
  3978             if(fnumber > seqframes.get()):
  3979                 if(seqcyclic.get() == "false"):
  3980                     fnumber = seqframes.get()
  3981                 else:
  3982                     fnumber = currentframe % seqframes.get()
  3983     
  3984             import re
  3985             def get_seq_filename(number, filename):
  3986                 m = re.findall(r'(\d+)', filename)
  3987                 if len(m) == 0:
  3988                     return "ERR: Can't find pattern"
  3989     
  3990                 rightmost_number = m[len(m)-1]
  3991                 seq_length = len(rightmost_number)
  3992     
  3993                 nstr = "%i" %number
  3994                 new_seq_number = nstr.zfill(seq_length)
  3995      
  3996                 return filename.replace(rightmost_number, new_seq_number)
  3997      
  3998             texturefilename.set(get_seq_filename(fnumber, texturefilename.get()))
  3999             if gui: gui.newline()
  4000     
  4001         str += luxFloat("gamma", luxProp(mat, keyname+".gamma", texturegamma()), 0.0, 6.0, "gamma", "", gui, 0.75)
  4002         str += luxFloat("gain", luxProp(mat, keyname+".gain", 1.0), 0.0, 10.0, "gain", "", gui, 0.5)
  4003         filttype = luxProp(mat, keyname+".filtertype", "bilinear")
  4004         filttypes = ["mipmap_ewa","mipmap_trilinear","bilinear","nearest"]
  4005         str += luxOption("filtertype", filttype, filttypes, "filtertype", "Choose the filtering method to use for the image texture", gui, 0.75)
  4006         
  4007         if filttype.get() == "mipmap_ewa" or filttype.get() == "mipmap_trilinear":    
  4008             str += luxFloat("maxanisotropy", luxProp(mat, keyname+".maxanisotropy", 8.0), 1.0, 512.0, "maxaniso", "", gui, 1.0)
  4009             str += luxInt("discardmipmaps", luxProp(mat, keyname+".discardmipmaps", 0), 0, 1, "discardmips", "", gui, 1.0)
  4010     
  4011         str += luxMapping(keyname, mat, gui, level+1)
  4012 
  4013     if texture.get() == "mix":
  4014         (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))
  4015         (s, l) = c((s, l), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4016         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4017         str = s + str + l
  4018 
  4019     if texture.get() == "scale":
  4020         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4021         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4022         str = s + str + l
  4023 
  4024     if texture.get() == "bilerp":
  4025         if type == "float":
  4026             str += luxFloat("v00", luxProp(mat, keyname+".v00", 0.0), min, max, "v00", "", gui, 1.0)
  4027             str += luxFloat("v01", luxProp(mat, keyname+".v01", 1.0), min, max, "v01", "", gui, 1.0)
  4028             if gui: gui.newline("", -2)
  4029             str += luxFloat("v10", luxProp(mat, keyname+".v10", 0.0), min, max, "v10", "", gui, 1.0)
  4030             str += luxFloat("v11", luxProp(mat, keyname+".v11", 1.0), min, max, "v11", "", gui, 1.0)
  4031         elif type == "color":
  4032             if gui: gui.newline("          v00:", -2)
  4033             str += luxRGB("v00", luxProp(mat, keyname+".v00", "0.0 0.0 0.0"), max, "v00", "", gui, 2.0)
  4034             if gui: gui.newline("          v01:", -2)
  4035             str += luxRGB("v01", luxProp(mat, keyname+".v01", "1.0 1.0 1.0"), max, "v01", "", gui, 2.0)
  4036             if gui: gui.newline("          v10:", -2)
  4037             str += luxRGB("v10", luxProp(mat, keyname+".v10", "0.0 0.0 0.0"), max, "v10", "", gui, 2.0)
  4038             if gui: gui.newline("          v11:", -2)
  4039             str += luxRGB("v11", luxProp(mat, keyname+".v11", "1.0 1.0 1.0"), max, "v11", "", gui, 2.0)
  4040         str += luxMapping(keyname, mat, gui, level+1)
  4041 
  4042     if texture.get() == "windy":
  4043         str += lux3DMapping(keyname, mat, gui, level+1)
  4044         # this texture has no options 
  4045 
  4046     if texture.get() == "checkerboard":
  4047         dim = luxProp(mat, keyname+".dim", 2)
  4048         str += luxInt("dimension", dim, 2, 3, "dim", "", gui, 1)
  4049         if dim.get() == 2: str += luxOption("aamode", luxProp(mat, keyname+".aamode", "closedform"), ["closedform","supersample","none"], "aamode", "antialiasing mode", gui, 0.6)
  4050         if gui: gui.newline("", -2)
  4051         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4052         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4053         str = s + str + l
  4054         if dim.get() == 2: str += luxMapping(keyname, mat, gui, level+1) 
  4055         if dim.get() == 3: str += lux3DMapping(keyname, mat, gui, level+1)
  4056 
  4057     if texture.get() == "dots":
  4058         (s, l) = c(("", ""), luxTexture("inside", keyname, type, default, min, max, "inside", "", mat, gui, matlevel, texlevel+1, lightsource))
  4059         (s, l) = c((s, l), luxTexture("outside", keyname, type, alternativedefault(type, default), min, max, "outside", "", mat, gui, matlevel, texlevel+1, lightsource))
  4060         str = s + str + l
  4061         str += luxMapping(keyname, mat, gui, level+1)
  4062 
  4063     if texture.get() == "fbm":
  4064         str += luxInt("octaves", luxProp(mat, keyname+".octaves", 8), 1, 100, "octaves", "", gui, 1)
  4065         # if gui: gui.newline("", -2)
  4066         str += luxFloat("roughness", luxProp(mat, keyname+".roughness", 0.5), 0.0, 1.0, "roughness", "", gui, 1, 1)
  4067         if gui: gui.newline("", -2)
  4068         str += lux3DMapping(keyname, mat, gui, level+1)
  4069 
  4070     if texture.get() == "marble":
  4071         str += luxInt("octaves", luxProp(mat, keyname+".octaves", 8), 1, 100, "octaves", "", gui, 1)
  4072         # if gui: gui.newline("", -2)
  4073         str += luxFloat("roughness", luxProp(mat, keyname+".roughness", 0.5), 0.0, 1.0, "roughness", "", gui, 1, 1)
  4074         if gui: gui.newline("", -2)
  4075         str += luxFloat("nscale", luxProp(mat, keyname+".nscale", 1.0), 0.0, 100.0, "nscale", "Scaling factor for the noise input", gui, 1.0)
  4076         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)
  4077         if gui: gui.newline("", -2)
  4078         str += lux3DMapping(keyname, mat, gui, level+1)
  4079 
  4080     if texture.get() == "wrinkled":
  4081         str += luxInt("octaves", luxProp(mat, keyname+".octaves", 8), 1, 100, "octaves", "", gui, 1)
  4082         # if gui: gui.newline("", -2)
  4083         str += luxFloat("roughness", luxProp(mat, keyname+".roughness", 0.5), 0.0, 1.0, "roughness", "", gui, 1, 1)
  4084         if gui: gui.newline("", -2)
  4085         str += lux3DMapping(keyname, mat, gui, level+1)
  4086 
  4087     if texture.get() == "brick":
  4088         if gui: gui.newline("brick:", -2, level+1, icon_texparam)
  4089 
  4090         str += luxFloat("brickwidth", luxProp(mat, keyname+".brickwidth", 0.3), 0.0, 10.0, "brickwidth (X)", "", gui, 1.0)
  4091         str += luxFloat("brickheight", luxProp(mat, keyname+".brickheight", 0.1), 0.0, 10.0, "brickheight (Z)", "", gui, 1.0)
  4092         str += luxFloat("brickdepth", luxProp(mat, keyname+".brickdepth", 0.15), 0.0, 10.0, "brickdepth (Y)", "", gui, 1.0)
  4093 
  4094         if gui: gui.newline("mortar:", -2, level+1, icon_texparam)
  4095 
  4096         str += luxFloat("mortarsize", luxProp(mat, keyname+".mortarsize", 0.01), 0.0, 1.0, "mortarsize", "", gui, 1.0)
  4097 
  4098         (s, l) = c(("", ""), luxTexture("bricktex", keyname, type, default, min, max, "bricktex", "", mat, gui, matlevel, texlevel+1, lightsource))
  4099         (s, l) = c((s, l), luxTexture("mortartex", keyname, type, alternativedefault(type, default), min, max, "mortartex", "", mat, gui, matlevel, texlevel+1, lightsource))
  4100         str = s + str + l
  4101 
  4102         str += lux3DMapping(keyname, mat, gui, level+1)
  4103 
  4104     if texture.get() == "blender_marble":
  4105         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4106 
  4107         mtype = luxProp(mat, keyname+".mtype", "soft")
  4108         mtypes = ["soft","sharp","sharper"]
  4109         str += luxOption("type", mtype, mtypes, "type", "", gui, 0.5)
  4110 
  4111         noisetype = luxProp(mat, keyname+".noisetype", "hard_noise")
  4112         noisetypes = ["soft_noise","hard_noise"]
  4113         str += luxOption("noisetype", noisetype, noisetypes, "noisetypes", "", gui, 0.75)
  4114 
  4115         str += luxInt("noisedepth", luxProp(mat, keyname+".noisedepth", 2), 0, 6, "noisedepth", "", gui, 0.75)
  4116 
  4117         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4118         str += luxFloat("turbulance", luxProp(mat, keyname+".turbulance", 5.0), 0.0, 200.0, "turbulance", "", gui, 1.0)
  4119 
  4120         if gui: gui.newline("basis:", -2, level+1, icon_texparam)
  4121         noisebasis2 = luxProp(mat, keyname+".noisebasis2", "sin")
  4122         noisebasises2 = ["sin","saw","tri"]
  4123         str += luxOption("noisebasis2", noisebasis2, noisebasises2, "noisebasis2", "", gui, 0.7)
  4124 
  4125         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4126         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4127         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 1.3)
  4128 
  4129         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4130         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4131         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4132 
  4133         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4134         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4135         str = s + str + l
  4136 
  4137         str += lux3DMapping(keyname, mat, gui, level+1)
  4138 
  4139     if texture.get() == "blender_musgrave":
  4140         if gui: gui.newline("type:", -2, level+1, icon_texparam)
  4141         mtype = luxProp(mat, keyname+".mtype", "multifractal")
  4142         mtypes = ["multifractal","ridged_multifractal", "hybrid_multifractal", "hetero_terrain", "fbm"]
  4143         str += luxOption("type", mtype, mtypes, "type", "", gui, 2.0)
  4144 
  4145         str += luxFloat("h", luxProp(mat, keyname+".h", 1.0), 0.0, 2.0, "h", "", gui, 0.5)
  4146         str += luxFloat("lacu", luxProp(mat, keyname+".lacu", 2.0), 0.0, 6.0, "lacu", "", gui, 0.75)
  4147         str += luxFloat("octs", luxProp(mat, keyname+".octs", 2.0), 0.0, 8.0, "octs", "", gui, 0.75)
  4148 
  4149         if mtype.get() == "hetero_terrain":
  4150             str += luxFloat("offset", luxProp(mat, keyname+".offset", 2.0), 0.0, 6.0, "offset", "", gui, 2.0)
  4151         if mtype.get() == "ridged_multifractal":
  4152             str += luxFloat("offset", luxProp(mat, keyname+".offset", 2.0), 0.0, 6.0, "offset", "", gui, 1.25)
  4153             str += luxFloat("gain", luxProp(mat, keyname+".gain", 2.0), 0.0, 6.0, "gain", "", gui, 0.75)
  4154         if mtype.get() == "hybrid_multifractal":
  4155             str += luxFloat("offset", luxProp(mat, keyname+".offset", 2.0), 0.0, 6.0, "offset", "", gui, 1.25)
  4156             str += luxFloat("gain", luxProp(mat, keyname+".gain", 2.0), 0.0, 6.0, "gain", "", gui, 0.75)
  4157 
  4158         str += luxFloat("outscale", luxProp(mat, keyname+".outscale", 1.0), 0.0, 10.0, "iscale", "", gui, 1.0)
  4159         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4160 
  4161         if gui: gui.newline("basis:", -2, level+1, icon_texparam)
  4162         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4163         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4164         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 2.0)
  4165 
  4166         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4167         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4168         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4169 
  4170         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4171         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4172         str = s + str + l
  4173 
  4174         str += lux3DMapping(keyname, mat, gui, level+1)
  4175 
  4176     if texture.get() == "blender_wood":
  4177         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4178 
  4179         mtype = luxProp(mat, keyname+".mtype", "bands")
  4180         mtypes = ["bands","rings","bandnoise", "ringnoise"]
  4181         str += luxOption("type", mtype, mtypes, "type", "", gui, 0.5)
  4182 
  4183         noisetype = luxProp(mat, keyname+".noisetype", "hard_noise")
  4184         noisetypes = ["soft_noise","hard_noise"]
  4185         str += luxOption("noisetype", noisetype, noisetypes, "noisetypes", "", gui, 0.75)
  4186 
  4187         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4188         str += luxFloat("turbulance", luxProp(mat, keyname+".turbulance", 5.0), 0.0, 200.0, "turbulance", "", gui, 1.0)
  4189 
  4190         if gui: gui.newline("basis:", -2, level+1, icon_texparam)
  4191         noisebasis2 = luxProp(mat, keyname+".noisebasis2", "sin")
  4192         noisebasises2 = ["sin","saw","tri"]
  4193         str += luxOption("noisebasis2", noisebasis2, noisebasises2, "noisebasis2", "", gui, 0.7)
  4194 
  4195         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4196         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4197         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 1.3)
  4198 
  4199         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4200         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4201         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4202 
  4203         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4204         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4205         str = s + str + l
  4206     
  4207         str += lux3DMapping(keyname, mat, gui, level+1)
  4208 
  4209     if texture.get() == "blender_clouds":
  4210         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4211 
  4212         mtype = luxProp(mat, keyname+".mtype", "default")
  4213         mtypes = ["default","color"]
  4214         str += luxOption("type", mtype, mtypes, "type", "", gui, 0.5)
  4215 
  4216         noisetype = luxProp(mat, keyname+".noisetype", "hard_noise")
  4217         noisetypes = ["soft_noise","hard_noise"]
  4218         str += luxOption("noisetype", noisetype, noisetypes, "noisetypes", "", gui, 0.75)
  4219 
  4220         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4221         str += luxInt("noisedepth", luxProp(mat, keyname+".noisedepth", 2), 0, 6, "noisedepth", "", gui, 1.0)
  4222 
  4223         if gui: gui.newline("basis:", -2, level+1, icon_texparam)
  4224         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4225         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4226         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 1.3)
  4227 
  4228         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4229         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4230         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4231 
  4232         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4233         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4234         str = s + str + l
  4235     
  4236         str += lux3DMapping(keyname, mat, gui, level+1)
  4237 
  4238     if texture.get() == "blender_blend":
  4239         if gui: gui.newline("type:", -2, level+1, icon_texparam)
  4240 
  4241         mtype = luxProp(mat, keyname+".mtype", "lin")
  4242         mtypes = ["lin","quad","ease","diag","sphere","halo","radial"]
  4243         str += luxOption("type", mtype, mtypes, "type", "", gui, 0.5)
  4244         
  4245         mflag = luxProp(mat, keyname+".flag", "false")
  4246         str += luxBool("flipxy", mflag, "flipXY", "", gui, 0.5)
  4247 
  4248         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4249         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4250         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4251 
  4252         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4253         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4254         str = s + str + l
  4255         
  4256         str += lux3DMapping(keyname, mat, gui, level+1)
  4257 
  4258     if texture.get() == "blender_distortednoise":
  4259         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4260         
  4261         str += luxFloat("distamount", luxProp(mat, keyname+".distamount", 1.0), 0.0, 10.0, "distamount", "", gui, 1.0)
  4262         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4263         str += luxFloat("nabla", luxProp(mat, keyname+".nabla", 0.025), 0.000, 2.0, "nabla", "", gui, 1.0)
  4264         
  4265         if gui: gui.newline("distortion:", -2, level+1, icon_texparam)
  4266         ntype = luxProp(mat, keyname+".type", "blender_original")
  4267         ntypes = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4268         str += luxOption("type", ntype, ntypes, "type", "", gui, 1.3)
  4269         
  4270         if gui: gui.newline("basis:", -2, level+1, icon_texparam)
  4271         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4272         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4273         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 1.3)
  4274 
  4275         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4276         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4277         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4278 
  4279         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4280         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4281         str = s + str + l
  4282         
  4283         str += lux3DMapping(keyname, mat, gui, level+1)
  4284 
  4285     if texture.get() == "blender_noise":        
  4286         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4287         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4288         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4289 
  4290         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4291         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4292         str = s + str + l
  4293         
  4294         str += lux3DMapping(keyname, mat, gui, level+1)
  4295         
  4296     if texture.get() == "blender_magic":
  4297         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4298         
  4299         str += luxInt("noisedepth", luxProp(mat, keyname+".noisedepth", 2), 0.0, 10.0, "noisedepth", "", gui, 1.0)
  4300         str += luxFloat("turbulance", luxProp(mat, keyname+".turbulance", 5.0), 0.0, 2.0, "turbulance", "", gui, 1.0)
  4301 
  4302         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4303         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4304         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4305 
  4306         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4307         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4308         str = s + str + l
  4309         
  4310         str += lux3DMapping(keyname, mat, gui, level+1)
  4311         
  4312     if texture.get() == "blender_stucci":
  4313         if gui: gui.newline("noise:", -2, level+1, icon_texparam)
  4314         mtype = luxProp(mat, keyname+".mtype", "Plastic")
  4315         mtypes = ["Plastic","Wall In","Wall Out"]
  4316         str += luxOption("type", mtype, mtypes, "type", "", gui, 0.5)
  4317 
  4318         noisetype = luxProp(mat, keyname+".noisetype", "soft_noise")
  4319         noisetypes = ["soft_noise","hard_noise"]
  4320         str += luxOption("noisetype", noisetype, noisetypes, "noisetypes", "", gui, 0.75)
  4321         
  4322         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 10.0, "noisesize", "", gui, 1.0)
  4323         str += luxFloat("turbulance", luxProp(mat, keyname+".turbulance", 5.0), 0.0, 200.0, "turbulance", "", gui, 1.0)
  4324 
  4325         noisebasis = luxProp(mat, keyname+".noisebasis", "blender_original")
  4326         noisebasises = ["blender_original","original_perlin", "improved_perlin", "voronoi_f1", "voronoi_f2", "voronoi_f3", "voronoi_f4", "voronoi_f2f1", "voronoi_crackle", "cell_noise"]
  4327         str += luxOption("noisebasis", noisebasis, noisebasises, "noisebasis", "", gui, 1.3)
  4328 
  4329         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4330         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4331         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4332 
  4333         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4334         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4335         str = s + str + l
  4336 
  4337         str += lux3DMapping(keyname, mat, gui, level+1)
  4338 
  4339     if texture.get() == "blender_voronoi":
  4340         #if gui: gui.newline("distmetric:", -2, level+1, icon_texparam)
  4341         mtype = luxProp(mat, keyname+".distmetric", "actual_distance")
  4342         mtypes = ["actual_distance","distance_squared","manhattan", "chebychev", "minkovsky_half", "minkovsky_four", "minkovsky"]
  4343         str += luxOption("distmetric", mtype, mtypes, "distmetric", "", gui, 1.1)
  4344 
  4345         if gui: gui.newline("param:", -2, level+1, icon_texparam)
  4346         str += luxFloat("minkovsky_exp", luxProp(mat, keyname+".minkovsky_exp", 2.5), 0.001, 10.0, "minkovsky_exp", "", gui, 1.0)
  4347         str += luxFloat("outscale", luxProp(mat, keyname+".outscale", 1.0), 0.01, 10.0, "outscale", "", gui, 1.0)
  4348         str += luxFloat("noisesize", luxProp(mat, keyname+".noisesize", 0.25), 0.0, 2.0, "noisesize", "", gui, 1.0)
  4349         str += luxFloat("nabla", luxProp(mat, keyname+".nabla", 0.025), 0.001, 0.1, "nabla", "", gui, 1.0)
  4350         if gui: gui.newline("wparam:", -2, level+1, icon_texparam)
  4351         str += luxFloat("w1", luxProp(mat, keyname+".w1", 1.0), -2.0, 2.0, "w1", "", gui, 1.0)
  4352         str += luxFloat("w2", luxProp(mat, keyname+".w2", 0.0), -2.0, 2.0, "w2", "", gui, 1.0)
  4353         str += luxFloat("w3", luxProp(mat, keyname+".w3", 0.0), -2.0, 2.0, "w3", "", gui, 1.0)
  4354         str += luxFloat("w4", luxProp(mat, keyname+".w4", 0.0), -2.0, 2.0, "w4", "", gui, 1.0)
  4355 
  4356         if gui: gui.newline("level:", -2, level+1, icon_texparam)
  4357         str += luxFloat("bright", luxProp(mat, keyname+".bright", 1.0), 0.0, 2.0, "bright", "", gui, 1.0)
  4358         str += luxFloat("contrast", luxProp(mat, keyname+".contrast", 1.0), 0.0, 10.0, "contrast", "", gui, 1.0)
  4359 
  4360         (s, l) = c(("", ""), luxTexture("tex1", keyname, type, default, min, max, "tex1", "", mat, gui, matlevel, texlevel+1, lightsource))
  4361         (s, l) = c((s, l), luxTexture("tex2", keyname, type, alternativedefault(type, default), min, max, "tex2", "", mat, gui, matlevel, texlevel+1, lightsource))
  4362         str = s + str + l
  4363 
  4364         str += lux3DMapping(keyname, mat, gui, level+1)
  4365 
  4366 
  4367 
  4368     return (str+"\n", " \"texture %s\" [\"%s\"]"%(name, texname))
  4369 
  4370 
  4371 def luxSpectrumTexture(name, key, default, max, caption, hint, mat, gui, level=0):
  4372     global icon_col
  4373     if gui: gui.newline(caption, 4, level, icon_col, scalelist([0.5,0.6,0.5],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     link = luxRGB(name, value, max, "", hint, gui, 2.0)
  4379     tex = luxProp(mat, keyname+".textured", False)
  4380     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)]))
  4381     if tex.get()=="true":
  4382         if gui: gui.newline("", -2)
  4383         (str, link) = luxTexture(name, key, "color", default, 0, max, caption, hint, mat, gui, level+1)
  4384         if value.getRGB() != (1.0, 1.0, 1.0):
  4385             if str == "": # handle special case if texture is a just a constant
  4386                 str += "Texture \"%s\" \"color\" \"scale\" \"color tex1\" [%s] \"color tex2\" [%s]\n"%(texname+".scale", (link.rpartition("[")[2])[0:-1], value.get())
  4387             else: str += "Texture \"%s\" \"color\" \"scale\" \"texture tex1\" [\"%s\"] \"color tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4388             link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4389     return (str, link)
  4390 
  4391 def luxLightSpectrumTexture(name, key, default, max, caption, hint, mat, gui, level=0):
  4392     #if gui: gui.newline(caption, 4, level, icon_emission, scalelist([0.6,0.5,0.5],2.0/(level+2)))
  4393     str = ""
  4394     keyname = "%s:%s"%(key, name)
  4395     texname = "%s:%s"%(mat.getName(), keyname)
  4396     (str, link) = luxTexture(name, key, "color", default, 0, max, caption, hint, mat, gui, level+1, 0, 1)
  4397     return (str, link)
  4398 
  4399 def luxFloatTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4400     global icon_float
  4401     if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4402     str = ""
  4403     keyname = "%s:%s"%(key, name)
  4404     texname = "%s:%s"%(mat.getName(), keyname)
  4405     value = luxProp(mat, keyname, default)
  4406     link = luxFloat(name, value, min, max, "", hint, gui, 2.0)
  4407     tex = luxProp(mat, keyname+".textured", False)
  4408     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)]))
  4409     if tex.get()=="true":
  4410         if gui: gui.newline("", -2)
  4411         (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4412         if value.get() != 1.0:
  4413             if str == "": # handle special case if texture is a just a constant
  4414                 str += "Texture \"%s\" \"float\" \"scale\" \"float tex1\" [%s] \"float tex2\" [%s]\n"%(texname+".scale", (link.rpartition("[")[2])[0:-1], value.get())
  4415             else: str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4416             link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4417     return (str, link)
  4418 
  4419 def luxFloatSliderTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4420         global icon_float
  4421         if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4422         str = ""
  4423         keyname = "%s:%s"%(key, name)
  4424         texname = "%s:%s"%(mat.getName(), keyname)
  4425         value = luxProp(mat, keyname, default)
  4426         link = luxFloat(name, value, min, max, caption, hint, gui, 2.0, 1)
  4427         tex = luxProp(mat, keyname+".textured", False)
  4428         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)]))
  4429         if tex.get()=="true":
  4430                 if gui: gui.newline("", -2)
  4431                 (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4432                 if value.get() != 1.0:
  4433                         if str == "": # handle special case if texture is a just a constant
  4434                                 str += "Texture \"%s\" \"float\" \"scale\" \"float tex1\" [%s] \"float tex2\" [%s]\n"%(texname+".scale", (link.rpartition("[")[2])[0:-1], value.get())
  4435                         else: str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4436                         link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4437         return (str, link)
  4438 
  4439 
  4440 def luxExponentTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4441     global icon_float
  4442     if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4443     str = ""
  4444     keyname = "%s:%s"%(key, name)
  4445     texname = "%s:%s"%(mat.getName(), keyname)
  4446     value = luxProp(mat, keyname, default)
  4447 
  4448     if(value.get() == None): value.set(0.002)
  4449 
  4450 #    link = luxFloat(name, value, min, max, "", hint, gui, 2.0)
  4451     if gui:
  4452         r = gui.getRect(2.0, 1)
  4453         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))
  4454     link = " \"float %s\" [%f]"%(name, value.getFloat())
  4455 
  4456     tex = luxProp(mat, keyname+".textured", False)
  4457     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)]))
  4458     if tex.get()=="true":
  4459         if gui: gui.newline("", -2)
  4460         (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4461         if value.get() != 1.0:
  4462             if str == "": # handle special case if texture is a just a constant
  4463                 str += "Texture \"%s\" \"float\" \"scale\" \"float tex1\" [%s] \"float tex2\" [%s]\n"%(texname+".scale", (link.rpartition("[")[2])[0:-1], value.get())
  4464             else: str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4465             link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4466     return (str, link)
  4467 
  4468 
  4469 def luxDispFloatTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4470     global icon_float
  4471     if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4472     str = ""
  4473     keyname = "%s:%s"%(key, name)
  4474     texname = "%s:%s"%(mat.getName(), keyname)
  4475     value = luxProp(mat, keyname, default)
  4476     link = luxFloat(name, value, min, max, "", hint, gui, 2.0)
  4477     tex = luxProp(mat, keyname+".textured", False)
  4478     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)]))
  4479     if tex.get()=="true":
  4480         if gui: gui.newline("", -2)
  4481         (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4482         str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4483         link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4484     return (str, link)
  4485 
  4486 def luxIORFloatTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4487     # IOR preset data
  4488     iornames = ["0Z *** Gases @ 0 C ***", "01 - Vacuum", "02 - Air @ STP", "03 - Air", "04 - Helium", "05 - Hydrogen", "06 - Carbon dioxide",
  4489     "1Z *** LIQUIDS @ 20 C ***", "11 - Benzene", "12 - Water", "13 - Ethyl alcohol", "14 - Carbon tetrachloride", "15 - Carbon disulfide", 
  4490     "2Z *** SOLIDS at room temperature ***", "21 - Diamond", "22 - Strontium titanate", "23 - Amber", "24 - Fused silica glass", "25 - sodium chloride", 
  4491     "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"]
  4492     iorvals = [1.0, 1.0, 1.0002926, 1.000293, 1.000036, 1.000132, 1.00045,
  4493     1.501, 1.501, 1.333, 1.361, 1.461, 1.628,
  4494     2.419, 2.419, 2.41, 1.55, 1.458, 1.50,
  4495     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]
  4496 
  4497     global icon_float
  4498     if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4499     str = ""
  4500     keyname = "%s:%s"%(key, name)
  4501     texname = "%s:%s"%(mat.getName(), keyname)
  4502     value = luxProp(mat, keyname, default)
  4503 
  4504     iorusepreset = luxProp(mat, keyname+".iorusepreset", "true")
  4505     luxBool("iorusepreset", iorusepreset, "Preset", "Select from a list of predefined presets", gui, 0.4)
  4506 
  4507     if(iorusepreset.get() == "true"):
  4508         iorpreset = luxProp(mat, keyname+".iorpreset", "24 - Fused silica glass")
  4509         if gui:
  4510             def setIor(i, value, preset, tree, dict): # callback function to set ior value after selection                
  4511                 if i >= 0:
  4512                     value.set(dict[i])
  4513                     preset.set(getTreeNameById(tree, i))
  4514             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) ] ) ]
  4515             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}
  4516             r = gui.getRect(1.6, 1)
  4517             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))
  4518         link = luxFloat(name, value, min, max, "IOR", hint, None, 1.6)
  4519     else:
  4520         link = luxFloat(name, value, min, max, "IOR", hint, gui, 1.6, 1)
  4521 
  4522     tex = luxProp(mat, keyname+".textured", False)
  4523     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)]))
  4524     if tex.get()=="true":
  4525         if gui: gui.newline("", -2)
  4526         (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4527         if value.get() != 1.0:
  4528             str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4529             link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4530     return (str, link)
  4531 
  4532 def luxCauchyBFloatTexture(name, key, default, min, max, caption, hint, mat, gui, level=0):
  4533     # IOR preset data
  4534     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" ]
  4535     cauchybvals = [ 0.00354, 0.00420, 0.00459, 0.00531, 0.00743, 0.01342 ]
  4536 
  4537     global icon_float
  4538     if gui: gui.newline(caption, 4, level, icon_float, scalelist([0.5,0.5,0.6],2.0/(level+2)))
  4539     str = ""
  4540     keyname = "%s:%s"%(key, name)
  4541     texname = "%s:%s"%(mat.getName(), keyname)
  4542     value = luxProp(mat, keyname, default)
  4543 
  4544     cauchybusepreset = luxProp(mat, keyname+".cauchybusepreset", "true")
  4545     luxBool("cauchybusepreset", cauchybusepreset, "Preset", "Select from a list of predefined presets", gui, 0.4)
  4546 
  4547     if(cauchybusepreset.get() == "true"):
  4548         cauchybpreset = luxProp(mat, keyname+".cauchybpreset", "01 - Fused silica glass")
  4549         luxOption("cauchybpreset", cauchybpreset, cauchybnames, "  PRESET", "select CauchyB preset", gui, 1.6)
  4550         idx = cauchybnames.index(cauchybpreset.get())
  4551         value.set(cauchybvals[idx])
  4552         link = luxFloat(name, value, min, max, "cauchyb", hint, None, 1.6)
  4553     else:
  4554         link = luxFloat(name, value, min, max, "cauchyb", hint, gui, 1.6, 1)
  4555 
  4556     tex = luxProp(mat, keyname+".textured", False)
  4557     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)]))
  4558     if tex.get()=="true":
  4559         if gui: gui.newline("", -2)
  4560         (str, link) = luxTexture(name, key, "float", default, min, max, caption, hint, mat, gui, level+1)
  4561         if value.get() != 1.0:
  4562             str += "Texture \"%s\" \"float\" \"scale\" \"texture tex1\" [\"%s\"] \"float tex2\" [%s]\n"%(texname+".scale", texname, value.get())
  4563             link = " \"texture %s\" [\"%s\"]"%(name, texname+".scale")
  4564     return (str, link)
  4565 
  4566 def luxLight(name, kn, mat, gui, level):
  4567     if gui:
  4568         if name != "": gui.newline(name+":", 10, level)
  4569         else: gui.newline("color:", 0, level+1)
  4570     (str,link) = luxLightSpectrumTexture("L", kn+"light", "1.0 1.0 1.0", 1.0, "Spectrum", "", mat, gui, level+1)
  4571     if gui: gui.newline("")
  4572     link += luxFloat("power", luxProp(mat, kn+"light.power", 100.0), 0.0, 10000.0, "Power(W)", "AreaLight Power in Watts", gui)
  4573     link += luxFloat("efficacy", luxProp(mat, kn+"light.efficacy", 17.0), 0.0, 100.0, "Efficacy(lm/W)", "Efficacy Luminous flux/watt", gui)
  4574     if gui: gui.newline("")
  4575     link += luxFloat("gain", luxProp(mat, kn+"light.gain", 1.0), 0.0, 100.0, "gain", "Gain/scale multiplier", gui)
  4576     lightgroup = luxProp(mat, kn+"light.lightgroup", "default")
  4577     luxString("lightgroup", lightgroup, "group", "assign light to a named light-group", gui, 1.0)
  4578 
  4579     if gui: gui.newline("Photometric")
  4580     pm = luxProp(mat, kn+"light.usepm", "false")
  4581     luxCollapse("photometric", pm, "Photometric Diagram", "Enable Photometric Diagram options", gui, 2.0)
  4582 
  4583     if(pm.get()=="true"):
  4584         pmtype = luxProp(mat, kn+"light.pmtype", "IESna")
  4585         pmtypes = ["IESna", "imagemap"]
  4586         luxOption("type", pmtype, pmtypes, "type", "Choose Photometric data type to use", gui, 0.6)
  4587         if(pmtype.get() == "imagemap"):
  4588             map = luxProp(mat, kn+"light.pmmapname", "")
  4589             link += luxFile("mapname", map, "map-file", "filename of the photometric map", gui, 1.4)
  4590         if(pmtype.get() == "IESna"):
  4591             map = luxProp(mat, kn+"light.pmiesname", "")
  4592             link += luxFile("iesname", map, "ies-file", "filename of the IES photometric data file", gui, 1.4)
  4593 
  4594     has_bump_options = 0
  4595     has_object_options = 1
  4596     return (str, link)
  4597 
  4598 def luxLamp(name, kn, mat, gui, level):
  4599     if gui:
  4600         if name != "": gui.newline(name+":", 10, level)
  4601         else: gui.newline("color:", 0, level+1)
  4602 #    if gui: gui.newline("", 10, level)
  4603     (str,link) = luxLightSpectrumTexture("L", kn+"light", "1.0 1.0 1.0", 1.0, "Spectrum", "", mat, gui, level+1)
  4604     if gui: gui.newline("")
  4605     link += luxFloat("gain", luxProp(mat, kn+"light.gain", 1.0), 0.0, 100.0, "gain", "Gain/scale multiplier", gui)
  4606     lightgroup = luxProp(mat, kn+"light.lightgroup", "default")
  4607     luxString("lightgroup", lightgroup, "group", "assign light to a named light-group", gui, 1.0)
  4608 
  4609     if gui: gui.newline("Photometric")
  4610     pm = luxProp(mat, kn+"light.usepm", "false")
  4611     luxBool("photometric", pm, "Photometric Diagram", "Enable Photometric Diagram options", gui, 2.0)
  4612 
  4613     if(pm.get()=="true"):
  4614         pmtype = luxProp(mat, kn+"light.pmtype", "IESna")
  4615         pmtypes = ["IESna", "imagemap"]
  4616         luxOption("type", pmtype, pmtypes, "type", "Choose Photometric data type to use", gui, 0.6)
  4617         if(pmtype.get() == "imagemap"):
  4618             map = luxProp(mat, kn+"light.pmmapname", "")
  4619             link += luxFile("mapname", map, "map-file", "filename of the photometric map", gui, 1.4)
  4620         if(pmtype.get() == "IESna"):
  4621             map = luxProp(mat, kn+"light.pmiesname", "")
  4622             link += luxFile("iesname", map, "ies-file", "filename of the IES photometric data file", gui, 1.4)
  4623 
  4624         link += luxBool("flipz", luxProp(mat, kn+"light.flipZ", "true"), "Flip Z", "Flip Z direction in mapping", gui, 2.0)
  4625 
  4626     return (str, link)
  4627 
  4628 def luxSpot(name, kn, mat, gui, level):
  4629     if gui:
  4630         if name != "": gui.newline(name+":", 10, level)
  4631         else: gui.newline("color:", 0, level+1)
  4632 #    if gui: gui.newline("", 10, level)
  4633     (str,link) = luxLightSpectrumTexture("L", kn+"light", "1.0 1.0 1.0", 1.0, "Spectrum", "", mat, gui, level+1)
  4634     if gui: gui.newline("")
  4635     link += luxFloat("gain", luxProp(mat, kn+"light.gain", 1.0), 0.0, 100.0, "gain", "Gain/scale multiplier", gui)
  4636     lightgroup = luxProp(mat, kn+"light.lightgroup", "default")
  4637     luxString("lightgroup", lightgroup, "group", "assign light to a named light-group", gui, 1.0)
  4638 
  4639     if gui: gui.newline("Projection")
  4640     proj = luxProp(mat, kn+"light.usetexproj", "false")
  4641     luxBool("projection", proj, "Texture Projection", "Enable imagemap texture projection", gui, 2.0)
  4642 
  4643     if(proj.get() == "true"):
  4644         map = luxProp(mat, kn+"light.pmmapname", "")
  4645         link += luxFile("mapname", map, "map-file", "filename of the photometric map", gui, 2.0)
  4646 
  4647     return (str, link)
  4648 
  4649 
  4650 def Preview_Sphereset(mat, kn, state):
  4651     if state=="true":
  4652         luxProp(mat, kn+"prev_sphere", "true").set("true")
  4653         luxProp(mat, kn+"prev_plane", "false").set("false")
  4654         luxProp(mat, kn+"prev_torus", "false").set("false")
  4655 def Preview_Planeset(mat, kn, state):
  4656     if state=="true":
  4657         luxProp(mat, kn+"prev_sphere", "true").set("false")
  4658         luxProp(mat, kn+"prev_plane", "false").set("true")
  4659         luxProp(mat, kn+"prev_torus", "false").set("false")
  4660 def Preview_Torusset(mat, kn, state):
  4661     if state=="true":
  4662         luxProp(mat, kn+"prev_sphere", "true").set("false")
  4663         luxProp(mat, kn+"prev_plane", "false").set("false")
  4664         luxProp(mat, kn+"prev_torus", "false").set("true")
  4665 
  4666 
  4667     
  4668 
  4669 def Preview_Update(mat, kn, defLarge, defType, texName, name, level):
  4670     #print("%s %s %s %s %s %s %s" % (mat, kn, defLarge, defType, texName, name, level))
  4671 
  4672     global previewing
  4673     previewing = True
  4674     
  4675     Blender.Window.WaitCursor(True)
  4676     scn = Scene.GetCurrent()
  4677     
  4678     # set path mode to absolute for preview
  4679     pm_prop = luxProp(scn, "pathmode", "absolute")
  4680     pm = pm_prop.get()
  4681     pm_prop.set('absolute')
  4682     
  4683 
  4684     # Size of preview thumbnail
  4685     thumbres = 110 # default 110x110
  4686     if(defLarge):
  4687         large = luxProp(mat, kn+"prev_large", "true")
  4688     else:
  4689         large = luxProp(mat, kn+"prev_large", "false")
  4690     if(large.get() == "true"):
  4691         thumbres = 140 # small 140x140
  4692 
  4693     thumbbuf = thumbres*thumbres*3
  4694 
  4695 #        consolebin = luxProp(scn, "luxconsole", "").get()
  4696     
  4697     p = get_lux_pipe(scn, buf=thumbbuf, type="luxconsole")
  4698 
  4699     # Unremark to write debugging output to file
  4700     # p.stdin = open('c:\preview.lxs', 'w')
  4701 
  4702     if defType == 0:    
  4703         prev_sphere = luxProp(mat, kn+"prev_sphere", "true")
  4704         prev_plane = luxProp(mat, kn+"prev_plane", "false")
  4705         prev_torus = luxProp(mat, kn+"prev_torus", "false")
  4706     elif defType == 1:
  4707         prev_sphere = luxProp(mat, kn+"prev_sphere", "false")
  4708         prev_plane = luxProp(mat, kn+"prev_plane", "true")
  4709         prev_torus = luxProp(mat, kn+"prev_torus", "false")
  4710     else:
  4711         prev_sphere = luxProp(mat, kn+"prev_sphere", "false")
  4712         prev_plane = luxProp(mat, kn+"prev_plane", "false")
  4713         prev_torus = luxProp(mat, kn+"prev_torus", "true")
  4714 
  4715     # Zoom
  4716     if luxProp(mat, kn+"prev_zoom", "false").get() == "true":
  4717         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')
  4718     else:
  4719         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')
  4720     # Fleximage
  4721     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))
  4722     p.stdin.write('PixelFilter "sinc"\n')
  4723     # Quality
  4724     scn = Scene.GetCurrent()
  4725     defprevmat = luxProp(scn, "defprevmat", "high")
  4726     quality = luxProp(mat, kn+"prev_quality", defprevmat.get())
  4727     if quality.get()=="low":
  4728         p.stdin.write('Sampler "lowdiscrepancy" "string pixelsampler" ["hilbert"] "integer pixelsamples" [2]\n')
  4729     elif quality.get()=="medium":
  4730         p.stdin.write('Sampler "lowdiscrepancy" "string pixelsampler" ["hilbert"] "integer pixelsamples" [4]\n')
  4731     elif quality.get()=="high":
  4732         p.stdin.write('Sampler "lowdiscrepancy" "string pixelsampler" ["hilbert"] "integer pixelsamples" [8]\n')
  4733     else: 
  4734         p.stdin.write('Sampler "lowdiscrepancy" "string pixelsampler" ["hilbert"] "integer pixelsamples" [32]\n')
  4735     # SurfaceIntegrator
  4736     if(prev_plane.get()=="false"):
  4737         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')
  4738     else:
  4739         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')
  4740     # World
  4741     p.stdin.write('WorldBegin\n')
  4742     if(prev_sphere.get()=="true"):
  4743         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')
  4744     elif (prev_plane.get()=="true"):
  4745         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')
  4746     else:
  4747         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')
  4748     obwidth = luxProp(mat, kn+"prev_obwidth", 1.0)
  4749     obw = obwidth.get()
  4750     p.stdin.write('TransformBegin\n')
  4751     p.stdin.write('Scale %f %f %f\n'%(obw,obw,obw))
  4752     if texName:
  4753         print("texture "+texName+"  "+name)
  4754         (str, link) = luxTexture(texName, name, "color", "1.0 1.0 1.0", None, None, "", "", mat, None, 0, level)
  4755         link = link.replace(" "+texName+"\"", " Kd\"") # swap texture name to "Kd"
  4756         p.stdin.write(str+"\n")
  4757         p.stdin.write("Material \"matte\" "+link+"\n") 
  4758     else:
  4759         # Material
  4760         p.stdin.write(luxMaterial(mat))
  4761         link = luxProp(mat,"link","").get()
  4762         if kn!="": link = link.rstrip("\"")+":"+kn.strip(".:")+"\""
  4763         p.stdin.write(link+'\n')
  4764     p.stdin.write('TransformEnd\n')
  4765     # Shape
  4766     if(prev_sphere.get()=="true"):
  4767         p.stdin.write('Shape "sphere" "float radius" [1.0]\n')
  4768     elif (prev_plane.get()=="true"):
  4769         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')
  4770     elif (prev_torus.get()=="true"):
  4771         p.stdin.write('Shape "torus" "float radius" [1.0]\n')
  4772     p.stdin.write('AttributeEnd\n')
  4773     # Checkerboard floor
  4774     if(prev_plane.get()=="false"):
  4775         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')
  4776         p.stdin.write('Texture "checks" "color" "checkerboard"')
  4777         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]')
  4778         p.stdin.write('"string mapping" ["uv"] "float uscale" [36.8] "float vscale" [36.0]\n')
  4779         p.stdin.write('Material "matte" "texture Kd" ["checks"]\n')
  4780         p.stdin.write('Shape "loopsubdiv" "integer nlevels" [3] "bool dmnormalsmooth" ["true"] "bool dmsharpboundary" ["false"] ')
  4781         p.stdin.write('"integer indices" [ 0 1 2 0 2 3 1 0 4 1 4 5 5 4 6 5 6 7 ]')
  4782         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')
  4783         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')
  4784         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')
  4785         p.stdin.write('AttributeEnd\n')
  4786     # Lightsource
  4787     if(prev_plane.get()=="false"):
  4788         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')
  4789     else:
  4790         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')
  4791     area = luxProp(mat, kn+"prev_arealight", "false")
  4792     if(area.get() == "false"):
  4793         p.stdin.write('Texture "pL" "color" "blackbody" "float temperature" [6500.0]\n')
  4794         p.stdin.write('LightSource "point" "texture L" ["pL"] "float gain" [0.002]')
  4795     else:
  4796         p.stdin.write('ReverseOrientation\n')
  4797         p.stdin.write('AreaLightSource "area" "color L" [1.0 1.0 1.0]\n')
  4798         if(prev_plane.get()=="false"):
  4799             p.stdin.write(' "float gain" [0.3]\n')
  4800         p.stdin.write('Shape "disk" "float radius" [1.0]\nAttributeEnd\n')
  4801     p.stdin.write('WorldEnd\n')
  4802     
  4803     previewing = False
  4804 
  4805     data = p.communicate()[0]
  4806     p.stdin.close()
  4807     
  4808     # restore path mode
  4809     pm_prop.set(pm)    
  4810     
  4811     datalen = len(data)
  4812     if(datalen < thumbbuf): 
  4813         print("error on preview: got %i bytes, expected %i" % (datalen, thumbbuf))
  4814         return
  4815     global previewCache
  4816     image = luxImage()
  4817     image.decodeLuxConsole(thumbres, thumbres, data)
  4818     previewCache[(mat.name+":"+kn).__hash__()] = image
  4819     Draw.Redraw()
  4820     Blender.Window.WaitCursor(False)
  4821 
  4822 def luxPreview(mat, name, defType=0, defEnabled=False, defLarge=False, texName=None, gui=None, level=0, color=None):
  4823     
  4824 
  4825     if gui:
  4826         kn = name
  4827         if texName: kn += ":"+texName
  4828         if kn != "": kn += "."
  4829         if(defEnabled == True):
  4830             showpreview = luxProp(mat, kn+"prev_show", "true")
  4831         else:
  4832             showpreview = luxProp(mat, kn+"prev_show", "false")
  4833         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)]))
  4834         if showpreview.get()=="true": 
  4835             if(defLarge):
  4836                 large = luxProp(mat, kn+"prev_large", "true")
  4837             else:
  4838                 large = luxProp(mat, kn+"prev_large", "false")
  4839             voffset = -8
  4840             rr = 5.65 
  4841             if(large.get() == "true"):
  4842                 rr = 7
  4843                 voffset = 22
  4844             gui.newline()
  4845             r = gui.getRect(1.1, rr)
  4846             if(color != None):
  4847                 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)
  4848             try: previewCache[(mat.name+":"+kn).__hash__()].draw(r[0]-82, r[1]+4)
  4849             except: pass
  4850 
  4851             prev_sphere = luxProp(mat, kn+"prev_sphere", "true")
  4852             prev_plane = luxProp(mat, kn+"prev_plane", "false")
  4853             prev_torus = luxProp(mat, kn+"prev_torus", "false")
  4854             if defType == 1:
  4855                 prev_sphere = luxProp(mat, kn+"prev_sphere", "false")
  4856                 prev_plane = luxProp(mat, kn+"prev_plane", "true")
  4857                 prev_torus = luxProp(mat, kn+"prev_torus", "false")
  4858             elif defType == 2:
  4859                 prev_sphere = luxProp(mat, kn+"prev_sphere", "false")
  4860                 prev_plane = luxProp(mat, kn+"prev_plane", "false")
  4861                 prev_torus = luxProp(mat, kn+"prev_torus", "true")
  4862 
  4863             # preview mode toggle buttons
  4864             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)]))
  4865             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)]))
  4866             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)]))
  4867 
  4868             # Zoom toggle
  4869             zoom = luxProp(mat, kn+"prev_zoom", "false")
  4870             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)]))
  4871 
  4872             area = luxProp(mat, kn+"prev_arealight", "false")
  4873             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)]))
  4874 
  4875             # Object width
  4876             obwidth = luxProp(mat, kn+"prev_obwidth", 1.0)
  4877             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))
  4878 
  4879             # large/small size
  4880             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)]))
  4881 
  4882             # Preview Quality
  4883             qs = ["low","medium","high","very high"]
  4884             scn = Scene.GetCurrent()
  4885             defprevmat = luxProp(scn, "defprevmat", "high")
  4886             quality = luxProp(mat, kn+"prev_quality", defprevmat.get())
  4887             luxOptionRect("quality", quality, qs, "  Quality", "select preview quality", gui, r[0]+200, r[1]+100+voffset, 88, 18)
  4888 
  4889             # Update preview
  4890             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))
  4891 
  4892             # Reset depths after getRect()
  4893             gui.y -= 92+voffset
  4894             gui.y -= gui.h
  4895             gui.hmax = 18 + 4
  4896 
  4897 def luxMaterialBlock(name, luxname, key, mat, gui=None, level=0, str_opt=""):
  4898     global icon_mat, icon_matmix, icon_map3dparam
  4899     def c(t1, t2):
  4900         return (t1[0]+t2[0], t1[1]+t2[1])
  4901     str = ""
  4902     if key == "": keyname = kn = name
  4903     else: keyname = kn = "%s:%s"%(key, name)
  4904     if kn != "": kn += "."
  4905     if keyname == "": matname = mat.getName()
  4906     else: matname = "%s:%s"%(mat.getName(), keyname)
  4907 
  4908     if mat:
  4909         mattype = luxProp(mat, kn+"type", "matte")
  4910         # Set backwards compatibility of glossy material from plastic and substrate
  4911         if(mattype.get() == "substrate" or mattype.get() == "plastic"):
  4912             mattype.set("glossy")
  4913 
  4914         # this is reverse order than in shown in the dropdown list
  4915         materials = ["null","mix","mirror","shinymetal","metal","mattetranslucent","matte","glossy","roughglass","glass","carpaint"]
  4916         
  4917         if level == 0: materials = ["portal","light","boundvolume"]+materials
  4918         if gui:
  4919             icon = icon_mat
  4920             if mattype.get() == "mix": icon = icon_matmix
  4921             if level == 0: gui.newline("Material type:", 12, level, icon, [0.75,0.5,0.25])
  4922             else: gui.newline(name+":", 12, level, icon, scalelist([0.75,0.6,0.25],2.0/(level+2)))
  4923 
  4924 
  4925         link = luxOption("type", mattype, materials, "  TYPE", "select material type", gui)
  4926         showadvanced = luxProp(mat, kn+"showadvanced", "false")
  4927         luxBool("advanced", showadvanced, "Advanced", "Show advanced options", gui, 0.6)
  4928         showhelp = luxProp(mat, kn+"showhelp", "false")
  4929         luxHelp("help", showhelp, "Help", "Show Help Information", gui, 0.4)
  4930 
  4931         # show copy/paste menu button
  4932         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))
  4933 
  4934         # Draw Material preview option
  4935         showmatprev = False
  4936         if level == 0:
  4937             showmatprev = True
  4938         if gui: luxPreview(mat, keyname, 0, showmatprev, True, None, gui, level, [0.746, 0.625, 0.5])
  4939 
  4940 
  4941         if gui: gui.newline()
  4942         has_object_options   = 0 # disable object options by default
  4943         has_bump_options     = 0 # disable bump mapping options by default
  4944         has_emission_options = 0 # disable emission options by default
  4945         has_compositing_options = 0 # disable compositing options by default
  4946 
  4947         if mattype.get() == "mix":
  4948             (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))
  4949             (str,link) = c((str,link), luxMaterialBlock("mat1", "namedmaterial1", keyname, mat, gui, level+1))
  4950             (str,link) = c((str,link), luxMaterialBlock("mat2", "namedmaterial2", keyname, mat, gui, level+1))
  4951             has_bump_options = 0
  4952             has_object_options = 1
  4953             has_emission_options = 1
  4954             has_compositing_options = 0
  4955 
  4956         if mattype.get() == "light":
  4957             if luxProp(Scene.GetCurrent(), "nolg", "false").get()!="true":
  4958                 lightgroup = luxProp(mat, kn+"light.lightgroup", "default")
  4959                 link = "LightGroup \"%s\"\n"%lightgroup.get()
  4960             else:
  4961                 link = ''
  4962             link += "AreaLightSource \"area\""
  4963             (str,link) = c((str,link), luxLight("", kn, mat, gui, level))
  4964             has_bump_options = 0
  4965             has_object_options = 1
  4966             has_emission_options = 0
  4967             has_compositing_options = 1
  4968 
  4969         if mattype.get() == "boundvolume":
  4970             link = ""
  4971             voltype = luxProp(mat, kn+"vol.type", "homogeneous")
  4972             vols = ["homogeneous", "exponential", "cloud"]
  4973             vollink = luxOption("type", voltype, vols, "type", "", gui)
  4974             if voltype.get() == "homogeneous":
  4975                 link = "Volume \"homogeneous\""
  4976             if voltype.get() == "exponential":
  4977                 link = "Volume \"exponential\""
  4978             if voltype.get() == "cloud":
  4979                 link = "Volume \"cloud\""
  4980 
  4981             if gui: gui.newline("absorption:", 0, level+1)
  4982             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)
  4983             if gui: gui.newline("scattering:", 0, level+1)
  4984             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)
  4985             if gui: gui.newline("emission:", 0, level+1)
  4986             link += luxRGB("Le", luxProp(mat, kn+"vol.le", "0.0 0.0 0.0"), 1.0, "Le", "The volume's emission spectrum", gui)
  4987             if gui: gui.newline("assymetry:", 0, level+1)
  4988             link += luxFloat("g", luxProp(mat, kn+"vol.g", 0.0), 0.0, 100.0, "g", "The phase function asymmetry parameter", gui)
  4989 
  4990             if voltype.get() == "exponential":
  4991                 if gui: gui.newline("form:", 0, level+1)
  4992                 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)
  4993                 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)
  4994                 if gui: gui.newline("updir:", 0, level+1)
  4995                 link += luxVector("updir", luxProp(mat, kn+"vol.updir", "0 0 1"), -1.0, 1.0, "updir", "Up direction vector", gui, 2.0)
  4996 
  4997             if voltype.get() == "cloud":
  4998                 if gui: gui.newline("cloud:", 0, level+1)
  4999                 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)
  5000                 link += luxFloat("noisescale", luxProp(mat, kn+"vol.noisescale", 0.3), 0.1, 2.0, "noisesize", "Size of cloud noise", gui)
  5001                 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)
  5002                 link += luxFloat("noiseoffset", luxProp(mat, kn+"vol.noiseoffset", 0.0), 0.0, 1000.0, "noiseoffset", "Useful for creating unique clouds", gui )
  5003                 link += luxInt("octaves", luxProp(mat, kn+"vol.octaves", 3), 1, 8, "octaves", "Sets the amount of detail for the noise", gui )
  5004                 link += luxFloat("omega", luxProp(mat, kn+"vol.omega", 0.75), 0.1, 1.0, "omega", "Sets the scale difference of each successive octave", gui )
  5005                 link += luxFloat("sharpness", luxProp(mat, kn+"vol.sharpness", 6.0), 0.2, 10.0, "sharpness", "Sets the sharpness of the noise", gui)
  5006                 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)
  5007                 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)
  5008                 link += luxInt("spheres", luxProp(mat, kn+"vol.spheres", 2000), 0, 10000, "spheres", "Number of small spheres for cumulus shape. 0 is non-cumulus.", gui )
  5009                 link += luxFloat("spheresize", luxProp(mat, kn+"vol.spheresize", 0.15), 0.05, 0.55, "spheresize", "Size of cumulus spheres", gui)
  5010  
  5011             link += str_opt
  5012 
  5013             has_bump_options = 0
  5014             has_object_options = 0
  5015             has_emission_options = 0
  5016 
  5017             return (str, link)
  5018 
  5019         if mattype.get() == "carpaint":
  5020             if gui: gui.newline("Preset:", 0, level+1)
  5021             carname = luxProp(mat, kn+"carpaint.name", "Custom")
  5022             cars = ["Custom","ford f8","polaris silber","opel titan","bmw339","2k acrylack","white","blue","blue matte"]
  5023             carlink = luxOption("name", carname, cars, "name", "", gui)
  5024             if carname.get() == "Custom":
  5025                 (str,link) = c((str,link), luxSpectrumTexture("Kd", keyname, "1.0 1.0 1.0", 1.0, "diffuse", "", mat, gui, level+1))
  5026                 (str,link) = c((str,link), luxSpectrumTexture("Ks1", keyname, "1.0 1.0 1.0", 1.0, "specular1", "", mat, gui, level+1))
  5027                 (str,link) = c((str,link), luxSpectrumTexture("Ks2", keyname, "1.0 1.0 1.0", 1.0, "specular2", "", mat, gui, level+1))
  5028                 (str,link) = c((str,link), luxSpectrumTexture("Ks3", keyname, "1.0 1.0 1.0", 1.0, "specular3", "", mat, gui, level+1))
  5029                 (str,link) = c((str,link), luxFloatTexture("R1", keyname, 1.0, 0.0, 1.0, "R1", "", mat, gui, level+1))
  5030                 (str,link) = c((str,link), luxFloatTexture("R2", keyname, 1.0, 0.0, 1.0, "R2", "", mat, gui, level+1))
  5031                 (str,link) = c((str,link), luxFloatTexture("R3", keyname, 1.0, 0.0, 1.0, "R3", "", mat, gui, level+1))
  5032                 (str,link) = c((str,link), luxFloatTexture("M1", keyname, 1.0, 0.0, 1.0, "M1", "", mat, gui, level+1))
  5033                 (str,link) = c((str,link), luxFloatTexture("M2", keyname, 1.0, 0.0, 1.0, "M2", "", mat, gui, level+1))
  5034                 (str,link) = c((str,link), luxFloatTexture("M3", keyname, 1.0, 0.0, 1.0, "M3", "", mat, gui, level+1))
  5035             else: link += carlink
  5036             absorption = luxProp(mat, keyname+".useabsorption", "false")
  5037             luxCollapse("absorption", absorption, "Absorption", "Enable Coating Absorption", gui, 2.0)
  5038             if absorption.get() == "true":
  5039                 (str,link) = c((str,link), luxSpectrumTexture("Ka", keyname, "0.2 0.2 0.2", 1.0, "absorption", "", mat, gui, level+1))
  5040                 (str,link) = c((str,link), luxFloatTexture("d", keyname, 5.0, 0.0, 15.0, "depth", "", mat, gui, level+1))
  5041             has_bump_options = 1
  5042             has_object_options = 1
  5043             has_emission_options = 1
  5044             has_compositing_options = 1
  5045         
  5046         if mattype.get() == "glass":
  5047             (str,link) = c((str,link), luxSpectrumTexture("Kr", keyname, "1.0 1.0 1.0", 1.0, "reflection", "", mat, gui, level+1))
  5048             (str,link) = c((str,link), luxSpectrumTexture("Kt", keyname, "1.0 1.0 1.0", 1.0, "transmission", "", mat, gui, level+1))
  5049             (str,link) = c((str,link), luxIORFloatTexture("index", keyname, 1.5, 1.0, 6.0, "IOR", "", mat, gui, level+1))
  5050             architectural = luxProp(mat, keyname+".architectural", "false")
  5051             link += luxBool("architectural", architectural, "architectural", "Enable architectural glass", gui, 2.0)
  5052             if architectural.get() == "false":
  5053                 chromadisp = luxProp(mat, keyname+".chromadisp", "false")
  5054                 luxCollapse("chromadisp", chromadisp, "Dispersive Refraction", "Enable Chromatic Dispersion", gui, 2.0)
  5055                 if chromadisp.get() == "true":
  5056                     (str,link) = c((str,link), luxCauchyBFloatTexture("cauchyb", keyname, 0.0, 0.0, 1.0, "cauchyb", "", mat, gui, level+1))
  5057                 thinfilm = luxProp(mat, keyname+".thinfilm", "false")
  5058                 luxCollapse("thinfilm", thinfilm, "Thin Film Coating", "Enable Thin Film Coating", gui, 2.0)
  5059                 if thinfilm.get() == "true":
  5060                     (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))
  5061                     (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))
  5062             has_bump_options = 1
  5063             has_object_options = 1
  5064             has_emission_options = 1
  5065             has_compositing_options = 1
  5066             
  5067         if mattype.get() == "matte":
  5068             orennayar = luxProp(mat, keyname+".orennayar", "false")
  5069             (str,link) = c((str,link), luxSpectrumTexture("Kd", keyname, "1.0 1.0 1.0", 1.0, "diffuse", "", mat, gui, level+1))
  5070             luxCollapse("orennayar", orennayar, "Oren-Nayar", "Enable Oren-Nayar BRDF", gui, 2.0)
  5071             if orennayar.get() == "true":
  5072                 (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))
  5073             has_bump_options = 1
  5074             has_object_options = 1
  5075             has_emission_options = 1
  5076             has_compositing_options = 1
  5077         
  5078         if mattype.get() == "mattetranslucent":
  5079             orennayar = luxProp(mat, keyname+".orennayar", "false")
  5080             (str,link) = c((str,link), luxSpectrumTexture("Kr", keyname, "1.0 1.0 1.0", 1.0, "reflection", "", mat, gui, level+1))
  5081             (str,link) = c((str,link), luxSpectrumTexture("Kt", keyname, "1.0 1.0 1.0", 1.0, "transmission", "", mat, gui, level+1))
  5082             luxCollapse("orennayar", orennayar, "Oren-Nayar", "Enable Oren-Nayar BRDF", gui, 2.0)
  5083             if orennayar.get() == "true":
  5084                 (str,link) = c((str,link), luxFloatTexture("sigma", keyname, 0.0, 0.0, 100.0, "sigma", "", mat, gui, level+1))
  5085             has_bump_options = 1
  5086             has_object_options = 1
  5087             has_emission_options = 1
  5088             has_compositing_options = 1
  5089         
  5090         if mattype.get() == "metal":
  5091             if gui: gui.newline("name:", 0, level+1)
  5092             metalname = luxProp(mat, kn+"metal.name", "")
  5093             metals = ["aluminium","amorphous carbon","silver","gold","copper"]
  5094 
  5095             if not(metalname.get() in metals):
  5096                 metals.append(metalname.get())
  5097             metallink = luxOption("name", metalname, metals, "name", "", gui, 1.88)
  5098             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"))
  5099             link += luxstr(metallink)
  5100             anisotropic = luxProp(mat, kn+"metal.anisotropic", "false")
  5101             if gui:
  5102                 gui.newline("")
  5103                 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)]))
  5104             if anisotropic.get()=="true":
  5105                 (str,link) = c((str,link), luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "u-exponent", "", mat, gui, level+1))
  5106                 (str,link) = c((str,link), luxExponentTexture("vroughness", keyname, 0.002, 0.0, 1.0, "v-exponent", "", mat, gui, level+1))
  5107             else:
  5108                 (s, l) = luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "exponent", "", mat, gui, level+1)
  5109                 (str,link) = c((str,link), (s, l))
  5110                 link += l.replace("uroughness", "vroughness", 1)
  5111                 
  5112             has_bump_options = 1
  5113             has_object_options = 1
  5114             has_emission_options = 1
  5115             has_compositing_options = 1
  5116             
  5117         if mattype.get() == "mirror":
  5118             (str,link) = c((str,link), luxSpectrumTexture("Kr", keyname, "1.0 1.0 1.0", 1.0, "reflection", "", mat, gui, level+1))
  5119             thinfilm = luxProp(mat, keyname+".thinfilm", "false")
  5120             luxCollapse("thinfilm", thinfilm, "Thin Film Coating", "Enable Thin Film Coating", gui, 2.0)
  5121             if thinfilm.get() == "true":
  5122                 (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))
  5123                 (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))
  5124 
  5125             has_bump_options = 1
  5126             has_object_options = 1
  5127             has_emission_options = 1
  5128             has_compositing_options = 1
  5129             
  5130         if mattype.get() == "roughglass":
  5131             (str,link) = c((str,link), luxSpectrumTexture("Kr", keyname, "1.0 1.0 1.0", 1.0, "reflection", "", mat, gui, level+1))
  5132             (str,link) = c((str,link), luxSpectrumTexture("Kt", keyname, "1.0 1.0 1.0", 1.0, "transmission", "", mat, gui, level+1))
  5133             anisotropic = luxProp(mat, kn+"roughglass.anisotropic", "false")
  5134             if gui:
  5135                 gui.newline("")
  5136                 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)]))
  5137             if anisotropic.get()=="true":
  5138                 (str,link) = c((str,link), luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "u-exponent", "", mat, gui, level+1))
  5139                 (str,link) = c((str,link), luxExponentTexture("vroughness", keyname, 0.002, 0.0, 1.0, "v-exponent", "", mat, gui, level+1))
  5140             else:
  5141                 (s, l) = luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "exponent", "", mat, gui, level+1)
  5142                 (str,link) = c((str,link), (s, l))
  5143                 link += l.replace("uroughness", "vroughness", 1)
  5144             (str,link) = c((str,link), luxIORFloatTexture("index", keyname, 1.5, 1.0, 6.0, "IOR", "", mat, gui, level+1))
  5145             chromadisp = luxProp(mat, keyname+".chromadisp", "false")
  5146             luxCollapse("chromadisp", chromadisp, "Dispersive Refraction", "Enable Chromatic Dispersion", gui, 2.0)
  5147             if chromadisp.get() == "true":
  5148                 (str,link) = c((str,link), luxCauchyBFloatTexture("cauchyb", keyname, 0.0, 0.0, 1.0, "cauchyb", "", mat, gui, level+1))
  5149             has_bump_options = 1
  5150             has_object_options = 1
  5151             has_emission_options = 1
  5152             has_compositing_options = 1
  5153             
  5154         if mattype.get() == "shinymetal":
  5155             (str,link) = c((str,link), luxSpectrumTexture("Kr", keyname, "1.0 1.0 1.0", 1.0, "reflection", "", mat, gui, level+1))
  5156             (str,link) = c((str,link), luxSpectrumTexture("Ks", keyname, "1.0 1.0 1.0", 1.0, "specular", "", mat, gui, level+1))
  5157             anisotropic = luxProp(mat, kn+"shinymetal.anisotropic", "false")
  5158             if gui:
  5159                 gui.newline("")
  5160                 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)]))
  5161             if anisotropic.get()=="true":
  5162                 (str,link) = c((str,link), luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "u-exponent", "", mat, gui, level+1))
  5163                 (str,link) = c((str,link), luxExponentTexture("vroughness", keyname, 0.002, 0.0, 1.0, "v-exponent", "", mat, gui, level+1))
  5164             else:
  5165                 (s, l) = luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "exponent", "", mat, gui, level+1)
  5166                 (str,link) = c((str,link), (s, l))
  5167                 link += l.replace("uroughness", "vroughness", 1)
  5168 
  5169             thinfilm = luxProp(mat, keyname+".thinfilm", "false")
  5170             luxCollapse("thinfilm", thinfilm, "Thin Film Coating", "Enable Thin Film Coating", gui, 2.0)
  5171             if thinfilm.get() == "true":
  5172                 (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))
  5173                 (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))
  5174 
  5175             has_bump_options = 1
  5176             has_object_options = 1
  5177             has_emission_options = 1
  5178             has_compositing_options = 1
  5179             
  5180         if mattype.get() == "glossy":
  5181             (str,link) = c((str,link), luxSpectrumTexture("Kd", keyname, "1.0 1.0 1.0", 1.0, "diffuse", "", mat, gui, level+1))
  5182             useior = luxProp(mat, keyname+".useior", "false")
  5183             if gui:
  5184                 gui.newline("")
  5185                 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)]))
  5186             if useior.get() == "true":
  5187                 (str,link) = c((str,link), luxIORFloatTexture("index", keyname, 1.5, 1.0, 50.0, "IOR", "", mat, gui, level+1))
  5188                 link += " \"color Ks\" [1.0 1.0 1.0]"    
  5189             else:
  5190                 (str,link) = c((str,link), luxSpectrumTexture("Ks", keyname, "1.0 1.0 1.0", 1.0, "specular", "", mat, gui, level+1))
  5191                 link += " \"float index\" [0.0]"    
  5192             anisotropic = luxProp(mat, kn+"glossy.anisotropic", "false")
  5193             if gui:
  5194                 gui.newline("")
  5195                 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)]))
  5196             if anisotropic.get()=="true":
  5197                 (str,link) = c((str,link), luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "u-exponent", "", mat, gui, level+1))
  5198                 (str,link) = c((str,link), luxExponentTexture("vroughness", keyname, 0.002, 0.0, 1.0, "v-exponent", "", mat, gui, level+1))
  5199             else:
  5200                 (s, l) = luxExponentTexture("uroughness", keyname, 0.002, 0.0, 1.0, "exponent", "", mat, gui, level+1)
  5201                 (str,link) = c((str,link), (s, l))
  5202                 link += l.replace("uroughness", "vroughness", 1)
  5203 
  5204             absorption = luxProp(mat, keyname+".useabsorption", "false")
  5205             luxCollapse("absorption", absorption, "Absorption", "Enable Coating Absorption", gui, 2.0)
  5206             if absorption.get() == "true":
  5207                 (str,link) = c((str,link), luxSpectrumTexture("Ka", keyname, "0.2 0.2 0.2", 1.0, "absorption", "", mat, gui, level+1))
  5208                 (str,link) = c((str,link), luxFloatTexture("d", keyname, 0.15, 0.0, 15.0, "depth", "", mat, gui, level+1))
  5209             has_bump_options = 1
  5210             has_object_options = 1
  5211             has_emission_options = 1
  5212             has_compositing_options = 1
  5213             
  5214         if mattype.get() == 'null':
  5215             has_emission_options = 1
  5216 
  5217         # Bump mapping options (common)
  5218         if (has_bump_options == 1):
  5219             usebump = luxProp(mat, keyname+".usebump", "false")
  5220             luxCollapse("usebump", usebump, "Bump Map", "Enable Bump Mapping options", gui, 2.0)
  5221             if usebump.get() == "true":
  5222                 (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))
  5223 
  5224         # emission options (common)
  5225         if (level == 0):
  5226             if (has_emission_options == 1):
  5227                 if gui: gui.newline("", 2, level, None, [0.6,0.6,0.4])
  5228                 useemission = luxProp(mat, "emission", "false")
  5229                 luxCollapse("useemission", useemission, "Emission", "Enable emission options", gui, 2.0)
  5230                 if useemission.get() == "true":
  5231                     # emission GUI is here but lux export will be done later 
  5232                     luxLight("", "", mat, gui, level)
  5233             else: luxProp(mat, "emission", "false").set("false") # prevent from exporting later
  5234 
  5235 
  5236         # Compositing options (common)
  5237         # Note - currently only display options when using distributedpath integrator
  5238         integratortype = luxProp(Scene.GetCurrent(), "sintegrator.type", "bidirectional")
  5239         if (integratortype.get() == "distributedpath" and level == 0):
  5240             if (has_compositing_options == 1):
  5241                 if gui: gui.newline("", 2, level, None, [0.4,0.4,0.6])
  5242                 usecompo = luxProp(mat, "compo", "false")
  5243                 luxCollapse("compo", usecompo, "Compositing", "Enable Compositing options", gui, 2.0)
  5244                 if usecompo.get() == "true":
  5245                     if gui: gui.newline("", 2, level, None, [0.35,0.35,0.55])
  5246                     usecompoviz = luxProp(mat, "compo_viz", "false")
  5247                     luxCollapse("compo_viz", usecompoviz, "Visibility", "Enable Visibility Compositing options", gui, 2.0)
  5248                     if usecompoviz.get() == "true":
  5249                         if gui: gui.newline("View", 2, level, None, [0.35,0.35,0.55])
  5250                         compovizmat = luxProp(mat, "compo_viz_mat", "true")
  5251                         link += luxBool("compo_visible_material", compovizmat, "Material", "Enable View Visibility of Material", gui, 1.0)
  5252                         compovizemi = luxProp(mat, "compo_viz_emi", "true")
  5253                         link += luxBool("compo_visible_emission", compovizemi, "Emission", "Enable View Visibility of Emission", gui, 1.0)
  5254                         
  5255                         if gui: gui.newline("Indirect", 2, level, None, [0.35,0.35,0.55])
  5256                         compovizmati = luxProp(mat, "compo_viz_mati", "true")
  5257                         link += luxBool("compo_visible_indirect_material", compovizmati, "Material", "Enable InDirect Visibility of Material", gui, 1.0)
  5258                         compovizemii = luxProp(mat, "compo_viz_emii", "true")
  5259                         link += luxBool("compo_visible_indirect_emission", compovizemii, "Emission", "Enable InDirect Visibility of Emission", gui, 1.0)
  5260                     
  5261                     if gui: gui.newline("", 2, level, None, [0.4,0.4,0.6])
  5262                     overridealpha = luxProp(mat, "compo_o_alpha", "false")
  5263                     link += luxCollapse("compo_override_alpha", overridealpha, "Override Alpha", "Enable Manual control of alpha value", gui, 2.0)
  5264                     if overridealpha.get() == "true":
  5265                         if gui: gui.newline("Alpha", 2, level, None, [0.4,0.4,0.6])
  5266                         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)
  5267                     usecolorkey = luxProp(mat, "compo_usekey", "false")
  5268                     if gui: gui.newline("", 2, level, None, [0.35,0.35,0.55])
  5269                     link += luxCollapse("compo_use_key", usecolorkey, "Chroma Key", "Enable Chroma Object key", gui, 2.0)
  5270                     if usecolorkey.get() == "true":
  5271                         if gui: gui.newline("Key", 2, level, None, [0.35,0.35,0.55])
  5272                         link += luxRGB("compo_key_color", luxProp(mat, "compo_key_color", "0.0 0.0 1.0"), 1.0, "key", "", gui, 2.0)
  5273 
  5274         # transformation options (common)
  5275         if (level == 0) and mattype.get() not in ['portal', 'null']:
  5276             if gui: gui.newline("", 2, level, None, [0.6,0.6,0.4])
  5277             usetransformation = luxProp(mat, "transformation", "false")
  5278             luxCollapse("usetransformation", usetransformation, "Texture Transformation", "Enable transformation option", gui, 2.0)
  5279             if usetransformation.get() == "true":
  5280                 scale = luxProp(mat, "3dscale", 1.0)
  5281                 rotate = luxProp(mat, "3drotate", "0 0 0")
  5282                 translate = luxProp(mat, "3dtranslate", "0 0 0")
  5283                 if gui:
  5284                     gui.newline("scale:", -2, level, icon_map3dparam)
  5285                     luxVectorUniform("scale", scale, 0.001, 1000.0, "scale", "scale-vector", gui, 2.0)
  5286                     gui.newline("rot:", -2, level, icon_map3dparam)
  5287                     luxVector("rotate", rotate, -360.0, 360.0, "rotate", "rotate-vector", gui, 2.0)
  5288                     gui.newline("move:", -2, level, icon_map3dparam)
  5289                     luxVector("translate", translate, -1000.0, 1000.0, "move", "translate-vector", gui, 2.0)
  5290                 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"
  5291 
  5292         # Object options (common)
  5293         if (level == 0) and (has_object_options == 1):
  5294             if gui: gui.newline("Mesh:", 2, level, icon, [0.6,0.6,0.4])
  5295             usesubdiv = luxProp(mat, "subdiv", "false")
  5296             luxBool("usesubdiv", usesubdiv, "Subdivision", "Enable Loop Subdivision options", gui, 1.0)
  5297             usedisp = luxProp(mat, "dispmap", "false")
  5298             luxBool("usedisp", usedisp, "Displacement Map", "Enable Displacement mapping options", gui, 1.0)
  5299             if usesubdiv.get() == "true" or usedisp.get() == "true":
  5300                 luxInt("sublevels", luxProp(mat, "sublevels", 2), 0, 12, "sublevels", "The number of levels of object subdivision", gui, 2.0)
  5301                 sharpbound = luxProp(mat, "sharpbound", "false")
  5302                 luxBool("sharpbound", sharpbound, "Sharpen Bounds", "Sharpen boundaries during subdivision", gui, 1.0)
  5303                 nsmooth = luxProp(mat, "nsmooth", "true")
  5304                 luxBool("nsmooth", nsmooth, "Smooth", "Smooth faces during subdivision", gui, 1.0)
  5305             if usedisp.get() == "true":
  5306                 (str,ll) = c((str,link), luxDispFloatTexture("dispmap", keyname, 0.1, -10, 10.0, "dispmap", "Displacement Mapping amount", mat, gui, level+1))
  5307                 luxFloat("sdoffset",  luxProp(mat, "sdoffset", 0.0), 0.0, 1.0, "Offset", "Offset for displacement map", gui, 2.0)
  5308                 usesubdiv.set("true")
  5309 
  5310         if mattype.get() == "light":
  5311             return (str, link)
  5312 
  5313         str += "MakeNamedMaterial \"%s\"%s\n"%(matname, link)
  5314     return (str, " \"string %s\" [\"%s\"]"%(luxname, matname))
  5315 
  5316 
  5317 def luxMaterial(mat, gui=None):
  5318     str = ""
  5319     if mat:
  5320         if luxProp(mat, "type", "").get()=="": # lux material not defined yet
  5321             print("Blender material \"%s\" has no lux material definition, converting..."%(mat.getName()))
  5322             try:
  5323                 convertMaterial(mat) # try converting the blender material to a lux material
  5324             except: pass
  5325         (str, link) = luxMaterialBlock("", "", "", mat, gui, 0)
  5326         if luxProp(mat, "type", "matte").get() != "light":
  5327             link = "NamedMaterial \"%s\""%(mat.getName())
  5328         # export emission options (no gui)
  5329         useemission = luxProp(mat, "emission", "false")
  5330         if useemission.get() == "true":
  5331             lightgroup = luxProp(mat, "light.lightgroup", "default")
  5332             if luxProp(Scene.GetCurrent(), "nolg", "false").get()!="true":
  5333                 link += "\n\tLightGroup \"%s\"\n"%lightgroup.get()
  5334             
  5335             (estr, elink) = luxLight("", "", mat, None, 0)
  5336             str += estr
  5337             link += "\n\tAreaLightSource \"area\" "+elink 
  5338             
  5339         luxProp(mat, "link", "").set("".join(link))
  5340         
  5341     return str
  5342         
  5343 
  5344 def luxVolume(mat, gui=None):
  5345     str = ""
  5346     if mat:
  5347         (str, link) = luxMaterialBlock("", "", "", mat, gui, 0)
  5348         luxProp(mat, "link", "").set("".join(link))
  5349     return str
  5350 
  5351 runRenderAfterExport = None
  5352 def CBluxExport(default, run):
  5353     global runRenderAfterExport
  5354     runRenderAfterExport = run
  5355     if default:
  5356         datadir = luxProp(Scene.GetCurrent(), "datadir", "").get()
  5357         if datadir=="": datadir = Blender.Get("datadir")
  5358         import os.path
  5359         if not os.path.exists(datadir):
  5360             Draw.PupMenu("ERROR: output directory does not exist!")
  5361             if LuxIsGUI:
  5362                 Draw.Redraw()
  5363             return
  5364         filename = datadir + os.sep + "default.lxs"
  5365         save_still(filename)
  5366     else:
  5367         Window.FileSelector(save_still, "Export", sys.makename(Blender.Get("filename"), ".lxs"))
  5368 
  5369 
  5370 def CBluxAnimExport(default, run, fileselect=True):
  5371     if default:
  5372         datadir = luxProp(Scene.GetCurrent(), "datadir", "").get()
  5373         if datadir=="": datadir = Blender.Get("datadir")
  5374         import os.path
  5375         if not os.path.exists(datadir):
  5376             Draw.PupMenu("ERROR: output directory does not exist!")
  5377             if LuxIsGUI:
  5378                 Draw.Redraw()
  5379             return
  5380         filename = datadir + os.sep + "default.lxs"
  5381         save_anim(filename)
  5382     else:
  5383         if fileselect:
  5384             Window.FileSelector(save_anim, "Export", sys.makename(Blender.Get("filename"), ".lxs"))
  5385         else:
  5386             datadir = luxProp(Scene.GetCurrent(), "datadir", "").get()
  5387             if datadir=="": datadir = Blender.Get("datadir")
  5388             filename = sys.makename(Blender.Get("filename") , ".lxs")
  5389             save_anim(filename)
  5390 
  5391 
  5392 # convert a Blender material to lux material
  5393 def convertMaterial(mat):
  5394     def dot(str):
  5395         if str != "": return str+"."
  5396         return str
  5397     def ddot(str):
  5398         if str != "": return str+":"
  5399         return str
  5400     def mapConstDict(value, constant_dict, lux_dict, default=None):
  5401         for k,v in constant_dict.items():
  5402             if (v == value) and (lux_dict.has_key(k)):
  5403                 return lux_dict[k]
  5404         return default
  5405 
  5406     def convertMapping(name, tex):
  5407         if tex.texco == Texture.TexCo["UV"]:
  5408             luxProp(mat, dot(name)+"mapping","").set("uv")
  5409             luxProp(mat, dot(name)+"uscale", 1.0).set(tex.size[0])
  5410             luxProp(mat, dot(name)+"vscale", 1.0).set(-tex.size[1])
  5411             luxProp(mat, dot(name)+"udelta", 0.0).set(tex.ofs[0]+0.5*(1.0-tex.size[0]))
  5412             luxProp(mat, dot(name)+"vdelta", 0.0).set(-tex.ofs[1]-0.5*(1.0-tex.size[1]))
  5413             if tex.mapping != Texture.Mappings["FLAT"]:
  5414                 print("Material Conversion Warning: for UV-texture-input only FLAT mapping is supported\n") 
  5415         else:
  5416             if tex.mapping == Texture.Mappings["FLAT"]:
  5417                 luxProp(mat, dot(name)+"mapping","").set("planar") # make planar-mapping convert correctly from blender(WYSIWYG)- jens
  5418                 luxProp(mat, dot(name)+"v1", "1.0 1.0 1.0").setVector((0.5*tex.size[0], 0.0, 0.0))
  5419                 luxProp(mat, dot(name)+"v2", "0.0 0.0 0.0").setVector((0.0, -0.5*tex.size[1], -0.0))
  5420                 luxProp(mat, dot(name)+"udelta", 0.0).set(tex.ofs[0]+0.5)
  5421                 luxProp(mat, dot(name)+"vdelta", 0.0).set(-tex.ofs[1]-0.5)
  5422             elif tex.mapping == Texture.Mappings["TUBE"]:
  5423                 luxProp(mat, dot(name)+"mapping","").set("cylindrical")
  5424             elif tex.mapping == Texture.Mappings["SPHERE"]:
  5425                 luxProp(mat, dot(name)+"mapping","").set("spherical")
  5426             else: luxProp(mat, dot(name)+"mapping","").set("planar")
  5427 
  5428         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]))
  5429         luxProp(mat, dot(name)+"3dtranslate", "0.0 0.0 0.0").setVector((-tex.ofs[0], -tex.ofs[1], -tex.ofs[2]))
  5430 
  5431     def convertColorband(colorband):
  5432         # colorbands are not supported in lux - so lets extract a average low-side and high-side color
  5433         cb = [colorband[0]] + colorband[:] + [colorband[-1]]
  5434         cb[0][4], cb[-1][4] = 0.0, 1.0
  5435         low, high = [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]
  5436         for i in range(1, len(cb)):
  5437             for c in range(4):
  5438                 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])
  5439                 high[c] += (cb[i-1][c]*cb[i-1][4] + cb[i][c]*cb[i][4]) * (cb[i][4]-cb[i-1][4])
  5440         return low, high
  5441 
  5442     def createLuxTexture(name, tex):
  5443         texture = tex.tex
  5444         convertMapping(name, tex)
  5445         if (texture.type == Texture.Types["IMAGE"]) and (texture.image) and (texture.image.filename!=""):
  5446             luxProp(mat, dot(name)+"texture", "").set("imagemap")
  5447             luxProp(mat, dot(name)+"filename", "").set(texture.image.filename)
  5448             luxProp(mat, dot(name)+"wrap", "").set(mapConstDict(texture.extend, Texture.ExtendModes, {"REPEAT":"repeat", "EXTEND":"clamp", "CLIP":"black"}, ""))
  5449         else:
  5450             if tex.texco != Texture.TexCo["GLOB"]:
  5451                 print("Material Conversion Warning: procedural textures supports global mapping only\n")
  5452             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"}
  5453             luxProp(mat, dot(name)+"bright", 1.0).set(texture.brightness)
  5454             luxProp(mat, dot(name)+"contrast", 1.0).set(texture.contrast)
  5455             if texture.type == Texture.Types["CLOUDS"]:
  5456                 luxProp(mat, dot(name)+"texture", "").set("blender_clouds")
  5457                 luxProp(mat, dot(name)+"mtype", "").set(mapConstDict(texture.stype, Texture.STypes, {"CLD_DEFAULT":"default", "CLD_COLOR":"color"}, ""))
  5458                 luxProp(mat, dot(name)+"noisetype", "").set({"soft":"soft_noise", "hard":"hard_noise"}[texture.noiseType])
  5459                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5460                 luxProp(mat, dot(name)+"noisedepth", 2).set(texture.noiseDepth)
  5461                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5462             elif texture.type == Texture.Types["WOOD"]:
  5463                 luxProp(mat, dot(name)+"texture", "").set("blender_wood")
  5464                 luxProp(mat, dot(name)+"mtype", "").set(mapConstDict(texture.stype, Texture.STypes, {"WOD_BANDS":"bands", "WOD_RINGS":"rings", "WOD_BANDNOISE":"bandnoise", "WOD_RINGNOISE":"ringnoise"}, ""))
  5465                 luxProp(mat, dot(name)+"noisebasis2", "").set(mapConstDict(texture.noiseBasis2, Texture.Noise, {"SINE":"sin", "SAW":"saw", "TRI":"tri"}, ""))
  5466                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5467                 luxProp(mat, dot(name)+"noisetype", "").set({"soft":"soft_noise", "hard":"hard_noise"}[texture.noiseType])
  5468                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5469                 luxProp(mat, dot(name)+"turbulance", 0.25).set(texture.turbulence)
  5470             elif texture.type == Texture.Types["MUSGRAVE"]:
  5471                 luxProp(mat, dot(name)+"texture", "").set("blender_musgrave")
  5472                 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"}, ""))
  5473                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5474                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5475                 # 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)
  5476                 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
  5477                 else: luxProp(mat, dot(name)+"h", 1.0).set(0.5) # use a default value
  5478                 # bug in blender python API: values "offset" and "gain" are missing in Python-API (reported to Ideasman42 - will be fixed after Blender 2.47)
  5479                 try:
  5480                     luxProp(mat, dot(name)+"offset", 1.0).set(texture.offset)
  5481                     luxProp(mat, dot(name)+"gain", 1.0).set(texture.gain)
  5482                 except AttributeError: pass
  5483                 luxProp(mat, dot(name)+"lacu", 2.0).set(texture.lacunarity)
  5484                 luxProp(mat, dot(name)+"octs", 2.0).set(texture.octs)
  5485                 luxProp(mat, dot(name)+"outscale", 1.0).set(texture.iScale)
  5486             elif texture.type == Texture.Types["MARBLE"]:
  5487                 luxProp(mat, dot(name)+"texture", "").set("blender_marble")
  5488                 luxProp(mat, dot(name)+"mtype", "").set(mapConstDict(texture.stype, Texture.STypes, {"MBL_SOFT":"soft", "MBL_SHARP":"sharp", "MBL_SHARPER":"sharper"}, ""))
  5489                 luxProp(mat, dot(name)+"noisetype", "").set({"soft":"soft_noise", "hard":"hard_noise"}[texture.noiseType])
  5490                 luxProp(mat, dot(name)+"turbulance", 0.25).set(texture.turbulence)
  5491                 luxProp(mat, dot(name)+"noisedepth", 2).set(texture.noiseDepth)
  5492                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5493                 luxProp(mat, dot(name)+"noisebasis2", "").set(mapConstDict(texture.noiseBasis2, Texture.Noise, {"SINE":"sin", "SAW":"saw", "TRI":"tri"}, ""))
  5494                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5495             elif texture.type == Texture.Types["VORONOI"]:
  5496                 luxProp(mat, dot(name)+"texture", "").set("blender_voronoi")
  5497                 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])
  5498                 luxProp(mat, dot(name)+"outscale", 1.0).set(texture.iScale)
  5499                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5500                 luxProp(mat, dot(name)+"minkosky_exp", 2.5).set(texture.exp)
  5501                 luxProp(mat, dot(name)+"w1", 1.0).set(texture.weight1)
  5502                 luxProp(mat, dot(name)+"w2", 0.0).set(texture.weight2)
  5503                 luxProp(mat, dot(name)+"w3", 0.0).set(texture.weight3)
  5504                 luxProp(mat, dot(name)+"w4", 0.0).set(texture.weight4)
  5505             elif texture.type == Texture.Types["NOISE"]:
  5506                 luxProp(mat, dot(name)+"texture", "").set("blender_noise")
  5507             elif texture.type == Texture.Types["DISTNOISE"]:
  5508                 luxProp(mat, dot(name)+"texture", "").set("blender_distortednoise")
  5509                 luxProp(mat, dot(name)+"distamount", 1.0).set(texture.distAmnt)
  5510                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5511                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5512                 luxProp(mat, dot(name)+"noisebasis2", "").set(mapConstDict(texture.noiseBasis2, Texture.Noise, noiseDict, ""))
  5513             elif texture.type == Texture.Types["MAGIC"]:
  5514                 luxProp(mat, dot(name)+"texture", "").set("blender_magic")
  5515                 luxProp(mat, dot(name)+"turbulance", 0.25).set(texture.turbulence)
  5516                 luxProp(mat, dot(name)+"noisedepth", 2).set(texture.noiseDepth)
  5517             elif texture.type == Texture.Types["STUCCI"]:
  5518                 luxProp(mat, dot(name)+"texture", "").set("blender_stucci")
  5519                 luxProp(mat, dot(name)+"mtype", "").set(mapConstDict(texture.stype, Texture.STypes, {"STC_PLASTIC":"Plastic", "MSTC_WALLIN":"Wall In", "STC_WALLOUT":"Wall Out"}, ""))
  5520                 luxProp(mat, dot(name)+"noisetype", "").set({"soft":"soft_noise", "hard":"hard_noise"}[texture.noiseType])
  5521                 luxProp(mat, dot(name)+"noisesize", 0.25).set(texture.noiseSize)
  5522                 luxProp(mat, dot(name)+"turbulance", 0.25).set(texture.turbulence)
  5523                 luxProp(mat, dot(name)+"noisebasis", "").set(mapConstDict(texture.noiseBasis, Texture.Noise, noiseDict, ""))
  5524             elif texture.type == Texture.Types["BLEND"]:
  5525                 luxProp(mat, dot(name)+"texture", "").set("blender_blend")
  5526                 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"}, ""))
  5527                 luxProp(mat, dot(name)+"flipXY", "false").set({0:"false", 1:"true"}[texture.rot90])
  5528             else:
  5529                 print("Material Conversion Warning: SORRY, this procedural texture isn\'t implemented in conversion\n")
  5530 
  5531     def convertTextures(basename, texs, type="float", channel="col", val=1.0):
  5532         tex = texs.pop()
  5533         texture = tex.tex
  5534         isImagemap = (texture.type == Texture.Types["IMAGE"]) and (texture.image) and (texture.image.filename!="")
  5535         if channel == "col":
  5536             if texture.flags & Texture.Flags["COLORBAND"] > 0:
  5537                 cbLow, cbHigh = convertColorband(texture.colorband)
  5538                 val1, alpha1, val2, alpha2 = (cbLow[0],cbLow[1],cbLow[2]), cbLow[3]*tex.colfac, (cbHigh[0], cbHigh[1], cbHigh[2]), cbHigh[3]*tex.colfac
  5539                 if tex.noRGB:
  5540                     lum1, lum2 = (val1[0]+val1[1]+val1[2])/3.0, (val2[0]+val2[1]+val2[2])/3.0
  5541                     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)
  5542             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
  5543             else: val1, alpha1, val2, alpha2 = tex.col, 0.0, tex.col, tex.colfac
  5544         elif channel == "nor": val1, alpha1, val2, alpha2 = tex.norfac * 0.01, 0.0, tex.norfac * 0.01, 1.0
  5545         else: val1, alpha1, val2, alpha2 = 1.0, 0.0, 1.0, tex.varfac
  5546         if (tex.neg)^((channel=="nor") and (tex.mtNor<0)): val1, alpha1, val2, alpha2 = val2, alpha2, val1, alpha1
  5547         luxProp(mat, dot(basename)+"textured", "").set("true")
  5548 
  5549         name = basename
  5550         if (alpha1 < 1.0) or (alpha2 < 1.0): # texture with transparency
  5551             luxProp(mat, dot(basename)+"texture", "").set("mix")
  5552             if alpha1 == alpha2: # constant alpha
  5553                 luxProp(mat, ddot(basename)+"amount.value", 1.0).set(alpha1)
  5554             else:
  5555                 createLuxTexture(ddot(basename)+"amount", tex)
  5556                 luxProp(mat, ddot(basename)+"amount:tex1.value", 1.0).set(alpha1)
  5557                 luxProp(mat, ddot(basename)+"amount:tex2.value", 1.0).set(alpha2)
  5558             # transparent to next texture
  5559             name = ddot(basename)+"tex1"
  5560             if len(texs) > 0:
  5561                 convertTextures(ddot(basename)+"tex1", texs, type, channel, val)
  5562             else:
  5563                 if type=="float": luxProp(mat, ddot(basename)+"tex1.value", 1.0).set(val)
  5564                 else: luxProp(mat, ddot(basename)+"tex1.value", "1.0 1.0 1.0").setRGB((val[0], val[1], val[2]))
  5565             name = ddot(basename)+"tex2"
  5566         if val1 == val2: # texture with different colors / value
  5567             if type == "col": luxProp(mat, dot(name)+"value", "1.0 1.0 1.0").setRGB(val1)
  5568             else: luxProp(mat, dot(name)+"value", 1.0).set(val1)
  5569         else:
  5570             createLuxTexture(name, tex)
  5571             if type == "col": luxProp(mat, ddot(name)+"tex1.value", "1.0 1.0 1.0").setRGB(val1)
  5572             else: luxProp(mat, ddot(name)+"tex1.value", 1.0).set(val1)
  5573             if type == "col": luxProp(mat, ddot(name)+"tex2.value", "1.0 1.0 1.0").setRGB(val2)
  5574             else: luxProp(mat, ddot(name)+"tex2.value", 1.0).set(val2)
  5575 
  5576 
  5577     def convertDiffuseTexture(name):
  5578         texs = []
  5579         for tex in mat.getTextures():
  5580             if tex and (tex.mapto & Texture.MapTo["COL"] > 0) and (tex.tex) and (tex.tex.type != Texture.Types["NONE"]): texs.append(tex)
  5581         if len(texs) > 0:
  5582             luxProp(mat, name, "").setRGB((mat.ref, mat.ref, mat.ref))
  5583             convertTextures(name, texs, "col", "col", (mat.R, mat.G, mat.B))
  5584     def convertSpecularTexture(name):
  5585         texs = []
  5586         for tex in mat.getTextures():
  5587             if tex and (tex.mapto & Texture.MapTo["CSP"] > 0) and (tex.tex) and (tex.tex.type != Texture.Types["NONE"]): texs.append(tex)
  5588         if len(texs) > 0:
  5589             luxProp(mat, name, "").setRGB((mat.ref*mat.spec, mat.ref*mat.spec, mat.ref*mat.spec))
  5590             convertTextures(name, texs, "col", "col", (mat.specR, mat.specG, mat.specB))
  5591     def convertMirrorTexture(name):
  5592         texs = []
  5593         for tex in mat.getTextures():
  5594             if tex and (tex.mapto & Texture.MapTo["CMIR"] > 0) and (tex.tex) and (tex.tex.type != Texture.Types["NONE"]): texs.append(tex)
  5595         if len(texs) > 0:
  5596             luxProp(mat, name, "").setRGB((mat.ref, mat.ref, mat.ref))
  5597             convertTextures(name, texs, "col", "col", (mat.mirR, mat.mirG, mat.mirB))
  5598     def convertBumpTexture(basename):
  5599         texs = []
  5600         for tex in mat.getTextures():
  5601             if tex and (tex.mapto & Texture.MapTo["NOR"] > 0) and (tex.tex) and (tex.tex.type != Texture.Types["NONE"]): texs.append(tex)
  5602         if len(texs) > 0:
  5603             name = basename+":bumpmap"
  5604             luxProp(mat, basename+".usebump", "").set("true")
  5605             luxProp(mat, dot(name)+"textured", "").set("true")
  5606             luxProp(mat, name, "").set(1.0)
  5607             convertTextures(name, texs, "float", "nor", 0.0)
  5608 
  5609     def makeMatte(name):
  5610         luxProp(mat, dot(name)+"type", "").set("matte")
  5611         luxProp(mat, name+":Kd", "").setRGB((mat.R*mat.ref, mat.G*mat.ref, mat.B*mat.ref))
  5612         convertDiffuseTexture(name+":Kd")
  5613         convertBumpTexture(name)
  5614     def makeGlossy(name, roughness):
  5615         luxProp(mat, dot(name)+"type", "").set("glossy")
  5616         luxProp(mat, name+":Kd", "").setRGB((mat.R*mat.ref, mat.G*mat.ref, mat.B*mat.ref))
  5617         luxProp(mat, name+":Ks", "").setRGB((mat.specR*mat.spec*0.5, mat.specG*mat.spec*0.5, mat.specB*mat.spec*0.5))
  5618         luxProp(mat, name+":uroughness", 0.0).set(roughness)
  5619         luxProp(mat, name+":vroughness", 0.0).set(roughness)
  5620         convertDiffuseTexture(name+":Kd")
  5621         convertSpecularTexture(name+":Ks")
  5622         convertBumpTexture(name)
  5623     def makeMirror(name):
  5624         luxProp(mat, dot(name)+"type", "").set("mirror")
  5625         luxProp(mat, name+":Kr", "").setRGB((mat.mirR, mat.mirG, mat.mirB))
  5626         convertMirrorTexture(name+":Kr")
  5627         convertBumpTexture(name)
  5628     def makeGlass(name):
  5629         luxProp(mat, dot(name)+"type", "").set("glass")
  5630         luxProp(mat, name+":Kr", "").setRGB((0.0, 0.0, 0.0))
  5631         luxProp(mat, name+":Kt", "").setRGB((mat.R, mat.G, mat.B))
  5632         luxProp(mat, name+":index.iorusepreset", "").set("false")
  5633         luxProp(mat, name+":index", 0.0).set(mat.getIOR())
  5634         convertMirrorTexture(name+":Kr")
  5635         convertDiffuseTexture(name+":Kt")
  5636         convertBumpTexture(name)
  5637     def makeRoughglass(name, roughness):
  5638         luxProp(mat, dot(name)+"type", "").set("roughglass")
  5639         luxProp(mat, name+":Kr", "").setRGB((0.0, 0.0, 0.0))
  5640         luxProp(mat, name+":Kt", "").setRGB((mat.R, mat.G, mat.B))
  5641         luxProp(mat, name+":index.iorusepreset", "").set("false")
  5642         luxProp(mat, name+":index", 0.0).set(mat.getIOR())
  5643         luxProp(mat, name+":uroughness", 0.0).set(roughness)
  5644         luxProp(mat, name+":vroughness", 0.0).set(roughness)
  5645         convertMirrorTexture(name+":Kr")
  5646         convertDiffuseTexture(name+":Kt")
  5647         convertBumpTexture(name)
  5648     print("convert Blender material \"%s\" to lux material"%(mat.name))
  5649     mat.properties['luxblend'] = {}
  5650     if mat.emit > 0.0001:
  5651         luxProp(mat, "type", "").set("light")
  5652         luxProp(mat, "light.l", "").setRGB((mat.R, mat.G, mat.B))
  5653         luxProp(mat, "light.gain", 1.0).set(mat.emit)
  5654         return
  5655     alpha = mat.alpha
  5656     if not(mat.mode & Material.Modes.RAYTRANSP): alpha = 1.0
  5657     alpha0name, alpha1name = "", ""
  5658     if (alpha > 0.0) and (alpha < 1.0):
  5659         luxProp(mat, "type", "").set("mix")
  5660         luxProp(mat, ":amount", 0.0).set(alpha)
  5661         alpha0name, alpha1name = "mat2", "mat1"
  5662     if alpha > 0.0:
  5663         mirror = mat.rayMirr
  5664         if not(mat.mode & Material.Modes.RAYMIRROR): mirror = 0.0
  5665         mirror0name, mirror1name = alpha1name, alpha1name
  5666         if (mirror > 0.0) and (mirror < 1.0):
  5667             luxProp(mat, dot(alpha1name)+"type", "").set("mix")
  5668             luxProp(mat, alpha1name+":amount", 0.0).set(1.0 - mirror)
  5669             mirror0name, mirror1name = ddot(alpha1name)+"mat1", ddot(alpha1name)+"mat2"
  5670         if mirror > 0.0:
  5671             if mat.glossMir < 1.0: makeGlossy(mirror1name, 1.0-mat.glossMir**2)
  5672             else: makeMirror(mirror1name)
  5673         if mirror < 1.0:
  5674             if mat.spec > 0.0: makeGlossy(mirror0name, 1.0/mat.hard)
  5675             else: makeMatte(mirror0name)
  5676     if alpha < 1.0:
  5677         if mat.glossTra < 1.0: makeRoughnessGlass(alpha0name, 1.0-mat.glossTra**2)
  5678         else: makeGlass(alpha0name)
  5679 
  5680 def convertAllMaterials():
  5681     for mat in Material.Get(): convertMaterial(mat)
  5682 
  5683 
  5684 
  5685 
  5686 ### Connect LRMDB ###
  5687 ConnectLrmdb = False
  5688 try:
  5689     import socket  # try import of socket library
  5690     ConnectLrmdb = True
  5691     def downloadLRMDB(mat, id):
  5692         if id.isalnum():
  5693             DrawProgressBar(0.0,'Getting Material #'+id)
  5694             try:
  5695                 HOST = 'www.luxrender.net'
  5696                 GET = '/lrmdb/en/material/download/'+id
  5697                 PORT = 80
  5698                 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  5699                 sock.connect((HOST, PORT))
  5700                 sock.send("GET %s HTTP/1.0\r\nHost: %s\r\n\r\n" % (GET, HOST))
  5701                 data = sock.recv(1024)
  5702                 str = ""
  5703                 while len(data):
  5704                     str += data
  5705                     data = sock.recv(1024)
  5706                 sock.close()
  5707                 if str.split("\n", 1)[0].find("200") < 0:
  5708                     print("ERROR: server error: %s"%(str.split("\n",1)[0]))
  5709                     return None
  5710                 str = (str.split("\r\n\r\n")[1]).strip()
  5711                 if (str[0]=="{") and (str[-1]=="}"):
  5712                     return str2MatTex(str)
  5713                 print("ERROR: downloaded data is not a material or texture")
  5714             except:
  5715                 print("ERROR: download failed")
  5716                 
  5717             DrawProgressBar(1.0,'')
  5718         else:
  5719             print("ERROR: material id is not valid")
  5720         return None
  5721     
  5722         
  5723     #===========================================================================
  5724     # COOKIETRANSPORT
  5725     #===========================================================================
  5726     
  5727     #--------------------------------------------------------------------------- 
  5728     # IMPORTS
  5729     import cookielib, urllib2, xmlrpclib
  5730     
  5731     #---------------------------------------------------------------------------
  5732     # pilfered from
  5733     # https://fedorahosted.org/python-bugzilla/browser/bugzilla.py?rev=e6f699f06e92b1e49b1b8d2c8fbe89d9425a4a9a
  5734     class CookieTransport(xmlrpclib.Transport):
  5735         '''
  5736         A subclass of xmlrpclib.Transport that supports cookies.
  5737         '''
  5738         
  5739         cookiejar = None
  5740         scheme = 'http'
  5741         verbose = None
  5742     
  5743         # Cribbed from xmlrpclib.Transport.send_user_agent 
  5744         def send_cookies(self, connection, cookie_request):
  5745             '''
  5746             Send all the cookie data that we have received
  5747             '''
  5748             
  5749             if self.cookiejar is None:
  5750                 self.cookiejar = cookielib.CookieJar()
  5751             elif self.cookiejar:
  5752                 # Let the cookiejar figure out what cookies are appropriate
  5753                 self.cookiejar.add_cookie_header(cookie_request)
  5754                 # Pull the cookie headers out of the request object...
  5755                 cookielist = list()
  5756                 for header, value in cookie_request.header_items():
  5757                     if header.startswith('Cookie'):
  5758                         cookielist.append([header, value])
  5759                 # ...and put them over the connection
  5760                 for header, value in cookielist:
  5761                     connection.putheader(header, value)
  5762     
  5763         # This is the same request() method from xmlrpclib.Transport,
  5764         # with a couple additions noted below
  5765         def request(self, host, handler, request_body, verbose=0):
  5766             '''
  5767             Handle the request
  5768             '''
  5769             
  5770             host_connection = self.make_connection(host)
  5771             if verbose:
  5772                 host_connection.set_debuglevel(1)
  5773     
  5774             # ADDED: construct the URL and Request object for proper cookie handling
  5775             request_url = "%s://%s/" % (self.scheme, host)
  5776             cookie_request  = urllib2.Request(request_url) 
  5777     
  5778             self.send_request(host_connection, handler, request_body)
  5779             self.send_host(host_connection, host) 
  5780             
  5781             # ADDED. creates cookiejar if None.
  5782             self.send_cookies(host_connection, cookie_request)
  5783             self.send_user_agent(host_connection)
  5784             self.send_content(host_connection, request_body)
  5785     
  5786             errcode, errmsg, headers = host_connection.getreply()
  5787     
  5788             # ADDED: parse headers and get cookies here
  5789             class CookieResponse:
  5790                 '''
  5791                 fake a response object that we can fill with the headers above
  5792                 '''
  5793                 
  5794                 def __init__(self, headers):
  5795                     self.headers = headers
  5796                     
  5797                 def info(self):
  5798                     return self.headers
  5799                 
  5800             cookie_response = CookieResponse(headers)
  5801             
  5802             # Okay, extract the cookies from the headers
  5803             self.cookiejar.extract_cookies(cookie_response, cookie_request)
  5804             
  5805             # And write back any changes
  5806             # DH THIS DOESN'T WORK
  5807             # self.cookiejar.save(self.cookiejar.filename)
  5808     
  5809             if errcode != 200:
  5810                 raise xmlrpclib.ProtocolError(
  5811                     host + handler,
  5812                     errcode, errmsg,
  5813                     headers
  5814                 )
  5815     
  5816             self.verbose = verbose
  5817     
  5818             try:
  5819                 sock = host_connection._conn.sock
  5820             except AttributeError:
  5821                 sock = None
  5822     
  5823             return self._parse_response(host_connection.getfile(), sock)
  5824     
  5825 
  5826     #===========================================================================
  5827     # LRMDB Integration
  5828     #===========================================================================
  5829     class lrmdb:
  5830         host              = 'http://www.luxrender.net/lrmdb/ixr'
  5831         
  5832         username          = ""
  5833         password          = ""
  5834         logged_in         = False
  5835         
  5836         SERVER            = None
  5837         
  5838         last_error_str    = None
  5839         
  5840         def last_error(self):
  5841             return self.last_error_str #'LRMDB Connector: %s' %
  5842         
  5843         def login(self):
  5844             try:
  5845                 result = self.SERVER.user.login(
  5846                     self.username,
  5847                     self.password
  5848                 )
  5849                 if not result:
  5850                     raise
  5851                 else:
  5852                     self.logged_in = True
  5853                     return True
  5854             except:
  5855                 self.last_error_str = 'Login Failed'
  5856                 self.logged_in = False
  5857                 return False
  5858             
  5859         def submit_object(self, mat, basekey, tex):
  5860             if not self.check_creds(): return False
  5861             
  5862             try:
  5863                 result = 'Unknown Error'
  5864                 
  5865                 if tex:
  5866                     name = Draw.PupStrInput('Name: ', '', 32)
  5867                 else:
  5868                     name = mat.name
  5869                 
  5870                 result = self.SERVER.object.submit(
  5871                     name,
  5872                     MatTex2dict( getMatTex(mat, basekey, tex), tex )
  5873                 )
  5874                 if result is not True:
  5875                     raise
  5876                 else:
  5877                     return True
  5878             except:
  5879                 self.last_error_str = 'Submit failed: %s' % result
  5880                 return False
  5881         
  5882         def check_creds(self):
  5883             if self.SERVER is None:
  5884                 try:
  5885                     self.SERVER = xmlrpclib.ServerProxy(self.host, transport=CookieTransport())
  5886                 except:
  5887                     self.last_error_str = 'ServerProxy init failed'
  5888                     return False
  5889             
  5890             
  5891             if not self.logged_in:
  5892                 #if self.username is "":
  5893                 self.request_username()
  5894                 
  5895                 #if self.password is "":
  5896                 self.request_password()
  5897                     
  5898                 return self.login()
  5899             else:
  5900                 return True
  5901                 
  5902         def request_username(self):
  5903             self.username = Draw.PupStrInput("Username:", self.username, 32)
  5904             
  5905         def request_password(self):
  5906             self.password = Draw.PupStrInput("Password:", self.password, 32)
  5907 
  5908     lrmdb_connector = lrmdb()
  5909         
  5910     
  5911 except: print("WARNING: LRMDB support not available")
  5912 
  5913 
  5914 
  5915 ### MatTex functions ###
  5916 ### MatTex : is a dictionary of material or texture properties
  5917 
  5918 def getMatTex(mat, basekey='', tex=False):
  5919     global usedproperties, usedpropertiesfilterobj
  5920     usedproperties = {}
  5921     usedpropertiesfilterobj = mat
  5922     luxMaterial(mat)
  5923     dict = {}
  5924     for k,v in usedproperties.items():
  5925         if k[:len(basekey)]==basekey:
  5926             if k[-9:] != '.textured':
  5927                 name = k[len(basekey):]
  5928                 if name == ".type": name = "type"
  5929                 dict[name] = v
  5930     dict["__type__"] = ["material","texture"][bool(tex)]
  5931     return dict
  5932 
  5933 def putMatTex(mat, dict, basekey='', tex=None):
  5934     if dict and (tex!=None) and (tex ^ (dict.has_key("__type__") and (dict["__type__"]=="texture"))):
  5935         print("ERROR: Can't apply %s as %s"%(["texture","material"][bool(tex)],["material","texture"][bool(tex)]))
  5936         return
  5937     if dict:
  5938         # remove all current properties in mat that starts with basekey
  5939         try:
  5940             d = mat.properties['luxblend']
  5941             for k,v in d.convert_to_pyobject().items():
  5942                 kn = k
  5943                 if k[:7]=="__hash:":    # decode if entry is hashed (cause of 32chars limit)
  5944                     l = v.split(" = ")
  5945                     kn = l[0]
  5946                 if kn[:len(basekey)]==basekey:
  5947                     del mat.properties['luxblend'][k]
  5948         except: print("error") # pass
  5949         # assign loaded properties
  5950         for k,v in dict.items():
  5951             try:
  5952                 if (basekey!="") and (k=="type"): k = ".type"
  5953                 # zuegs: following two lines should fix issue http://www.luxrender.net/forum/viewtopic.php?f=16&t=1618&p=14512#p14512
  5954                 if (basekey!="") and ((k[0]!=".") and (k[0]!=":")): k = ":"+k
  5955                 if (basekey=="") and (k[0:4]==":mat"): k = k[1:]
  5956                 luxProp(mat, basekey+k, None).set(v)
  5957                 if k[-8:] == '.texture':
  5958                     luxProp(mat, basekey+k[:-8]+'.textured', 'false').set('true')
  5959             except: pass
  5960 
  5961 
  5962 LBX_VERSION = '0.7'
  5963 
  5964 def MatTex2dict(d, tex = None):
  5965     global LBX_VERSION
  5966     
  5967     if LBX_VERSION == '0.6':
  5968     
  5969         if tex is not None and tex == True:
  5970             d['LUX_DATA'] = 'TEXTURE'
  5971         else:
  5972             d['LUX_DATA'] = 'MATERIAL'
  5973         
  5974         d['LUX_VERSION'] = '0.6'
  5975         
  5976         return d
  5977     
  5978     elif LBX_VERSION == '0.7':
  5979         definition = []
  5980         for k in d.keys():
  5981             if type(d[k]) == types.IntType:
  5982                 t = 'integer'
  5983             if type(d[k]) == types.FloatType:
  5984                 t = 'float'
  5985             if type(d[k]) == types.BooleanType:
  5986                 t = 'bool'
  5987             if type(d[k]) == types.StringType:
  5988                 l=None
  5989                 try:
  5990                     l = d[k].split(" ")
  5991                 except: pass
  5992                 if l==None or len(l)!=3:
  5993                     t = 'string'
  5994                 else:
  5995                     t = 'vector'
  5996                 
  5997             definition.append([ t, k, d[k] ])
  5998         
  5999         
  6000         lbx = {
  6001             'type': d['__type__'],
  6002             'version': '0.7',
  6003             'definition': definition,
  6004             'metadata': [
  6005                 ['string', 'generator', 'luxblend'],
  6006             ]
  6007         }
  6008         
  6009         return lbx
  6010 
  6011 def format_dictStr(dictStr):
  6012     result = ''
  6013     pos = 0
  6014     indentStr = '  '
  6015     newLine = '\n'
  6016     
  6017     for char in dictStr:
  6018         if char in ['}', ']']:
  6019             result += newLine
  6020             pos -= 1
  6021             for j in range(0,pos):
  6022                 result += indentStr
  6023                 
  6024         result += char
  6025         
  6026         if char in [',', '{', '[']:
  6027             result += newLine
  6028             if char in ['{', '[']:
  6029                 pos += 1
  6030             for j in range(0,pos):
  6031                 result += indentStr
  6032             
  6033     return result
  6034 
  6035 
  6036 def MatTex2str(d, tex = None):
  6037     global LBX_VERSION
  6038     
  6039     if LBX_VERSION == '0.6':
  6040         return format_dictStr(str( MatTex2dict(d, tex) )) #.replace(", \'", ",\n\'")
  6041     
  6042     elif LBX_VERSION == '0.7':
  6043         return format_dictStr(str( MatTex2dict(d, tex) )) #.replace("], \'", "],\r\n\'").replace("[","\r\n\t[")
  6044         
  6045 
  6046 def str2MatTex(s, tex = None):    # todo: this is not absolutely save from attacks!!!
  6047     global LBX_VERSION
  6048     
  6049     s = s.strip()
  6050     if (s[0]=='{') and (s[-1]=='}'):
  6051         d = eval(s, dict(__builtins__=None))
  6052         if type(d)==types.DictType:
  6053             
  6054             
  6055             if LBX_VERSION == '0.6':
  6056             
  6057                 if tex is not None and tex == True:
  6058                     test_str = 'TEXTURE'
  6059                 else:
  6060                     test_str = 'MATERIAL'
  6061                     
  6062                 if   ('LUX_DATA' in d.keys() and d['LUX_DATA'] == test_str) \
  6063                 and  ('LUX_VERSION' in d.keys() and (d['LUX_VERSION'] == '0.6' or d['LUX_VERSION'] == 0.6)):
  6064                     return d
  6065                 else:
  6066                     reason = 'Missing/incorrect metadata'
  6067                     
  6068             elif LBX_VERSION == '0.7':
  6069                 
  6070                 def lb_list_to_dict(list):
  6071                     d = {}
  6072                     for t, k, v in list:
  6073                         if t == 'float':
  6074                             v = float(v)
  6075                             
  6076                         d[k] = v
  6077                     return d
  6078                 
  6079                 if   ('version' in d.keys() and d['version'] in ['0.6', '0.7']) \
  6080                 and  ('type' in d.keys() and d['type'] in ['material', 'texture']) \
  6081                 and  ('definition' in d.keys()):
  6082                     
  6083                     
  6084                     try:
  6085                         definition = lb_list_to_dict(d['definition'])
  6086                         
  6087                         if 'metadata' in d.keys():
  6088                             definition.update( lb_list_to_dict(d['metadata']) )
  6089                         
  6090                         return definition
  6091                     except:
  6092                         reason = 'Incorrect LBX definition data'
  6093                 else: 
  6094                     reason = 'Missing/incorrect metadata'
  6095             else:
  6096                 reason = 'Unknown LBX version'
  6097         else:
  6098             reason = 'Not a parsed dict'
  6099     else:
  6100         reason = 'Not a stored dict'
  6101             
  6102             
  6103     print("ERROR: string to material/texture conversion failed: %s" % reason)
  6104     return None
  6105 
  6106 
  6107 luxclipboard = None # global variable for copy/paste content
  6108 def showMatTexMenu(mat, basekey='', tex=False):
  6109     global luxclipboard, ConnectLrmdb
  6110     if tex: menu="Texture menu:%t"
  6111     else: menu="Material menu:%t"
  6112     menu += "|Copy%x1"
  6113     try:
  6114         if luxclipboard and (not(tex) ^ (luxclipboard["__type__"]=="texture")): menu +="|Paste%x2"
  6115     except: pass
  6116     if (tex):
  6117         menu += "|Load LBT%x3|Save LBT%x4"
  6118     else:
  6119         menu += "|Load LBM%x3|Save LBM%x4"
  6120     if  ConnectLrmdb:
  6121         menu += "|Download from DB%x5" #not(tex) and
  6122         menu += "|Upload to DB%x6"
  6123 
  6124 #    menu += "|%l|dump material%x99|dump clipboard%x98"
  6125     r = Draw.PupMenu(menu)
  6126     if r==1:
  6127         luxclipboard = getMatTex(mat, basekey, tex)
  6128     elif r==2: putMatTex(mat, luxclipboard, basekey, tex)
  6129     elif r==3: 
  6130         scn = Scene.GetCurrent()
  6131         if (tex):
  6132             Window.FileSelector(lambda fn:loadMatTex(mat, fn, basekey, tex), "load texture", luxProp(scn, "lux", "").get()+os.sep+".lbt")
  6133         else:
  6134             Window.FileSelector(lambda fn:loadMatTex(mat, fn, basekey, tex), "load material", luxProp(scn, "lux", "").get()+os.sep+".lbm")
  6135     elif r==4:
  6136         scn = Scene.GetCurrent()
  6137         if (tex):
  6138             Window.FileSelector(lambda fn:saveMatTex(mat, fn, basekey, tex), "save texture", luxProp(scn, "lux", "").get()+os.sep+".lbt")
  6139         else:
  6140             Window.FileSelector(lambda fn:saveMatTex(mat, fn, basekey, tex), "save material", luxProp(scn, "lux", "").get()+os.sep+".lbm")
  6141     elif r==5:
  6142         if not tex:
  6143             id = Draw.PupStrInput("Material ID:", "", 32)
  6144         else:
  6145             id = Draw.PupStrInput("Texture ID:", "", 32)
  6146         if id: putMatTex(mat, downloadLRMDB(mat, id), basekey, tex)
  6147     elif r==6:
  6148         global lrmdb_connector
  6149         if not lrmdb_connector.submit_object(mat, basekey, tex):
  6150             msg = lrmdb_connector.last_error()
  6151         else:
  6152             msg = 'OK'
  6153             
  6154         Draw.PupMenu("Upload: "+msg+".%t|OK")
  6155 #    elif r==99:
  6156 #        for k,v in mat.properties['luxblend'].convert_to_pyobject().items(): print(k+"="+repr(v))
  6157 #    elif r==98:
  6158 #        for k,v in luxclipboard.items(): print(k+"="+repr(v))
  6159 #    prin()
  6160     Draw.Redraw()
  6161 
  6162 
  6163 def saveMatTex(mat, fn, basekey='', tex=False):
  6164     global LuxIsGUI
  6165     d = getMatTex(mat, basekey, tex)
  6166     file = open(fn, 'w')
  6167     file.write(MatTex2str(d, tex))
  6168     file.close()
  6169     if LuxIsGUI: Draw.Redraw()
  6170 
  6171 
  6172 def loadMatTex(mat, fn, basekey='', tex=None):
  6173     global LuxIsGUI
  6174     file = open(fn, 'rU')
  6175     data = file.read()
  6176     file.close()
  6177     data = str2MatTex(data, tex)
  6178     putMatTex(mat, data, basekey, tex) 
  6179     if LuxIsGUI: Draw.Redraw()
  6180 
  6181 
  6182 activemat = None
  6183 def setactivemat(mat):
  6184     global activemat
  6185     activemat = mat
  6186 
  6187 
  6188 # scrollbar
  6189 class scrollbar:
  6190     def __init__(self):
  6191         self.position = 0 # current position at top (inside 0..height-viewHeight)
  6192         self.height = 0 # total height of the content
  6193         self.viewHeight = 0 # height of window
  6194         self.x = 0 # horizontal position of the scrollbar
  6195         self.scrolling = self.over = False # start without scrolling ;)
  6196     def calcRects(self):
  6197         # Blender doesn't give us direct access to the window size yet, but it does set the
  6198         # GL scissor box for it, so we can get the size from that. (thx to Daniel Dunbar)
  6199         size = BGL.Buffer(BGL.GL_FLOAT, 4)
  6200         BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, size)
  6201         size = size.list # [winx, winy, width, height]
  6202         self.winrect = size[:]
  6203         self.viewHeight = size[3]
  6204         size[0], size[1] = size[2]-20, 0 # [scrollx1, scrolly1, scrollx2, scrolly2]
  6205         self.rect = size[:]
  6206         if self.position < 0: self.position = 0
  6207         if self.height < self.viewHeight: self.height = self.viewHeight
  6208         if self.position > self.height-self.viewHeight: self.position = self.height-self.viewHeight
  6209         self.factor = (size[3]-size[1]-4)/self.height
  6210         self.sliderRect = [size[0]+2, size[3]-2-(self.position+self.viewHeight)*self.factor, size[2]-2, size[3]-2-self.position*self.factor]
  6211     def draw(self):
  6212         self.calcRects()
  6213         BGL.glColor3f(0.5,0.5,0.5); BGL.glRectf(self.rect[0],self.rect[1],self.rect[2],self.rect[3])
  6214         if self.over or self.scrolling: BGL.glColor3f(1.0,1.0,0.7)
  6215         else: BGL.glColor3f(0.7,0.7,0.7)
  6216         BGL.glRectf(self.sliderRect[0],self.sliderRect[1],self.sliderRect[2],self.sliderRect[3])
  6217     def getTop(self):
  6218         return self.viewHeight+self.position
  6219     def scroll(self, delta):
  6220         self.position = self.position + delta
  6221         self.calcRects()
  6222         Draw.Redraw()
  6223     def Mouse(self):
  6224         self.calcRects()
  6225         coord, buttons = Window.GetMouseCoords(), Window.GetMouseButtons()
  6226         over = (coord[0]>=self.winrect[0]+self.rect[0]) and (coord[0]<=self.winrect[0]+self.rect[2]) and \
  6227                (coord[1]>=self.winrect[1]+self.rect[1]) and (coord[1]<=self.winrect[1]+self.rect[3])
  6228         if Window.MButs.L and buttons > 0:
  6229             if self.scrolling:
  6230                 if self.factor > 0: self.scroll((self.lastcoord[1]-coord[1])/self.factor)
  6231                 Draw.Redraw()
  6232             elif self.over:
  6233                 self.scrolling = True
  6234             self.lastcoord = coord
  6235         elif self.scrolling:
  6236             self.scrolling = False
  6237             Draw.Redraw()
  6238         if self.over != over: Draw.Redraw()
  6239         self.over = over
  6240 
  6241 scrollbar = scrollbar()
  6242 
  6243 
  6244 # gui main draw
  6245 def luxDraw():
  6246     global icon_luxblend
  6247 
  6248     BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
  6249 
  6250     y = int(scrollbar.getTop()) # 420
  6251     BGL.glColor3f(0.1,0.1,0.1); BGL.glRectf(0,0,440,y)
  6252     BGL.glColor3f(1.0,0.5,0.0); BGL.glRasterPos2i(130,y-21); Draw.Text("v%s"%__version__)
  6253     BGL.glColor3f(0.9,0.9,0.9)
  6254 
  6255     drawLogo(icon_luxblend, 6, y-25)
  6256 
  6257     scn = Scene.GetCurrent()
  6258     if scn:
  6259         luxpage = luxProp(scn, "page", 0)
  6260         gui = luxGui(y-70)
  6261 
  6262         # render presets
  6263         BGL.glRasterPos2i(10,y-45); Draw.Text("Render presets:")
  6264         luxpreset = luxProp(scn, "preset", "1C - Final - medium MLT/Path Tracing (indoor) (recommended)")
  6265         presets = getScenePresets()
  6266         presetskeys = presets.keys()
  6267         presetskeys.sort()
  6268         presetskeys.insert(0, "")
  6269         presetsstr = "presets: %t"
  6270         for i, v in enumerate(presetskeys): presetsstr = "%s %%x%d|%s"%(v, i, presetsstr)
  6271         try: i = presetskeys.index(luxpreset.get())
  6272         except ValueError: i = 0
  6273         Draw.Menu(presetsstr, evtLuxGui, 110, y-50, 220, 18, i, "", lambda e,v: luxpreset.set(presetskeys[v]))
  6274         Draw.Button("save", evtSavePreset, 330, y-50, 40, 18, "create a render-settings preset")
  6275         Draw.Button("del", evtDeletePreset, 370, y-50, 40, 18, "delete a render-settings preset")
  6276 
  6277         # if preset is selected load values
  6278         if luxpreset.get() != "":
  6279             try:
  6280                 d = presets[luxpreset.get()]
  6281                 for k,v in d.items(): scn.properties['luxblend'][k] = v
  6282             except: pass
  6283 
  6284         Draw.Button("Material", evtLuxGui, 10, y-70, 80, 16, "", lambda e,v:luxpage.set(0))
  6285         Draw.Button("Cam/Env", evtLuxGui, 90, y-70, 80, 16, "", lambda e,v:luxpage.set(1))
  6286         Draw.Button("Render", evtLuxGui, 170, y-70, 80, 16, "", lambda e,v:luxpage.set(2))
  6287         Draw.Button("Output", evtLuxGui, 250, y-70, 80, 16, "", lambda e,v:luxpage.set(3))
  6288         Draw.Button("System", evtLuxGui, 330, y-70, 80, 16, "", lambda e,v:luxpage.set(4))
  6289         if luxpage.get() == 0:
  6290             BGL.glColor3f(1.0,0.5,0.0);BGL.glRectf(10,y-74,90,y-70);BGL.glColor3f(0.9,0.9,0.9)
  6291             obj = scn.objects.active
  6292             if obj:
  6293                 if (obj.getType() == "Lamp"):
  6294                     ltype = obj.getData(mesh=1).getType() # data
  6295                     if (ltype == Lamp.Types["Area"]): luxLight("Area LIGHT", "", obj, gui, 0)
  6296                     elif (ltype == Lamp.Types["Spot"]): luxSpot("Spot LIGHT", "", obj, gui, 0)
  6297                     elif (ltype == Lamp.Types["Lamp"]): luxLamp("Point LIGHT", "", obj, gui, 0)
  6298                 else:
  6299                     matfilter = luxProp(scn, "matlistfilter", "false")
  6300                     mats = getMaterials(obj, True)
  6301                     if (activemat == None) and (len(mats) > 0):
  6302                         setactivemat(mats[0])
  6303                     if matfilter.get() == "false":
  6304                         mats = Material.Get()
  6305                     matindex = 0
  6306                     for i, v in enumerate(mats):
  6307                         if v==activemat: matindex = i
  6308                     matnames = [m.getName() for m in mats]
  6309                     menustr = "Material: %t"
  6310                     for i, v in enumerate(matnames): menustr = "%s %%x%d|%s"%(v, i, menustr)
  6311                     gui.newline("MATERIAL:", 8) 
  6312                     r = gui.getRect(1.1, 1)
  6313                     Draw.Button("C", evtConvertMaterial, r[0]-gui.h, gui.y-gui.h, gui.h, gui.h, "convert blender material to lux material")
  6314                     Draw.Menu(menustr, evtLuxGui, r[0], r[1], r[2], r[3], matindex, "", lambda e,v: setactivemat(mats[v]))
  6315                     luxBool("", matfilter, "filter", "only show active object materials", gui, 0.5)
  6316 
  6317                     Draw.Button("L", evtLoadMaterial, gui.x, gui.y-gui.h, gui.h, gui.h, "load a material preset")
  6318                     Draw.Button("S", evtSaveMaterial, gui.x+gui.h, gui.y-gui.h, gui.h, gui.h, "save a material preset")
  6319                     Draw.Button("D", evtDeleteMaterial, gui.x+gui.h*2, gui.y-gui.h, gui.h, gui.h, "delete a material preset")
  6320                     if len(mats) > 0:
  6321                         setactivemat(mats[matindex])
  6322                         luxMaterial(activemat, gui)
  6323         if luxpage.get() == 1:
  6324             BGL.glColor3f(1.0,0.5,0.0);BGL.glRectf(90,y-74,170,y-70);BGL.glColor3f(0.9,0.9,0.9)
  6325             cam = scn.getCurrentCamera()
  6326             if cam:
  6327                 r = gui.getRect(1.1, 1)
  6328                 luxCamera(cam.data, scn.getRenderingContext(), gui)
  6329             gui.newline("", 10)
  6330             luxEnvironment(scn, gui)
  6331         if luxpage.get() == 2:
  6332             BGL.glColor3f(1.0,0.5,0.0);BGL.glRectf(170,y-74,250,y-70);BGL.glColor3f(0.9,0.9,0.9)
  6333             r = gui.getRect(1.1, 1)
  6334             luxSampler(scn, gui)
  6335             gui.newline("", 10)
  6336             luxSurfaceIntegrator(scn, gui)
  6337             gui.newline("", 10)
  6338             luxVolumeIntegrator(scn, gui)
  6339             gui.newline("", 10)
  6340             luxPixelFilter(scn, gui)
  6341         if luxpage.get() == 3:
  6342             BGL.glColor3f(1.0,0.5,0.0);BGL.glRectf(250,y-74,330,y-70);BGL.glColor3f(0.9,0.9,0.9)
  6343             r = gui.getRect(1.1, 1)
  6344             luxFilm(scn, gui)
  6345         if luxpage.get() == 4:
  6346             BGL.glColor3f(1.0,0.5,0.0);BGL.glRectf(330,y-74,410,y-70);BGL.glColor3f(0.9,0.9,0.9)
  6347             luxSystem(scn, gui)
  6348             gui.newline("", 10)
  6349             luxAccelerator(scn, gui)
  6350             gui.newline("MATERIALS:", 10)
  6351             r = gui.getRect(2,1)
  6352             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())
  6353             gui.newline("SETTINGS:", 10)
  6354             r = gui.getRect(2,1)
  6355             Draw.Button("save defaults", 0, r[0], r[1], r[2], r[3], "save current settings as defaults", lambda e,v:saveluxdefaults())
  6356         y = gui.y - 80
  6357         if y > 0: y = 0 # bottom align of render button
  6358         run = luxProp(scn, "run", "true")
  6359         dlt = luxProp(scn, "default", "true")
  6360         pipe = luxProp(scn, "pipe", "false")
  6361         clay = luxProp(scn, "clay", "false")
  6362         nolg = luxProp(scn, "nolg", "false")
  6363         lxs = luxProp(scn, "lxs", "true")
  6364         lxo = luxProp(scn, "lxo", "true")
  6365         lxm = luxProp(scn, "lxm", "true")
  6366         lxv = luxProp(scn, "lxv", "true")
  6367         net = luxProp(scn, "netrenderctl", "false")
  6368         donet = luxProp(scn, "donetrender", "true")
  6369         
  6370         global render_status_text
  6371         global render_status
  6372         
  6373         if render_status == True:
  6374             BGL.glRasterPos2i(10,y+20)
  6375             Draw.Text(render_status_text)
  6376         else:
  6377             BGL.glRasterPos2i(10,y+5)
  6378             Draw.Text(render_status_text, "tiny")
  6379             
  6380             def check_pipe_def_exclusion(m, v):
  6381             	if m == 'd':
  6382             		dlt.set(["false","true"][bool(v)])
  6383             		
  6384             		if dlt.get() == 'true':
  6385             			pipe.set('false')
  6386             	elif m == 'p':
  6387             		pipe.set(["false","true"][bool(v)])
  6388             		
  6389             		if pipe.get() == 'true':
  6390             			dlt.set('false')
  6391             
  6392             if (run.get()=="true"):
  6393                 Draw.Button("Render", 0, 10, y+20, 100, 36, "Render with Lux", lambda e,v:CBluxExport(dlt.get()=="true" or pipe.get()=="true", True))
  6394                 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))
  6395             else:
  6396                 Draw.Button("Export", 0, 10, y+20, 100, 36, "Export", lambda e,v:CBluxExport(dlt.get()=="true" or pipe.get()=="true", False))
  6397                 Draw.Button("Export Anim", 0, 110, y+20, 100, 36, "Export animation", lambda e,v:CBluxAnimExport(dlt.get()=="true" or pipe.get()=="true", False))
  6398             
  6399             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)]))
  6400             
  6401             if (pipe.get() == 'false' and dlt.get() == 'true') or run.get()=='false':
  6402                 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))
  6403             elif pipe.get() == 'true' and dlt.get() == 'false':
  6404                 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))
  6405             else:
  6406                 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))
  6407                 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))
  6408             
  6409             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)]))
  6410             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)]))
  6411             
  6412             if pipe.get() == "false":
  6413                 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)]))
  6414                 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)]))
  6415                 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)]))
  6416                 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)]))
  6417     
  6418     BGL.glColor3f(0.9, 0.9, 0.9)
  6419     
  6420     BGL.glRasterPos2i(330,y+5) ; Draw.Text("Press Q or ESC to quit.", "tiny")
  6421     scrollbar.height = scrollbar.getTop() - y
  6422     scrollbar.draw()
  6423 
  6424 render_status_text = ''
  6425 render_status = False
  6426 
  6427 mouse_xr=1 
  6428 mouse_yr=1 
  6429 
  6430 activeObject = None
  6431 activeEvent = None
  6432 lastEventTime = 0
  6433 key_tabs = {
  6434     Draw.ONEKEY:     0,
  6435     Draw.TWOKEY:     1,
  6436     Draw.THREEKEY:   2,
  6437     Draw.FOURKEY:    3,
  6438     Draw.FIVEKEY:    4,
  6439 }
  6440 def luxEvent(evt, val):  # function that handles keyboard and mouse events
  6441     global activeObject, activemat, activeEvent, lastEventTime, key_tabs
  6442     if evt == Draw.ESCKEY or evt == Draw.QKEY:
  6443         stop = Draw.PupMenu("OK?%t|Cancel export %x1")
  6444         if stop == 1:
  6445             Draw.Exit()
  6446             return
  6447     scn = Scene.GetCurrent()
  6448     if scn:
  6449         if scn.objects.active != activeObject:
  6450             activeObject = scn.objects.active
  6451             activemat = None
  6452             Window.QRedrawAll()
  6453     if (evt == Draw.MOUSEX) or (evt == Draw.MOUSEY): scrollbar.Mouse()
  6454     if evt == Draw.WHEELUPMOUSE: scrollbar.scroll(-16)
  6455     if evt == Draw.WHEELDOWNMOUSE: scrollbar.scroll(16)
  6456     if evt == Draw.PAGEUPKEY: scrollbar.scroll(-50)
  6457     if evt == Draw.PAGEDOWNKEY: scrollbar.scroll(50)
  6458 
  6459     # scroll to [T]op and [B]ottom
  6460     if evt == Draw.TKEY:
  6461         scrollbar.scroll(-scrollbar.position)
  6462     if evt == Draw.BKEY:
  6463         scrollbar.scroll(100000)   # Some large number should be enough ?!
  6464 
  6465     # R key shortcut to launch render
  6466     # E key shortcut to export current scene (not render)
  6467     # P key shortcut to preview current material
  6468     # These keys need time and process-complete locks
  6469     if evt in [Draw.RKEY, Draw.EKEY, Draw.PKEY]:
  6470         if activeEvent == None and (sys.time() - lastEventTime) > 5:
  6471             lastEventTime = sys.time()
  6472             if evt == Draw.RKEY:
  6473                 activeEvent = 'RKEY'
  6474                 CBluxExport(luxProp(scn, "default", "true").get() == "true" or luxProp(scn, "pipe", "false").get() == "true", True)
  6475                 activeEvent = None
  6476             if evt == Draw.EKEY:
  6477                 activeEvent = 'EKEY'
  6478                 CBluxExport(luxProp(scn, "default", "true").get() == "true" or luxProp(scn, "pipe", "false").get() == "true", False)
  6479                 activeEvent = None
  6480             if evt == Draw.PKEY:
  6481                 activeEvent = 'PKEY'
  6482                 if activemat != None:
  6483                     Preview_Update(activemat, '', True, 0, None, None, None)
  6484                 activeEvent = None
  6485         
  6486     # Switch GUI tabs with number keys
  6487     if evt in key_tabs.keys():
  6488         luxProp(scn, "page", 0).set(key_tabs[evt])        
  6489         luxDraw()
  6490         Window.QRedrawAll()
  6491           
  6492 
  6493     # Handle icon button events - note - radiance - this is a work in progress! :)
  6494 #    if evt == Draw.LEFTMOUSE and not val: 
  6495 #           size=BGL.Buffer(BGL.GL_FLOAT, 4) 
  6496 #           BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, size) 
  6497 #            size= [int(s) for s in size] 
  6498 #        mx, my = Window.GetMouseCoords()
  6499 #        mousex = mx - size[0]
  6500 #        print("mousex = %i"%mousex)
  6501 #        #if((mousex > 2) and (mousex < 25)):
  6502 #            # Mouse clicked in left button bar
  6503 #        if((mousex > 399) and (mousex < 418)):
  6504 #            # Mouse clicked in right button bar
  6505 #            mousey = my - size[1] - scrollbar.position
  6506 #            print("mousey = %i"%mousey)
  6507             
  6508     
  6509 def luxButtonEvt(evt):  # function that handles button events
  6510     global usedproperties, usedpropertiesfilterobj
  6511     if evt == evtLuxGui:
  6512         Draw.Redraw()
  6513     if evt == evtSavePreset:
  6514         scn = Scene.GetCurrent()
  6515         if scn:
  6516             name = Draw.PupStrInput("preset name: ", "")
  6517             if name != "":
  6518                 usedproperties = {}
  6519                 usedpropertiesfilterobj = None
  6520                 luxSurfaceIntegrator(scn)
  6521                 luxSampler(scn)
  6522                 luxPixelFilter(scn)
  6523                 # luxFilm(scn)
  6524                 luxAccelerator(scn)
  6525                 # luxEnvironment(scn)
  6526                 saveScenePreset(name, usedproperties.copy())
  6527                 luxProp(scn, "preset", "").set(name)
  6528                 Draw.Redraw()
  6529     if evt == evtDeletePreset:
  6530         presets = getScenePresets().keys()
  6531         presets.sort()
  6532         presetsstr = "delete preset: %t"
  6533         for i, v in enumerate(presets): presetsstr += "|%s %%x%d"%(v, i)
  6534         r = Draw.PupMenu(presetsstr, 20)
  6535         if r >= 0:
  6536             saveScenePreset(presets[r], None)
  6537             Draw.Redraw()
  6538 
  6539     if evt == evtLoadMaterial:
  6540         if activemat:
  6541             mats = getMaterialPresets()
  6542             matskeys = mats.keys()
  6543             matskeys.sort()
  6544             matsstr = "load preset: %t"
  6545             for i, v in enumerate(matskeys): matsstr += "|%s %%x%d"%(v, i)
  6546             r = Draw.PupMenu(matsstr, 20)
  6547             if r >= 0:
  6548                 name = matskeys[r]
  6549                 try:
  6550 #                    for k,v in mats[name].items(): activemat.properties['luxblend'][k] = v
  6551                     for k,v in mats[name].items(): luxProp(activemat, k, None).set(v)
  6552                 except: pass
  6553                 Draw.Redraw()
  6554     if evt == evtSaveMaterial:
  6555         if activemat:
  6556             name = Draw.PupStrInput("preset name: ", "")
  6557             if name != "":
  6558                 usedproperties = {}
  6559                 usedpropertiesfilterobj = activemat
  6560                 luxMaterial(activemat)
  6561                 saveMaterialPreset(name, usedproperties.copy())
  6562                 Draw.Redraw()
  6563     if evt == evtDeleteMaterial:
  6564         matskeys = getMaterialPresets().keys()
  6565         matskeys.sort()
  6566         matsstr = "delete preset: %t"
  6567         for i, v in enumerate(matskeys): matsstr += "|%s %%x%d"%(v, i)
  6568         r = Draw.PupMenu(matsstr, 20)
  6569         if r >= 0:
  6570             saveMaterialPreset(matskeys[r], None)
  6571             Draw.Redraw()
  6572     if evt == evtConvertMaterial:
  6573         if activemat: convertMaterial(activemat)
  6574         Draw.Redraw()
  6575     if evt == evtLoadMaterial2:
  6576         if activemat:
  6577             scn = Scene.GetCurrent()
  6578             Window.FileSelector(lambda fn:loadMatTex(activemat, fn), "load material", luxProp(scn, "lux", "").get()+os.sep+".lbm")
  6579     if evt == evtSaveMaterial2:
  6580         if activemat:
  6581             scn = Scene.GetCurrent()
  6582             Window.FileSelector(lambda fn:saveMaterial(activemat, fn), "save material", luxProp(scn, "lux", "").get()+os.sep+".lbm")
  6583     
  6584 
  6585 def setFocus(target):
  6586     currentscene = Scene.GetCurrent()
  6587     camObj = currentscene.objects.camera # currentscene.getCurrentCamera()
  6588     if target == "S":
  6589         try:
  6590             refLoc = (Object.GetSelected()[0]).getLocation()
  6591         except:
  6592             print("select an object to focus\n")
  6593     elif target == "C":
  6594         refLoc = Window.GetCursorPos()
  6595     else:
  6596         refLoc = (Object.Get(target)).getLocation()
  6597     dist = Mathutils.Vector(refLoc) - Mathutils.Vector(camObj.getLocation())
  6598     camDir = camObj.getMatrix()[2]*(-1.0)
  6599     camObj.getData(mesh=1).dofDist = (camDir[0]*dist[0]+camDir[1]*dist[1]+camDir[2]*dist[2])/camDir.length # data
  6600 
  6601 
  6602 # Parse command line arguments for batch mode rendering if supplied
  6603 
  6604 try:
  6605     batchindex = osys.argv.index('--batch')
  6606     pyargs = osys.argv[osys.argv.index('--batch')+1:]
  6607 except: pyargs = []
  6608 
  6609 if (pyargs != []) and (batchindex != 0):
  6610     print("\n\nLuxBlend v%s - BATCH mode\n"%__version__)
  6611     LuxIsGUI = False
  6612 
  6613     scene = Scene.GetCurrent()
  6614     context = scene.getRenderingContext()
  6615 
  6616     luxpath = ""
  6617     import getopt
  6618     o, a = getopt.getopt(pyargs, 's:e:o:t:l:',["scale=","haltspp=","run=", "lbm=", "lbt="])
  6619 
  6620     opts = {}
  6621     for k,v in o:
  6622         opts[k] = v
  6623 
  6624     if (opts.has_key('--run')) and (opts['--run'] == 'false'):
  6625         print("Run: false")
  6626         luxProp(scene, "run", "true").set("false")
  6627     else:
  6628         luxProp(scene, "run", "true").set("true")
  6629 
  6630     if opts.has_key('--scale'):
  6631         print("Zoom: %s" %opts['--scale'])
  6632         luxProp(scene, "film.scale", "100 %").set(opts['--scale'])
  6633 
  6634     if opts.has_key('--haltspp'):
  6635         print("haltspp: %s" %opts['--haltspp'])
  6636         luxProp(scene, "haltspp", 0).set(int(opts['--haltspp']))
  6637 
  6638     if opts.has_key('-s'):
  6639         print("Start frame: %s" %opts['-s'])
  6640         context.startFrame(int(opts['-s']))
  6641     else:
  6642         print("Error: Start frame not supplied (-s)"); osys.exit(1)
  6643     if opts.has_key('-e'):
  6644         print("End frame: %s" %opts['-e'])
  6645         context.endFrame(int(opts['-e']))
  6646     else:
  6647         print("Error: End frame not supplied (-e)"); osys.exit(1)
  6648     if opts.has_key('-l'):
  6649         print("Path to lux binary: %s" %opts['-l'])
  6650         luxbatchconsolemode = luxProp(scene, "luxbatchc", "false")
  6651         luxbatchconsolemode.set("true")
  6652         luxpathprop = luxProp(scene, "lux", "")
  6653         luxpathprop.set(opts['-l'])
  6654     else:
  6655         print("Error: path to lux binary not supplied (-l)"); osys.exit(1)
  6656     if opts.has_key('-o'):
  6657         print("Image output path: %s" %opts['-o'])
  6658         luxProp(scene, "overrideoutputpath", "").set(opts['-o'])
  6659     else:
  6660         print("Error: image output path not supplied (-o)"); osys.exit(1)
  6661     if opts.has_key('-t'):
  6662         print("Temporary export path: %s" %opts['-t'])
  6663         luxProp(scene, "datadir", "").set(opts['-t'])
  6664     else:
  6665         print("Error: Temporary export path not supplied (-t)"); osys.exit(1)
  6666     
  6667     if opts.has_key('--lbm'):
  6668         print("Load material: %s" %opts['--lbm'])
  6669         mat = Material.Get("Material")
  6670         if mat: loadMatTex(mat, opts['--lbm'])
  6671         else:
  6672             print("Error: No material with name \"Material\" found (--lbm)"); osys.exit(1)
  6673             
  6674     if opts.has_key('--lbt'):
  6675         print("Load material: %s" %opts['--lbt'])
  6676         mat = Material.Get("Material")
  6677         if mat: loadMatTex(mat, opts['--lbt'], ':Kd')
  6678         else:
  6679             print("Error: No material with name \"Material\" found (--lbt)"); osys.exit(1)
  6680 
  6681 #    CBluxAnimExport(True, True)
  6682     CBluxAnimExport(True, True, False) # as by zukazuka (http://www.luxrender.net/forum/viewtopic.php?f=11&t=1288)
  6683     osys.exit(0)
  6684 
  6685 else:
  6686     print("\n\nLuxBlend v%s - UI mode\n"%__version__)
  6687     from Blender.Window import DrawProgressBar
  6688     LuxIsGUI = True
  6689     
  6690     Draw.Register(luxDraw, luxEvent, luxButtonEvt) # init GUI
  6691 
  6692     luxpathprop = luxProp(Scene.GetCurrent(), "lux", "")
  6693     luxpath = luxpathprop.get()
  6694     luxrun = luxProp(Scene.GetCurrent(), "run", True).get()
  6695     checkluxpath = luxProp(Scene.GetCurrent(), "checkluxpath", True).get()
  6696 
  6697     if checkluxpath and luxrun:
  6698         if (luxpath is None) or (sys.exists(luxpath)<=0):
  6699             # luxpath not valid, so delete entry from .blend scene file
  6700             luxpathprop.delete()
  6701             # and re-get luxpath, so we get the path from default-settings
  6702             luxpath = luxpathprop.get()
  6703             #
  6704             LUXRENDER_ROOT = os.getenv('LUXRENDER_ROOT')
  6705             if LUXRENDER_ROOT is not None:
  6706                 LUXRENDER_ROOT = LUXRENDER_ROOT + os.sep
  6707                 luxpathprop.set(LUXRENDER_ROOT)
  6708                 luxpath = LUXRENDER_ROOT
  6709                 if sys.exists(luxpath)>0:
  6710                     print('LuxRender path set from LUXRENDER_ROOT environment variable')
  6711                     saveluxdefaults()
  6712             
  6713             if (luxpath is None) or (sys.exists(luxpath)<=0):
  6714                 print("WARNING: LuxPath \"%s\" is not valid\n"%(luxpath))
  6715                 scn = Scene.GetCurrent()
  6716                 if scn:
  6717                     r = Draw.PupMenu("Installation: Set path to the lux render software?%t|Yes%x1|No%x0|Never%x2")
  6718                     if r == 1:
  6719                         Window.FileSelector(lambda s:luxProp(scn, "lux", "").set(Blender.sys.dirname(s)+os.sep), "Select file in Lux path")
  6720                         saveluxdefaults()
  6721                     if r == 2:
  6722                         newluxdefaults["checkluxpath"] = False
  6723                         saveluxdefaults()
  6724     else    :
  6725         print("Lux path check disabled\n")