text: /*=========================================================================
  
    Program:   Visualization Toolkit
    Module:    vtkOSPRayMaterialLibrary.cxx
  
    Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
    All rights reserved.
    See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
  
       This software is distributed WITHOUT ANY WARRANTY; without even
       the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
       PURPOSE.  See the above copyright notice for more information.
  
  =========================================================================*/
  
  #include "vtkOSPRayMaterialLibrary.h"
  
  #include "vtkActor.h"
  #include "vtkCommand.h"
  #include "vtkImageData.h"
  #include "vtkJPEGReader.h"
  #include "vtkObjectFactory.h"
  #include "vtkOSPRayMaterialHelpers.h"
  #include "vtkPNGReader.h"
  #include "vtkSmartPointer.h"
  #include "vtkTexture.h"
  #include "vtkXMLImageDataReader.h"
  #include "vtkXMLImageDataWriter.h"
  #include "vtk_jsoncpp.h"
  #include <vtksys/SystemTools.hxx>
  
  #include <fstream>
  #include <string>
  #include <vector>
  
  #include <sys/types.h>
  
  namespace
  {
    const std::map<std::string, std::map<std::string, std::string> > Aliases = {
      {
        "OBJMaterial", {
          { "colorMap", "map_Kd" },
          { "map_kd", "map_Kd" },
          { "map_ks", "map_Ks" },
          { "map_ns", "map_Ns" },
          { "map_bump", "map_Bump" },
          { "normalMap", "map_Bump" },
          { "BumpMap", "map_Bump" },
          { "color", "Kd" },
          { "kd", "Kd" },
          { "alpha", "d" },
          { "ks", "Ks" },
          { "ns", "Ns" },
          { "tf", "Tf" }
        }
      },
      {
        "ThinGlass", {
          { "color", "attenuationColor" },
          { "transmission", "attenuationColor" }
        }
      },
      {
        "MetallicPaint", {
          { "color", "baseColor" }
        }
      },
      {
        "Glass", {
          { "etaInside", "eta" },
          { "etaOutside", "eta" },
          { "attenuationColorOutside", "attenuationColor" }
        }
      },
      {
        "Principled", {}
      },
      {
        "CarPaint", {}
      },
      {
        "Metal", {}
      },
      {
        "Alloy", {}
      }
    };
  
    std::string FindRealName(const std::string& materialType, const std::string& alias)
    {
      auto matAliasesIt = ::Aliases.find(materialType);
      if (matAliasesIt != ::Aliases.end())
      {
        auto realNameIt = matAliasesIt->second.find(alias);
        if (realNameIt != matAliasesIt->second.end())
        {
          return realNameIt->second;
        }
      }
      return alias;
    }
  }
  
  typedef std::map<std::string, std::vector<double> > NamedVariables;
  typedef std::map<std::string, vtkSmartPointer<vtkTexture> > NamedTextures;
  
  class vtkOSPRayMaterialLibraryInternals
  {
  public:
    vtkOSPRayMaterialLibraryInternals() {}
    ~vtkOSPRayMaterialLibraryInternals() {}
  
    std::set<std::string> NickNames;
    std::map<std::string, std::string> ImplNames;
    std::map<std::string, NamedVariables> VariablesFor;
    std::map<std::string, NamedTextures> TexturesFor;
  };
  
  // ----------------------------------------------------------------------------
  vtkStandardNewMacro(vtkOSPRayMaterialLibrary);
  
  // ----------------------------------------------------------------------------
  vtkOSPRayMaterialLibrary::vtkOSPRayMaterialLibrary()
  {
    this->Internal = new vtkOSPRayMaterialLibraryInternals;
  }
  
  // ----------------------------------------------------------------------------
  vtkOSPRayMaterialLibrary::~vtkOSPRayMaterialLibrary()
  {
    delete this->Internal;
  }
  
  // ----------------------------------------------------------------------------
  void vtkOSPRayMaterialLibrary::PrintSelf(ostream& os, vtkIndent indent)
  {
    this->Superclass::PrintSelf(os, indent);
    os << indent << "Materials:\n";
    for (auto mat : this->Internal->NickNames)
    {
      os << indent << "  - " << mat << "( " << this->Internal->ImplNames[mat] << " )" << endl;
      for (auto v : this->Internal->VariablesFor[mat])
      {
        os << indent << "    - " << v.first << endl;
      }
    }
  }
  
  // ----------------------------------------------------------------------------
  void vtkOSPRayMaterialLibrary::AddMaterial(const std::string& nickname, const std::string& implname)
  {
    auto& dic = vtkOSPRayMaterialLibrary::GetParametersDictionary();
  
    if (dic.find(implname) != dic.end())
    {
      this->Internal->NickNames.insert(nickname);
      this->Internal->ImplNames[nickname] = implname;
    }
    else
    {
      vtkGenericWarningMacro("Unknown material type \"" << implname
        << "\" for material named \"" << nickname << "\"");
    }
  }
  
  // ----------------------------------------------------------------------------
  void vtkOSPRayMaterialLibrary::RemoveMaterial(const std::string& nickname)
  {
    this->Internal->NickNames.erase(nickname);
    this->Internal->ImplNames.erase(nickname);
    this->Internal->VariablesFor.erase(nickname);
    this->Internal->TexturesFor.erase(nickname);
  }
  
  // ----------------------------------------------------------------------------
  void vtkOSPRayMaterialLibrary::AddTexture(
    const std::string& nickname, const std::string& texname, vtkTexture* tex)
  {
    std::string realname = ::FindRealName(this->Internal->ImplNames[nickname], texname);
  
    auto& dic = vtkOSPRayMaterialLibrary::GetParametersDictionary();
    auto& params = dic.at(this->Internal->ImplNames[nickname]);
    if (params.find(realname) != params.end())
    {
      NamedTextures& tsForNickname = this->Internal->TexturesFor[nickname];
      tsForNickname[realname] = tex;
    }
    else
    {
      vtkGenericWarningMacro("Unknown parameter \"" << texname
        << "\" for type \"" << this->Internal->ImplNames[nickname] << "\"");
    }
  }
  
  // ----------------------------------------------------------------------------
  void vtkOSPRayMaterialLibrary::RemoveTexture(
    const std::string& nickname, const std::string& texname)
  {
    std::string realname = ::FindRealName(this->Internal->ImplNames[nickname], texname);
    this->Internal->TexturesFor[nickname].erase(realname);
  }
  
  // ----------------------------------------------------------------------------
  void vtkOSPRayMaterialLibrary::RemoveAllTextures(const std::string& nickname)
  {
    this->Internal->TexturesFor[nickname].clear();
  }
  
  // ----------------------------------------------------------------------------
  void vtkOSPRayMaterialLibrary::AddShaderVariable(
    const std::string& nickname, const std::string& varname, int numVars, const double* x)
  {
    std::vector<double> w;
    w.assign(x, x + numVars);
  
    std::string realname = ::FindRealName(this->Internal->ImplNames[nickname], varname);
  
    auto& dic = vtkOSPRayMaterialLibrary::GetParametersDictionary();
    auto& params = dic.at(this->Internal->ImplNames[nickname]);
    if (params.find(realname) != params.end())
    {
      NamedVariables& vsForNickname = this->Internal->VariablesFor[nickname];
      vsForNickname[realname] = std::move(w);
    }
    else
    {
      vtkGenericWarningMacro("Unknown parameter \"" << varname
        << "\" for type \"" << this->Internal->ImplNames[nickname] << "\"");
    }
  }
  
  // ----------------------------------------------------------------------------
  void vtkOSPRayMaterialLibrary::RemoveShaderVariable(
    const std::string& nickname, const std::string& varname)
  {
    std::string realname = ::FindRealName(this->Internal->ImplNames[nickname], varname);
    this->Internal->VariablesFor[nickname].erase(realname);
  }
  
  // ----------------------------------------------------------------------------
  void vtkOSPRayMaterialLibrary::RemoveAllShaderVariables(const std::string& nickname)
  {
    this->Internal->VariablesFor[nickname].clear();
  }
  
  // ----------------------------------------------------------------------------
  bool vtkOSPRayMaterialLibrary::ReadFile(const char* filename)
  {
    return this->InternalParse(filename, true);
  }
  
  // ----------------------------------------------------------------------------
  bool vtkOSPRayMaterialLibrary::ReadBuffer(const char* filename)
  {
    return this->InternalParse(filename, false);
  }
  
  // ----------------------------------------------------------------------------
  bool vtkOSPRayMaterialLibrary::InternalParse(const char* filename, bool fromfile)
  {
    if (!filename)
    {
      return false;
    }
    if (fromfile && !vtksys::SystemTools::FileExists(filename, true))
    {
      return false;
    }
  
    std::istream* doc;
    if (fromfile)
    {
      doc = new std::ifstream(filename, std::ifstream::binary);
    }
    else
    {
      doc = new std::istringstream(filename);
    }
    bool retOK = false;
    if (std::string(filename).rfind(".mtl") != std::string::npos)
    {
      retOK = this->InternalParseMTL(filename, fromfile, doc);
    }
    else
    {
      retOK = this->InternalParseJSON(filename, fromfile, doc);
    }
    delete doc;
    return retOK;
  }
  
  // ----------------------------------------------------------------------------
  bool vtkOSPRayMaterialLibrary::InternalParseJSON(
    const char* filename, bool fromfile, std::istream* doc)
  {
    Json::Value root;
    std::string errs;
    Json::CharReaderBuilder jreader;
    bool ok = Json::parseFromStream(jreader, *doc, &root, &errs);
    if (!ok)
    {
      return false;
    }
    if (!root.isMember("family"))
    {
      vtkErrorMacro("Not a materials file. Must have \"family\"=\"...\" entry.");
      return false;
    }
    const Json::Value family = root["family"];
    if (family.asString() != "OSPRay")
    {
      vtkErrorMacro("Unsupported materials file. Family is not \"OSPRay\".");
      return false;
    }
    if (!root.isMember("version"))
    {
      vtkErrorMacro("Not a materials file. Must have \"version\"=\"...\" entry.");
      return false;
    }
    const Json::Value version = root["version"];
    if (version.asString() != "0.0")
    {
      vtkErrorMacro("Unsupported materials file. Version is not \"0.0\".");
      return false;
    }
    if (!root.isMember("materials"))
    {
      vtkErrorMacro("Not a materials file. Must have \"materials\"={...} entry.");
      return false;
    }
  
    const Json::Value materials = root["materials"];
    std::vector<std::string> ikeys = materials.getMemberNames();
    for (size_t i = 0; i < ikeys.size(); ++i)
    {
      const std::string& nickname = ikeys[i];
      const Json::Value nextmat = materials[nickname];
      if (!nextmat.isMember("type"))
      {
        vtkErrorMacro(
          "Invalid material " << nickname << " must have \"type\"=\"...\" entry, ignoring.");
        continue;
      }
  
      // keep a record so others know this material is available
      this->Internal->NickNames.insert(nickname);
  
      const std::string& implname = nextmat["type"].asString();
      this->Internal->ImplNames[nickname] = implname;
      if (nextmat.isMember("textures"))
      {
        std::string parentDir = vtksys::SystemTools::GetParentDirectory(filename);
        const Json::Value textures = nextmat["textures"];
        for (const std::string& tname : textures.getMemberNames())
        {
          const Json::Value nexttext = textures[tname];
          const char* tfname = nexttext.asCString();
          vtkSmartPointer<vtkTexture> textr = vtkSmartPointer<vtkTexture>::New();
          vtkSmartPointer<vtkJPEGReader> jpgReader = vtkSmartPointer<vtkJPEGReader>::New();
          vtkSmartPointer<vtkPNGReader> pngReader = vtkSmartPointer<vtkPNGReader>::New();
          if (fromfile)
          {
            std::string tfullname = parentDir + "/" + tfname;
            if (!vtksys::SystemTools::FileExists(tfullname.c_str(), true))
            {
              cerr << "No such texture file " << tfullname << " skipping" << endl;
              continue;
            }
            if (tfullname.substr(tfullname.length() - 3) == "png")
            {
              pngReader->SetFileName(tfullname.c_str());
              pngReader->Update();
              textr->SetInputConnection(pngReader->GetOutputPort(0));
            }
            else
            {
              jpgReader->SetFileName(tfullname.c_str());
              jpgReader->Update();
              textr->SetInputConnection(jpgReader->GetOutputPort(0));
            }
          }
          else
          {
            vtkSmartPointer<vtkXMLImageDataReader> reader =
              vtkSmartPointer<vtkXMLImageDataReader>::New();
            reader->ReadFromInputStringOn();
            reader->SetInputString(tfname);
            textr->SetInputConnection(reader->GetOutputPort(0));
          }
          textr->Update();
          this->AddTexture(nickname, tname, textr);
        }
      }
      if (nextmat.isMember("doubles"))
      {
        const Json::Value doubles = nextmat["doubles"];
        for (const std::string& vname : doubles.getMemberNames())
        {
          const Json::Value nexttext = doubles[vname];
          std::vector<double> vals(nexttext.size());
          for (size_t k = 0; k < nexttext.size(); ++k)
          {
            const Json::Value nv = nexttext[static_cast<int>(k)];
            vals[k] = nv.asDouble();
          }
          this->AddShaderVariable(nickname, vname, nexttext.size(), vals.data());
        }
      }
    }
  
    return true;
  }
  
  namespace
  {
  static std::string trim(std::string s)
  {
    size_t start = 0;
    while ((start < s.length()) && (isspace(s[start])))
    {
      start++;
    }
    size_t end = s.length();
    while ((end > start) && (isspace(s[end - 1])))
    {
      end--;
    }
    return s.substr(start, end - start);
  }
  }
  
  // ----------------------------------------------------------------------------
  bool vtkOSPRayMaterialLibrary::InternalParseMTL(
    const char* filename, bool fromfile, std::istream* doc)
  {
    std::string str;
    std::string nickname = "";
    std::string implname = "OBJMaterial";
  
    const std::vector<std::string> singles{ "d ", "Ks ", "alpha ", "roughness ", "eta ",
      "thickness " };
    const std::vector<std::string> triples{ "Ka ", "color ", "Kd ", "Ks " };
    const std::vector<std::string> textures{ "map_d ", "map_Kd ", "map_kd ", "colorMap ", "map_Ks ",
      "map_ks ", "map_Ns ", "map_ns ", "map_Bump", "map_bump", "normalMap", "bumpMap" };
  
    while (getline(*doc, str))
    {
      std::string tstr = trim(str);
      std::string lkey;
  
      // a new material
      lkey = "newmtl ";
      if (tstr.compare(0, lkey.size(), lkey) == 0)
      {
        nickname = trim(tstr.substr(lkey.size()));
        this->Internal->NickNames.insert(nickname);
        this->Internal->ImplNames[nickname] = "OBJMaterial";
      }
  
      // ospray type of the material, if not obj
      lkey = "type ";
      if (tstr.compare(0, lkey.size(), lkey) == 0)
      {
        // this non standard entry is a quick way to break out of
        // objmaterial and use one of the ospray specific materials
        implname = trim(tstr.substr(lkey.size()));
        if (implname == "matte")
        {
          implname = "OBJMaterial";
        }
        if (implname == "glass")
        {
          implname = "ThinGlass";
        }
        if (implname == "metal")
        {
          implname = "Metal";
        }
        if (implname == "metallicPaint")
        {
          implname = "MetallicPaint";
        }
        this->Internal->ImplNames[nickname] = implname;
      }
  
      // grab all the single valued settings we see
      std::vector<std::string>::const_iterator sit1 = singles.begin();
      while (sit1 != singles.end())
      {
        std::string key = *sit1;
        ++sit1;
        if (tstr.compare(0, key.size(), key) == 0)
        {
          std::string v = tstr.substr(key.size());
          double dv = 0.;
          bool OK = false;
          try
          {
            dv = std::stod(v);
            OK = true;
          }
          catch (const std::invalid_argument&)
          {
          }
          catch (const std::out_of_range&)
          {
          }
          if (OK)
          {
            double vals[1] = { dv };
            this->AddShaderVariable(nickname, key.substr(0, key.size() - 1).c_str(), 1, vals);
          }
        }
      }
  
      // grab all the triple valued settings we see
      std::vector<std::string>::const_iterator sit3 = triples.begin();
      while (sit3 != triples.end())
      {
        std::string key = *sit3;
        ++sit3;
        if (tstr.compare(0, key.size(), key) == 0)
        {
          std::string vs = tstr.substr(key.size());
          size_t loc1 = vs.find(" ");
          size_t loc2 = vs.find(" ", loc1);
          std::string v1 = vs.substr(0, loc1);
          std::string v2 = vs.substr(loc1 + 1, loc2);
          std::string v3 = vs.substr(loc2 + 1);
          double d1 = 0;
          double d2 = 0;
          double d3 = 0;
          bool OK = false;
          try
          {
            d1 = std::stod(v1);
            d2 = std::stod(v1);
            d3 = std::stod(v1);
            OK = true;
          }
          catch (const std::invalid_argument&)
          {
          }
          catch (const std::out_of_range&)
          {
          }
          if (OK)
          {
            double vals[3] = { d1, d2, d3 };
            this->AddShaderVariable(nickname, key.substr(0, key.size() - 1).c_str(), 3, vals);
          }
        }
      }
  
      // grab all the textures we see
      std::vector<std::string>::const_iterator tit = textures.begin();
      while (tit != textures.end())
      {
        std::string key = *tit;
        ++tit;
  
        std::string tfname = "";
        if (tstr.compare(0, key.size(), key) == 0)
        {
          tfname = trim(tstr.substr(key.size()));
        }
        if (tfname != "")
        {
          vtkSmartPointer<vtkTexture> textr = vtkSmartPointer<vtkTexture>::New();
          vtkSmartPointer<vtkJPEGReader> jpgReader = vtkSmartPointer<vtkJPEGReader>::New();
          vtkSmartPointer<vtkPNGReader> pngReader = vtkSmartPointer<vtkPNGReader>::New();
          if (fromfile)
          {
            std::string parentDir = vtksys::SystemTools::GetParentDirectory(filename);
            std::string tfullname = parentDir + "/" + tfname;
            if (!vtksys::SystemTools::FileExists(tfullname.c_str(), true))
            {
              cerr << "No such texture file " << tfullname << " skipping" << endl;
              continue;
            }
            if (tfullname.substr(tfullname.length() - 3) == "png")
            {
              pngReader->SetFileName(tfullname.c_str());
              pngReader->Update();
              textr->SetInputConnection(pngReader->GetOutputPort(0));
            }
            else
            {
              jpgReader->SetFileName(tfullname.c_str());
              jpgReader->Update();
              textr->SetInputConnection(jpgReader->GetOutputPort(0));
            }
          }
          else
          {
            vtkSmartPointer<vtkXMLImageDataReader> reader =
              vtkSmartPointer<vtkXMLImageDataReader>::New();
            reader->ReadFromInputStringOn();
            reader->SetInputString(tfname);
            textr->SetInputConnection(reader->GetOutputPort(0));
          }
          textr->Update();
  
          this->AddTexture(nickname, key.substr(0, key.size() - 1).c_str(), textr);
        }
      }
    }
  
    return true;
  }
  
  // ----------------------------------------------------------------------------
  const char* vtkOSPRayMaterialLibrary::WriteBuffer()
  {
    Json::Value root;
    root["family"] = "OSPRay";
    root["version"] = "0.0";
    Json::Value materials;
  
    vtkSmartPointer<vtkXMLImageDataWriter> idwriter = vtkSmartPointer<vtkXMLImageDataWriter>::New();
    idwriter->WriteToOutputStringOn();
  
    std::set<std::string>::iterator it = this->Internal->NickNames.begin();
    while (it != this->Internal->NickNames.end())
    {
      std::string nickname = *it;
      Json::Value jnickname;
      std::string implname = this->LookupImplName(nickname);
      jnickname["type"] = implname;
  
      if (this->Internal->VariablesFor.find(nickname) != this->Internal->VariablesFor.end())
      {
        Json::Value variables;
        NamedVariables::iterator vit = this->Internal->VariablesFor[nickname].begin();
        while (vit != this->Internal->VariablesFor[nickname].end())
        {
          std::string vname = vit->first;
          std::vector<double> vvals = vit->second;
          Json::Value jvvals;
          for (size_t i = 0; i < vvals.size(); ++i)
          {
            jvvals.append(vvals[i]);
          }
          variables[vname] = jvvals;
          ++vit;
        }
  
        jnickname["doubles"] = variables;
      }
  
      if (this->Internal->TexturesFor.find(nickname) != this->Internal->TexturesFor.end())
      {
        Json::Value textures;
        NamedTextures::iterator vit = this->Internal->TexturesFor[nickname].begin();
        while (vit != this->Internal->TexturesFor[nickname].end())
        {
          std::string vname = vit->first;
          vtkSmartPointer<vtkTexture> vvals = vit->second;
          idwriter->SetInputData(vvals->GetInput());
          idwriter->Write();
          std::string os = idwriter->GetOutputString();
          Json::Value jvvals = os;
          textures[vname] = jvvals;
          ++vit;
        }
  
        jnickname["textures"] = textures;
      }
  
      materials[nickname] = jnickname;
      ++it;
    }
  
    root["materials"] = materials;
  
    Json::StreamWriterBuilder builder;
    builder["commentStyle"] = "None";
    builder["indentation"] = "   ";
    std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
    std::ostringstream result;
    writer->write(root, &result);
    std::string rstring = result.str();
  
    if (rstring.size())
    {
      char* buf = new char[rstring.size() + 1];
      memcpy(buf, rstring.c_str(), rstring.size());
      buf[rstring.size()] = 0;
      return buf;
    }
    return nullptr;
  }
  
  //-----------------------------------------------------------------------------
  void vtkOSPRayMaterialLibrary::Fire()
  {
    this->InvokeEvent(vtkCommand::UpdateDataEvent);
  }
  
  //-----------------------------------------------------------------------------
  std::set<std::string> vtkOSPRayMaterialLibrary::GetMaterialNames()
  {
    return this->Internal->NickNames;
  }
  
  //-----------------------------------------------------------------------------
  std::string vtkOSPRayMaterialLibrary::LookupImplName(const std::string& nickname)
  {
    return this->Internal->ImplNames[nickname];
  }
  
  //-----------------------------------------------------------------------------
  vtkTexture* vtkOSPRayMaterialLibrary::GetTexture(
    const std::string& nickname, const std::string& texturename)
  {
    NamedTextures tsForNickname;
    if (this->Internal->TexturesFor.find(nickname) != this->Internal->TexturesFor.end())
    {
      tsForNickname = this->Internal->TexturesFor[nickname];
      std::string realname = ::FindRealName(this->Internal->ImplNames[nickname], texturename);
      return tsForNickname[realname];
    }
    return nullptr;
  }
  
  //-----------------------------------------------------------------------------
  std::vector<double> vtkOSPRayMaterialLibrary::GetDoubleShaderVariable(
    const std::string& nickname, const std::string& varname)
  {
    if (this->Internal->VariablesFor.find(nickname) != this->Internal->VariablesFor.end())
    {
      NamedVariables vsForNickname = this->Internal->VariablesFor[nickname];
      std::string realname = ::FindRealName(this->Internal->ImplNames[nickname], varname);
      return vsForNickname[realname];
    }
    return std::vector<double>();
  }
  
  //-----------------------------------------------------------------------------
  std::vector<std::string> vtkOSPRayMaterialLibrary::GetDoubleShaderVariableList(
    const std::string& nickname)
  {
    std::vector<std::string> variableNames;
    if (this->Internal->VariablesFor.find(nickname) != this->Internal->VariablesFor.end())
    {
      for (auto& v : this->Internal->VariablesFor[nickname])
      {
        variableNames.push_back(v.first);
      }
    }
    return variableNames;
  }
  
  //-----------------------------------------------------------------------------
  std::vector<std::string> vtkOSPRayMaterialLibrary::GetTextureList(const std::string& nickname)
  {
    std::vector<std::string> texNames;
    if (this->Internal->TexturesFor.find(nickname) != this->Internal->TexturesFor.end())
    {
      for (auto& v : this->Internal->TexturesFor[nickname])
      {
        texNames.push_back(v.first);
      }
    }
    return texNames;
  }
  
  //-----------------------------------------------------------------------------
  const std::map<std::string, vtkOSPRayMaterialLibrary::ParametersMap>&
    vtkOSPRayMaterialLibrary::GetParametersDictionary()
  {
    // This is the material dictionary from OSPRay 1.8
    // If attribute name changes with new OSPRay version, keep old name aliases support in functions
    // vtkOSPRayMaterialLibrary::AddShaderVariable and vtkOSPRayMaterialLibrary::AddTexture
    static std::map<std::string, vtkOSPRayMaterialLibrary::ParametersMap> dic =
    {
      {
        "OBJMaterial", {
          { "Ka", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "Kd", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "Ks", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "Ns", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "d", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "Tf", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "map_Bump", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "map_Kd", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "map_Ks", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "map_Ns", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "map_d", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
        }
      },
      {
        "Principled", {
          { "baseColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "edgeColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "metallic", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "diffuse", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "specular", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "ior", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "transmission", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "transmissionColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "transmissionDepth", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "roughness", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "anisotropy", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "rotation", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "normal", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "baseNormal", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "thin", vtkOSPRayMaterialLibrary::ParameterType::BOOLEAN },
          { "thickness", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "backlight", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "coat", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "coatIor", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "coatColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "coatThickness", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "coatRoughness", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "coatNormal", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "sheen", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "sheenColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "sheenTint", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "sheenRoughness", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "opacity", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "baseColorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "edgeColorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "metallicMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "diffuseMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "specularMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "iorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "transmissionMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "transmissionColorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "transmissionDepthMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "roughnessMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "anisotropyMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "rotationMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "normalMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "baseNormalMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "thinMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "thicknessMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "backlightMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatIorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatColorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatThicknessMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatRoughnessMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatNormalMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "sheenMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "sheenColorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "sheenTintMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "sheenRoughnessMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "opacityMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
        }
      },
      {
        "CarPaint", {
          { "baseColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "roughness", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "normal", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "flakeDensity", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "flakeScale", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "flakeSpread", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "flakeJitter", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "flakeRoughness", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "coat", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "coatIor", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "coatColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "coatThickness", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "coatRoughness", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "coatNormal", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "flipflopColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "flipflopFalloff", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "baseColorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "roughnessMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "normalMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "flakeDensityMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "flakeScaleMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "flakeSpreadMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "flakeJitterMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "flakeRoughnessMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatIorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatColorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatThicknessMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatRoughnessMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "coatNormalMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "flipflopColorMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "flipflopFalloffMap", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
        }
      },
      {
        "Metal", {
          { "ior", vtkOSPRayMaterialLibrary::ParameterType::FLOAT_DATA },
          { "eta", vtkOSPRayMaterialLibrary::ParameterType::VEC3 },
          { "k", vtkOSPRayMaterialLibrary::ParameterType::VEC3 },
          { "roughness", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "map_roughness", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
        }
      },
      {
        "Alloy", {
          { "color", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "edgeColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "roughness", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "map_color", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "map_edgeColor", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
          { "map_roughness", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
        }
      },
      {
        "Glass", {
          { "eta", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "attenuationColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "attenuationDistance", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
        }
      },
      {
        "ThinGlass", {
          { "eta", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "attenuationColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "attenuationDistance", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "thickness", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "map_attenuationColor", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
        }
      },
      {
        "MetallicPaint", {
          { "baseColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "flakeAmount", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "flakeColor", vtkOSPRayMaterialLibrary::ParameterType::COLOR_RGB },
          { "flakeSpread", vtkOSPRayMaterialLibrary::ParameterType::NORMALIZED_FLOAT },
          { "eta", vtkOSPRayMaterialLibrary::ParameterType::FLOAT },
          { "map_baseColor", vtkOSPRayMaterialLibrary::ParameterType::TEXTURE },
        }
      },
    };
    return dic;
  }
  